@uniku/cli 0.4.0 → 0.5.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
@@ -5,7 +5,7 @@
5
5
 
6
6
  Command-line tool for generating, validating, and inspecting unique identifiers.
7
7
 
8
- Supports UUID v4/v7, ULID, TypeID, CUID2, Nanoid, KSUID, and MongoDB ObjectID.
8
+ Supports UUID v4/v7, ULID, TypeID, CUID2, Nanoid, KSUID, MongoDB ObjectID, and TSID.
9
9
 
10
10
  ## Installation
11
11
 
@@ -17,7 +17,7 @@ Download and install a standalone binary — no Node.js required:
17
17
  curl -fsSL https://raw.githubusercontent.com/jkomyno/uniku/main/install.sh | sh
18
18
  ```
19
19
 
20
- Supports macOS (Intel & Apple Silicon) and Linux (x64). Override the install location or version with environment variables:
20
+ Supports macOS (Intel and Apple Silicon) and Linux (x64/amd64 and ARM64). Override the install location or version with environment variables:
21
21
 
22
22
  ```bash
23
23
  # Custom install directory
@@ -93,6 +93,16 @@ uniku objectid
93
93
  # ObjectID for a fixed Unix timestamp (s)
94
94
  uniku objectid --timestamp 1720000000
95
95
 
96
+ # TSID (64-bit Snowflake-style, time-sorted)
97
+ uniku tsid
98
+ # => 0QXW2CK4XZM2A
99
+
100
+ # TSID for a fixed Unix timestamp (ms) - note: milliseconds, unlike ObjectID/KSUID's seconds
101
+ uniku tsid --timestamp 1720000000000
102
+
103
+ # TSID for a fixed node ID
104
+ uniku tsid --node 42 --node-bits 10
105
+
96
106
  # Output as JSON
97
107
  uniku uuid --count 3 --json
98
108
  ```
@@ -137,7 +147,7 @@ uniku inspect user_01h2xcejqtf2nbrexx3vqjhp41
137
147
  uniku inspect --json 018e5e5c-7c8a-7000-8000-000000000000
138
148
  ```
139
149
 
140
- For time-ordered IDs (UUID v7, ULID, TypeID, KSUID, ObjectID), inspect extracts the embedded timestamp. For random-only IDs (UUID v4, CUID2, Nanoid), it reports that no decodable metadata is available.
150
+ For time-ordered IDs (UUID v7, ULID, TypeID, KSUID, ObjectID, TSID), inspect extracts the embedded timestamp. For random-only IDs (UUID v4, CUID2, Nanoid), it reports that no decodable metadata is available. Timestamp precision varies by generator: UUID v7, ULID, and TSID are millisecond-precision, while KSUID and ObjectID are second-precision.
141
151
 
142
152
  ## Commands Reference
143
153
 
@@ -150,6 +160,7 @@ For time-ordered IDs (UUID v7, ULID, TypeID, KSUID, ObjectID), inspect extracts
150
160
  | `uniku cuid` | Generate CUIDs (v2) |
151
161
  | `uniku ksuid` | Generate KSUIDs |
152
162
  | `uniku objectid` | Generate MongoDB ObjectIDs |
163
+ | `uniku tsid` | Generate TSIDs (64-bit Snowflake-style, time-sorted) |
153
164
  | `uniku validate <id>` | Check if an ID is valid |
154
165
  | `uniku inspect <id>` | Decode and inspect an ID |
155
166
 
@@ -177,12 +188,15 @@ For time-ordered IDs (UUID v7, ULID, TypeID, KSUID, ObjectID), inspect extracts
177
188
  | `cuid` | `--length` | `-l` | Length of ID, 2-32 (default: 24) |
178
189
  | `ksuid` | `--timestamp` | | Unix timestamp in seconds or "now" |
179
190
  | `objectid` | `--timestamp` | | Unix timestamp in seconds or "now" |
191
+ | `tsid` | `--timestamp` | | Unix timestamp in milliseconds or "now" |
192
+ | `tsid` | `--node` | | Node ID (0 to 2^node-bits - 1) |
193
+ | `tsid` | `--node-bits` | | Number of bits allocated to the node ID, 0-20 (default: 10) |
180
194
 
181
195
  ### Validate Options
182
196
 
183
197
  | Option | Description |
184
198
  |--------|-------------|
185
- | `--type` | Expected ID type: uuid, ulid, typeid, nanoid, cuid, ksuid, objectid (auto-detected if omitted) |
199
+ | `--type` | Expected ID type: uuid, ulid, typeid, nanoid, cuid, ksuid, objectid, tsid (auto-detected if omitted) |
186
200
  | `--stdin` | Read IDs from stdin (one per line) |
187
201
  | `--quiet` | No output, exit code only (0 = valid, 2 = invalid) |
188
202
  | `--json` | Output as JSON |
@@ -191,7 +205,7 @@ For time-ordered IDs (UUID v7, ULID, TypeID, KSUID, ObjectID), inspect extracts
191
205
 
192
206
  | Option | Description |
193
207
  |--------|-------------|
194
- | `--type` | ID type: uuid, ulid, typeid, nanoid, cuid, ksuid, objectid (auto-detected if omitted) |
208
+ | `--type` | ID type: uuid, ulid, typeid, nanoid, cuid, ksuid, objectid, tsid (auto-detected if omitted) |
195
209
  | `--json` | Output as JSON |
196
210
 
197
211
  ## Tech Stack
package/build/bin.mjs CHANGED
@@ -1,7 +1,7 @@
1
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{objectid as g}from"uniku/objectid";import{typeid as _}from"uniku/typeid";import{ulid as v}from"uniku/ulid";import{uuidv4 as y}from"uniku/uuid/v4";import{uuidv7 as b}from"uniku/uuid/v7";import*as x from"effect/Context";import*as ee from"effect/Console";import*as S 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 se,join as ce}from"node:path";import*as C from"effect/Config";const le={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},ue=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 de(e){let t={error:e.message,code:e.code};return e.hint&&(t.hint=e.hint),t}function fe(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 pe(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 me(e){if(e)return le[e]??e}function he(e){return r.try({try:()=>{let t=me(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 ge(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(g(n))}return t},catch:e=>e instanceof p?T(e):new w({code:`GENERATE_FAILED`,message:String(e)})})}function _e(e){return r.try({try:()=>{let t=[];for(let n=0;n<e.count;n++)t.push(_(e.prefix));return t},catch:e=>e instanceof p?T(e):new w({code:`GENERATE_FAILED`,message:String(e)})})}function ve(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=v(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 ye(e){return r.try({try:()=>{let t=e.version===7?b:y,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 x.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 be(e){return{json:()=>e.length===1?e[0]:e,text:()=>e.map(Ce)}}function xe(e){return{json:()=>e,text:()=>[we(e)]}}function Se(e){return{json:()=>de(e),text:()=>[Te(e)]}}function Ce(e){if(e.valid){let t=e.version==null?``:` v${e.version}`;return`valid (${e.type}${t})`}return`invalid: ${e.error??`malformed identifier`}`}function we(e){let t=[],n=e.version==null?e.type:`${e.type} (v${e.version})`;return t.push(`Type: ${n}`),e.prefix!=null&&t.push(`Prefix: ${e.prefix===``?`(empty)`:e.prefix}`),e.suffix&&t.push(`Suffix: ${e.suffix}`),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 Te(e){return e.hint?`Error: ${e.message}\n ${e.hint}`:`Error: ${e.message}`}const A=l.integer(`count`).pipe(l.withAlias(`n`),l.withDescription(`Number of IDs to generate`),l.withDefault(1)),j=l.boolean(`json`).pipe(l.withDescription(`Output as JSON`),l.withDefault(!1)),Ee=l.choiceWithValue(`uuid-version`,[[`4`,4],[`7`,7]]).pipe(l.withAlias(`v`),l.withDescription(`UUID version: 4, 7`),l.withDefault(4)),M=l.boolean(`lowercase`).pipe(l.withDescription(`Output in lowercase`),l.withDefault(!1)),N=c.make(`uuid`,{count:A,json:j,version:Ee,lowercase:M},r.fn(`cli.generate.uuid`)(function*({count:e,json:t,version:n,lowercase:r}){let i=yield*D,a=yield*ye({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`}])),De=l.string(`prefix`).pipe(l.withAlias(`p`),l.withDescription(`Type prefix, e.g. "user" for user_... (empty by default)`),l.withDefault(``)),P=c.make(`typeid`,{count:A,json:j,prefix:De},r.fn(`cli.generate.typeid`)(function*({count:e,json:t,prefix:n}){let r=yield*D,i=yield*_e({count:e,prefix:n});yield*r.write(k(i),{json:t})})).pipe(c.withDescription(`Generate TypeIDs`),c.withExamples([{command:`uniku typeid --prefix user`,description:`Generate a TypeID such as user_...`},{command:`uniku typeid -p api_key -n 5 --json`,description:`Generate 5 api_key TypeIDs as JSON`},{command:`uniku typeid`,description:`Generate a canonical prefixless TypeID`}])),Oe=l.boolean(`monotonic`).pipe(l.withDescription(`Generate monotonically increasing ULIDs`),l.withDefault(!1)),ke=l.string(`timestamp`).pipe(l.withDescription(`Unix timestamp in milliseconds (or "now")`),l.optional),F=c.make(`ulid`,{count:A,json:j,monotonic:Oe,timestamp:ke,lowercase:M},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*ve({count:e,monotonic:n,timestamp:s===void 0?void 0:yield*Ue(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)`}])),Ae=l.integer(`size`).pipe(l.withAlias(`s`),l.withDescription(`Length of ID (1-256)`),l.withDefault(21)),je=l.string(`alphabet`).pipe(l.withAlias(`a`),l.withDescription(`Custom alphabet or preset: hex, numeric, alpha`),l.optional),I=c.make(`nanoid`,{count:A,json:j,size:Ae,alphabet:je},r.fn(`cli.generate.nanoid`)(function*({count:e,json:t,size:n,alphabet:r}){let i=yield*D,a=yield*he({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`}])),Me=l.integer(`length`).pipe(l.withAlias(`l`),l.withDescription(`Length of ID (2-32)`),l.withDefault(24)),L=c.make(`cuid`,{count:A,json:j,length:Me},r.fn(`cli.generate.cuid`)(function*({count:e,json:t,length:n}){let r=yield*D,i=yield*fe({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`}])),Ne=l.string(`timestamp`).pipe(l.withDescription(`Unix timestamp in seconds (or "now")`),l.optional),R=c.make(`ksuid`,{count:A,json:j,timestamp:Ne},r.fn(`cli.generate.ksuid`)(function*({count:e,json:t,timestamp:n}){let r=yield*D,i=o.getOrUndefined(n),a=yield*pe({count:e,timestamp:i===void 0?void 0:yield*V(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)`}])),Pe=l.string(`timestamp`).pipe(l.withDescription(`Unix timestamp in seconds (or "now")`),l.optional),z=c.make(`objectid`,{count:A,json:j,timestamp:Pe},r.fn(`cli.generate.objectid`)(function*({count:e,json:t,timestamp:n}){let r=yield*D,i=o.getOrUndefined(n),a=yield*ge({count:e,timestamp:i===void 0?void 0:yield*V(i)});yield*r.write(k(a),{json:t})})).pipe(c.withDescription(`Generate MongoDB ObjectIDs`),c.withExamples([{command:`uniku objectid -n 5 --json`,description:`Generate 5 ObjectIDs as a JSON array`},{command:`uniku objectid --timestamp 1720000000`,description:`Generate an ObjectID for a fixed Unix timestamp (s)`}])),Fe=c.make(`generate`).pipe(c.withDescription(`Generate new IDs`),c.withSubcommands([N,F,P,I,L,R,z]),c.withExamples([{command:`uniku generate uuid -n 5 --json`,description:`Generate 5 UUIDs as a JSON array`},{command:`uniku generate typeid --prefix user`,description:`Generate one user TypeID`},{command:`uniku generate ulid`,description:"Generate one ULID (subcommands also work top-level: `uniku ulid`)"}])),Ie=N,Le=F,Re=P,ze=I,Be=L,Ve=R,He=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}),Ue=e=>B(e,e=>e,`Provide a Unix timestamp in milliseconds or "now"`),V=e=>B(e,e=>Math.floor(e/1e3),`Provide a Unix timestamp in seconds or "now"`);function We(e,t){switch(t){case`uuid`:return Ge(e);case`ulid`:return Ke(e);case`typeid`:return qe(e);case`ksuid`:return Je(e);case`objectid`:return Ye(e);case`cuid`:return Xe(e);case`nanoid`:return Ze(e)}}function H(e){return b.isValid(e)?{id:e,valid:!0,type:`uuid`,version:7}:y.isValid(e)?{id:e,valid:!0,type:`uuid`,version:4}:_.isValid(e)?{id:e,valid:!0,type:`typeid`,version:7}:v.isValid(e)?{id:e,valid:!0,type:`ulid`}:m.isValid(e)?{id:e,valid:!0,type:`ksuid`}:g.isValid(e)?{id:e,valid:!0,type:`objectid`}: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 Ge(e){return b.isValid(e)?{id:e,valid:!0,type:`uuid`,version:7}:y.isValid(e)?{id:e,valid:!0,type:`uuid`,version:4}:{id:e,valid:!1,type:`uuid`,error:`invalid UUID format`}}function Ke(e){return v.isValid(e)?{id:e,valid:!0,type:`ulid`}:{id:e,valid:!1,type:`ulid`,error:`invalid ULID format`}}function qe(e){return _.isValid(e)?{id:e,valid:!0,type:`typeid`,version:7}:{id:e,valid:!1,type:`typeid`,error:`invalid TypeID format`}}function Je(e){return m.isValid(e)?{id:e,valid:!0,type:`ksuid`}:{id:e,valid:!1,type:`ksuid`,error:`invalid KSUID format`}}function Ye(e){return g.isValid(e)?{id:e,valid:!0,type:`objectid`}:{id:e,valid:!1,type:`objectid`,error:`invalid ObjectID format`}}function Xe(e){return f.isValid(e)?{id:e,valid:!0,type:`cuid`}:{id:e,valid:!1,type:`cuid`,error:`invalid CUID format`}}function Ze(e){return h.isValid(e)?{id:e,valid:!0,type:`nanoid`}:{id:e,valid:!1,type:`nanoid`,error:`invalid Nanoid format`}}function Qe(e,t){let n=t??$e(e);if(!n)return null;switch(n){case`uuid`:return et(e);case`ulid`:return tt(e);case`typeid`:return nt(e);case`ksuid`:return rt(e);case`objectid`:return it(e);case`cuid`:return at(e);case`nanoid`:return ot(e)}}function $e(e){let t=H(e);return t.valid?t.type??null:null}function et(e){if(b.isValid(e)){let t=b.timestamp(e),n=b.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 y.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 tt(e){let t=v.timestamp(e),n=e.slice(10);return{id:e,type:`ulid`,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:n}}function nt(e){if(!_.isValid(e))return{id:e,type:`typeid`,note:`Unrecognized TypeID format.`};let t=_.timestamp(e),n=_.toBytes(e),r=Buffer.from(n.slice(10)).toString(`hex`);return{id:e,type:`typeid`,version:7,prefix:_.prefix(e),suffix:_.suffix(e),timestamp:new Date(t).toISOString(),timestamp_ms:t,random:r}}function rt(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 it(e){let t=g.timestamp(e),n=g.toBytes(e),r=Buffer.from(n.slice(4)).toString(`hex`);return{id:e,type:`objectid`,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:r}}function at(e){return{id:e,type:`cuid`,note:`This ID type contains no decodable metadata.`}}function ot(e){return{id:e,type:`nanoid`,note:`This ID type contains no decodable metadata.`}}function st(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 dt(n)?[...n,...r.map(ut)]:[...n,`--`,...r]}const U=`\0uniku-literal:`,ct=new Set([`inspect`,`validate`]),lt=new Set([`--completions`,`--log-level`]);function W(e){return e.startsWith(U)?e.slice(15):e}function ut(e){return`${U}${e}`}function dt(e){for(let t=0;t<e.length;t+=1){let n=e[t];if(n.startsWith(`-`)){lt.has(n)&&(t+=1);continue}return ct.has(n)}return!1}const ft=s.string(`id`).pipe(s.withDescription(`The ID to inspect`)),pt=l.choice(`type`,[`uuid`,`ulid`,`typeid`,`nanoid`,`cuid`,`ksuid`,`objectid`]).pipe(l.withDescription(`ID type (auto-detected if omitted)`),l.optional),mt=l.boolean(`json`).pipe(l.withDescription(`Output as JSON`),l.withDefault(!1)),ht=c.make(`inspect`,{id:ft,type:pt,json:mt},r.fn(`cli.inspect`)(function*({id:e,type:t,json:n}){let r=yield*D,i=o.getOrUndefined(t),a=W(e),s=Qe(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(xe(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 G=class e extends x.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 gt=s.string(`id`).pipe(s.withDescription(`The ID to validate`),s.optional),_t=l.choice(`type`,[`uuid`,`ulid`,`typeid`,`nanoid`,`cuid`,`ksuid`,`objectid`]).pipe(l.withDescription(`Expected ID type (auto-detected if omitted)`),l.optional),vt=l.boolean(`stdin`).pipe(l.withDescription(`Read IDs from stdin (one per line)`),l.withDefault(!1)),yt=l.boolean(`json`).pipe(l.withDescription(`Output validation results as JSON`),l.withDefault(!1)),bt=l.boolean(`quiet`).pipe(l.withDescription(`No output, exit code only`),l.withDefault(!1)),xt=c.make(`validate`,{id:gt,type:_t,stdin:vt,json:yt,quiet:bt},r.fn(`cli.validate`)(function*({id:e,type:t,stdin:n,json:r,quiet:i}){let a=yield*D,s=yield*G,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=[W(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?We(e,c):H(e));if(i||(yield*a.write(be(u),{json:r})),u.some(e=>!e.valid))return yield*new ue({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`}])),St=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 typeid --prefix user`,description:`Generate one user TypeID`},{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([Fe,xt,ht,Ie,Le,Re,ze,Be,Ve,He])),Ct=e=>c.runWith(St,{version:e});function wt(e){return e.includes(`--json`)}const Tt=S.type().pipe(S.tag(`CliError`,e=>e.exitCode),S.tag(`ValidationFailedError`,e=>e.exitCode),S.tag(`ShowHelp`,e=>e.errors.length>0?1:0),S.tag(`UnrecognizedOption`,`DuplicateOption`,`MissingOption`,`MissingArgument`,`InvalidValue`,`UnknownSubcommand`,`UserError`,()=>1),S.exhaustive),Et=r.fn(`cli.handleCliFailure`)(function*(e,t){yield*S.value(e).pipe(S.tag(`CliError`,`ValidationFailedError`,e=>D.use(n=>n.writeError(Se(e),{json:wt(t)}))),S.tag(`ShowHelp`,()=>r.void),S.tag(`UnrecognizedOption`,`DuplicateOption`,`MissingOption`,`MissingArgument`,`InvalidValue`,`UnknownSubcommand`,`UserError`,e=>ee.error(`Error: ${e.message}`)),S.exhaustive),process.exitCode=Tt(e)});var K=class e extends x.Service()(`uniku/cli/UpdateCheckService`){static layer=a.sync(e,()=>Rt())};const q=`@uniku/cli`;function Dt(){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 Ot(){let e=Dt(),t=e?`uniku-update-check-${e}.json`:`uniku-update-check.json`;return ce(ae(),t)}const kt=Ot();function J(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 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 X(e){return C.option(C.string(e)).pipe(r.catch(()=>r.succeed(o.none())))}function Z(e){return o.isSome(e)&&e.value.length>0}const At=r.all({noUpdateNotifier:X(`NO_UPDATE_NOTIFIER`),ci:X(`CI`),continuousIntegration:X(`CONTINUOUS_INTEGRATION`),nodeEnv:X(`NODE_ENV`)});function jt(e=process.stderr.isTTY){return At.pipe(r.map(t=>Z(t.noUpdateNotifier)||Z(t.ci)||Z(t.continuousIntegration)||o.isSome(t.nodeEnv)&&t.nodeEnv.value===`test`||!e))}function Mt(e,t){if(t){let t=e.isStandaloneBinary?`Download at https://github.com/jkomyno/uniku/releases`:`Run \`npm install -g ${q}\` 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 ${q}\`${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 Nt(e){return X(`NO_COLOR`).pipe(r.map(t=>Mt(e,Z(t))))}function Pt(e,t){return o.isSome(t)&&!e.includes(`--json`)}function Ft(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(se(t),{recursive:!0});let n=`${t}.tmp`;ie(n,JSON.stringify(e)),re(n,t)}catch{}}function It(e){return r.tryPromise({try:t=>fetch(`https://registry.npmjs.org/%40uniku%2Fcli/latest`,{headers:{Accept:`application/json`,"User-Agent":`${q}/${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 Lt(){try{return typeof __STANDALONE_BINARY__<`u`&&__STANDALONE_BINARY__===!0}catch{return!1}}function Rt(e={}){let t=e.cacheFile??kt,n=e.fetchLatestVersion??It,i=e.now??Date.now,a=e.isStandaloneBinary??Lt,s=e.isStderrTTY??(()=>process.stderr.isTTY),c=e.writeStderr??(e=>process.stderr.write(e));return K.of({check:r.fn(`UpdateCheckService.check`)(function*(e){if(yield*jt(s()))return o.none();let r=Ft(t),c=i();if(r&&c-r.checkedAt<864e5)return r.latestVersion&&Y(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),Y(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*Nt(e);yield*r.sync(()=>{c(t)})})})}var $=`0.4.0`;const zt=Ct($),Bt=a.mergeAll(D.layer,G.layer,K.layer,t.layer);r.gen(function*(){let e=yield*K,t=st(process.argv.slice(2)),a=yield*r.forkChild(e.check($),{startImmediately:!0});yield*zt(t).pipe(r.catch(e=>Et(e,t)));let s=yield*i.join(a).pipe(r.timeoutOption(n.millis(250)));yield*i.interrupt(a);let c=o.flatten(s);Pt(t,c)&&(yield*e.notify(c.value))}).pipe(r.provide(Bt),e.runMain);export{};
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{cuidv2 as f}from"uniku/cuid/v2";import{UniqueIdError as p}from"uniku/errors";import{ksuid as m}from"uniku/ksuid";import{nanoid as h}from"uniku/nanoid";import{objectid as g}from"uniku/objectid";import{tsid as _}from"uniku/tsid";import{typeid as v}from"uniku/typeid";import{ulid as y}from"uniku/ulid";import{uuidv4 as b}from"uniku/uuid/v4";import{uuidv7 as x}from"uniku/uuid/v7";import*as S from"effect/Context";import{ID_GENERATORS as C}from"uniku/generators";import*as ee from"effect/Console";import*as w 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 se,join as ce}from"node:path";import*as T from"effect/Config";const le={hex:`0123456789abcdef`,numeric:`0123456789`,alpha:`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`};var E=class extends d.TaggedErrorClass()(`CliError`,{code:d.String,message:d.String,hint:d.optionalKey(d.String)}){exitCode=1},ue=class extends d.TaggedErrorClass()(`ValidationFailedError`,{message:d.String}){code=`VALIDATION_FAILED`;hint=void 0;exitCode=2};function D(e){return new E({code:e.code,message:e.message})}function de(e){let t={error:e.message,code:e.code};return e.hint&&(t.hint=e.hint),t}function fe(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?D(e):new E({code:`GENERATE_FAILED`,message:String(e)})})}function pe(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?D(e):new E({code:`GENERATE_FAILED`,message:String(e)})})}function me(e){if(e)return le[e]??e}function he(e){return r.try({try:()=>{let t=me(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?D(e):new E({code:`GENERATE_FAILED`,message:String(e)})})}function ge(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(g(n))}return t},catch:e=>e instanceof p?D(e):new E({code:`GENERATE_FAILED`,message:String(e)})})}function _e(e){return r.try({try:()=>{let t=e.timestamp!=null||e.node!=null||e.nodeBits!=null,n=[];if(!t){for(let t=0;t<e.count;t++)n.push(_.toString(_()));return n}let r=2**(22-(e.nodeBits??10)),i=e.timestamp??Date.now();for(let t=0;t<e.count;t++){let a={msecs:i+Math.floor(t/r),counter:t%r,...e.node==null?{}:{node:e.node},...e.nodeBits==null?{}:{nodeBits:e.nodeBits}};n.push(_.toString(_(a)))}return n},catch:e=>e instanceof p?D(e):new E({code:`GENERATE_FAILED`,message:String(e)})})}function ve(e){return r.try({try:()=>{let t=[];for(let n=0;n<e.count;n++)t.push(v(e.prefix));return t},catch:e=>e instanceof p?D(e):new E({code:`GENERATE_FAILED`,message:String(e)})})}function ye(e){return e.monotonic&&e.timestamp!=null?r.fail(new E({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=y(e.timestamp==null?void 0:{msecs:e.timestamp});e.lowercase&&(n=n.toLowerCase()),t.push(n)}return t},catch:e=>e instanceof p?D(e):new E({code:`GENERATE_FAILED`,message:String(e)})})}function be(e){return r.try({try:()=>{let t=e.version===7?x:b,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?D(e):new E({code:`GENERATE_FAILED`,message:String(e)})})}function O(e,t){return t.json?[JSON.stringify(e.json())]:e.text()}var k=class e extends S.Service()(`uniku/cli/OutputService`){static layer=a.succeed(e,e.of({write:(e,t)=>r.sync(()=>A(process.stdout,O(e,t))),writeError:(e,t)=>r.sync(()=>A(process.stderr,O(e,t)))}))};function A(e,t){for(let n of t)e.write(`${n}\n`)}function j(e){return{json:()=>e.length===1?e[0]:e,text:()=>e}}function xe(e){return{json:()=>e.length===1?e[0]:e,text:()=>e.map(we)}}function Se(e){return{json:()=>e,text:()=>[Te(e)]}}function Ce(e){return{json:()=>de(e),text:()=>[Ee(e)]}}function we(e){if(e.valid){let t=e.version==null?``:` v${e.version}`;return`valid (${e.type}${t})`}return`invalid: ${e.error??`malformed identifier`}`}function Te(e){let t=[],n=e.version==null?e.type:`${e.type} (v${e.version})`;return t.push(`Type: ${n}`),e.prefix!=null&&t.push(`Prefix: ${e.prefix===``?`(empty)`:e.prefix}`),e.suffix&&t.push(`Suffix: ${e.suffix}`),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 Ee(e){return e.hint?`Error: ${e.message}\n ${e.hint}`:`Error: ${e.message}`}const M=l.integer(`count`).pipe(l.withAlias(`n`),l.withDescription(`Number of IDs to generate`),l.withDefault(1)),N=l.boolean(`json`).pipe(l.withDescription(`Output as JSON`),l.withDefault(!1)),De=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:M,json:N,version:De,lowercase:P},r.fn(`cli.generate.uuid`)(function*({count:e,json:t,version:n,lowercase:r}){let i=yield*k,a=yield*be({count:e,version:n,lowercase:r});yield*i.write(j(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`}])),Oe=l.string(`prefix`).pipe(l.withAlias(`p`),l.withDescription(`Type prefix, e.g. "user" for user_... (empty by default)`),l.withDefault(``)),I=c.make(`typeid`,{count:M,json:N,prefix:Oe},r.fn(`cli.generate.typeid`)(function*({count:e,json:t,prefix:n}){let r=yield*k,i=yield*ve({count:e,prefix:n});yield*r.write(j(i),{json:t})})).pipe(c.withDescription(`Generate TypeIDs`),c.withExamples([{command:`uniku typeid --prefix user`,description:`Generate a TypeID such as user_...`},{command:`uniku typeid -p api_key -n 5 --json`,description:`Generate 5 api_key TypeIDs as JSON`},{command:`uniku typeid`,description:`Generate a canonical prefixless TypeID`}])),ke=l.boolean(`monotonic`).pipe(l.withDescription(`Generate monotonically increasing ULIDs`),l.withDefault(!1)),Ae=l.string(`timestamp`).pipe(l.withDescription(`Unix timestamp in milliseconds (or "now")`),l.optional),L=c.make(`ulid`,{count:M,json:N,monotonic:ke,timestamp:Ae,lowercase:P},r.fn(`cli.generate.ulid`)(function*({count:e,json:t,monotonic:n,timestamp:r,lowercase:i}){let a=yield*k,s=o.getOrUndefined(r),c=yield*ye({count:e,monotonic:n,timestamp:s===void 0?void 0:yield*W(s),lowercase:i});yield*a.write(j(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)`}])),je=l.integer(`size`).pipe(l.withAlias(`s`),l.withDescription(`Length of ID (1-256)`),l.withDefault(21)),Me=l.string(`alphabet`).pipe(l.withAlias(`a`),l.withDescription(`Custom alphabet or preset: hex, numeric, alpha`),l.optional),R=c.make(`nanoid`,{count:M,json:N,size:je,alphabet:Me},r.fn(`cli.generate.nanoid`)(function*({count:e,json:t,size:n,alphabet:r}){let i=yield*k,a=yield*he({count:e,size:n,alphabet:o.getOrUndefined(r)});yield*i.write(j(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`}])),Ne=l.integer(`length`).pipe(l.withAlias(`l`),l.withDescription(`Length of ID (2-32)`),l.withDefault(24)),z=c.make(`cuid`,{count:M,json:N,length:Ne},r.fn(`cli.generate.cuid`)(function*({count:e,json:t,length:n}){let r=yield*k,i=yield*fe({count:e,length:n});yield*r.write(j(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`}])),Pe=l.string(`timestamp`).pipe(l.withDescription(`Unix timestamp in seconds (or "now")`),l.optional),B=c.make(`ksuid`,{count:M,json:N,timestamp:Pe},r.fn(`cli.generate.ksuid`)(function*({count:e,json:t,timestamp:n}){let r=yield*k,i=o.getOrUndefined(n),a=yield*pe({count:e,timestamp:i===void 0?void 0:yield*G(i)});yield*r.write(j(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)`}])),Fe=l.string(`timestamp`).pipe(l.withDescription(`Unix timestamp in seconds (or "now")`),l.optional),V=c.make(`objectid`,{count:M,json:N,timestamp:Fe},r.fn(`cli.generate.objectid`)(function*({count:e,json:t,timestamp:n}){let r=yield*k,i=o.getOrUndefined(n),a=yield*ge({count:e,timestamp:i===void 0?void 0:yield*G(i)});yield*r.write(j(a),{json:t})})).pipe(c.withDescription(`Generate MongoDB ObjectIDs`),c.withExamples([{command:`uniku objectid -n 5 --json`,description:`Generate 5 ObjectIDs as a JSON array`},{command:`uniku objectid --timestamp 1720000000`,description:`Generate an ObjectID for a fixed Unix timestamp (s)`}])),Ie=l.string(`timestamp`).pipe(l.withDescription(`Unix timestamp in milliseconds (or "now")`),l.optional),Le=l.string(`node`).pipe(l.withDescription(`Node ID (0 to 2^node-bits - 1)`),l.optional),Re=l.string(`node-bits`).pipe(l.withDescription(`Number of bits allocated to the node ID (0-20, default 10)`),l.optional),H=c.make(`tsid`,{count:M,json:N,timestamp:Ie,node:Le,nodeBits:Re},r.fn(`cli.generate.tsid`)(function*({count:e,json:t,timestamp:n,node:r,nodeBits:i}){let a=yield*k,s=o.getOrUndefined(n),c=s===void 0?void 0:yield*W(s),l=o.getOrUndefined(r),u=l===void 0?void 0:yield*Je(l),d=o.getOrUndefined(i),f=yield*_e({count:e,timestamp:c,node:u,nodeBits:d===void 0?void 0:yield*Ye(d)});yield*a.write(j(f),{json:t})})).pipe(c.withDescription(`Generate TSIDs (64-bit Snowflake-style, time-sorted)`),c.withExamples([{command:`uniku tsid -n 5 --json`,description:`Generate 5 TSIDs as a JSON array`},{command:`uniku tsid --timestamp 1720000000000`,description:`Generate a TSID for a fixed Unix timestamp (ms)`},{command:`uniku tsid --node 42 --node-bits 10`,description:`Generate a TSID for a fixed node ID`}])),ze=c.make(`generate`).pipe(c.withDescription(`Generate new IDs`),c.withSubcommands([F,L,I,R,z,B,V,H]),c.withExamples([{command:`uniku generate uuid -n 5 --json`,description:`Generate 5 UUIDs as a JSON array`},{command:`uniku generate typeid --prefix user`,description:`Generate one user TypeID`},{command:`uniku generate ulid`,description:"Generate one ULID (subcommands also work top-level: `uniku ulid`)"}])),Be=F,Ve=L,He=I,Ue=R,We=z,Ge=B,Ke=V,qe=H,U=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 E({code:`INVALID_TIMESTAMP`,message:`Invalid timestamp: "${e}"`,hint:n}):r}),W=e=>U(e,e=>e,`Provide a Unix timestamp in milliseconds or "now"`),G=e=>U(e,e=>Math.floor(e/1e3),`Provide a Unix timestamp in seconds or "now"`),K=r.fn(`cli.generate.parseNonNegativeInt`)(function*(e,t,n,r){let i=Number(e);return!Number.isInteger(i)||i<0?yield*new E({code:t,message:`Invalid ${n}: "${e}"`,hint:r}):i}),Je=e=>K(e,`INVALID_NODE`,`node`,`Provide a non-negative integer for --node`),Ye=e=>K(e,`INVALID_NODE_BITS`,`node-bits`,`Provide a non-negative integer (0-20) for --node-bits`);function Xe(e,t){switch(t){case`uuid`:return Ze(e);case`ulid`:return Qe(e);case`typeid`:return $e(e);case`ksuid`:return et(e);case`objectid`:return tt(e);case`cuid`:return nt(e);case`nanoid`:return rt(e);case`tsid`:return J(e)}}function q(e){return x.isValid(e)?{id:e,valid:!0,type:`uuid`,version:7}:b.isValid(e)?{id:e,valid:!0,type:`uuid`,version:4}:v.isValid(e)?{id:e,valid:!0,type:`typeid`,version:7}:y.isValid(e)?{id:e,valid:!0,type:`ulid`}:m.isValid(e)?{id:e,valid:!0,type:`ksuid`}:g.isValid(e)?{id:e,valid:!0,type:`objectid`}:J(e).valid?{id:e,valid:!0,type:`tsid`}: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 Ze(e){return x.isValid(e)?{id:e,valid:!0,type:`uuid`,version:7}:b.isValid(e)?{id:e,valid:!0,type:`uuid`,version:4}:{id:e,valid:!1,type:`uuid`,error:`invalid UUID format`}}function Qe(e){return y.isValid(e)?{id:e,valid:!0,type:`ulid`}:{id:e,valid:!1,type:`ulid`,error:`invalid ULID format`}}function $e(e){return v.isValid(e)?{id:e,valid:!0,type:`typeid`,version:7}:{id:e,valid:!1,type:`typeid`,error:`invalid TypeID format`}}function et(e){return m.isValid(e)?{id:e,valid:!0,type:`ksuid`}:{id:e,valid:!1,type:`ksuid`,error:`invalid KSUID format`}}function tt(e){return g.isValid(e)?{id:e,valid:!0,type:`objectid`}:{id:e,valid:!1,type:`objectid`,error:`invalid ObjectID format`}}function nt(e){return f.isValid(e)?{id:e,valid:!0,type:`cuid`}:{id:e,valid:!1,type:`cuid`,error:`invalid CUID format`}}function rt(e){return h.isValid(e)?{id:e,valid:!0,type:`nanoid`}:{id:e,valid:!1,type:`nanoid`,error:`invalid Nanoid format`}}function J(e){try{return _.fromString(e),{id:e,valid:!0,type:`tsid`}}catch{return{id:e,valid:!1,type:`tsid`,error:`invalid TSID format`}}}function it(e,t){let n=t??at(e);if(!n)return null;switch(n){case`uuid`:return ot(e);case`ulid`:return st(e);case`typeid`:return ct(e);case`ksuid`:return lt(e);case`objectid`:return ut(e);case`cuid`:return dt(e);case`nanoid`:return ft(e);case`tsid`:return pt(e)}}function at(e){let t=q(e);return t.valid?t.type??null:null}function ot(e){if(x.isValid(e)){let t=x.timestamp(e),n=x.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 b.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 st(e){let t=y.timestamp(e),n=e.slice(10);return{id:e,type:`ulid`,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:n}}function ct(e){if(!v.isValid(e))return{id:e,type:`typeid`,note:`Unrecognized TypeID format.`};let t=v.timestamp(e),n=v.toBytes(e),r=Buffer.from(n.slice(10)).toString(`hex`);return{id:e,type:`typeid`,version:7,prefix:v.prefix(e),suffix:v.suffix(e),timestamp:new Date(t).toISOString(),timestamp_ms:t,random:r}}function lt(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 ut(e){let t=g.timestamp(e),n=g.toBytes(e),r=Buffer.from(n.slice(4)).toString(`hex`);return{id:e,type:`objectid`,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:r}}function dt(e){return{id:e,type:`cuid`,note:`This ID type contains no decodable metadata.`}}function ft(e){return{id:e,type:`nanoid`,note:`This ID type contains no decodable metadata.`}}function pt(e){let t;try{t=_.fromString(e)}catch{return{id:e,type:`tsid`,note:`Unrecognized TSID format.`}}let n=_.timestamp(t),r=(t&4194303n).toString(16);return{id:e,type:`tsid`,timestamp:new Date(n).toISOString(),timestamp_ms:n,random:r}}function mt(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 bt(n)?[...n,...r.map(yt)]:[...n,`--`,...r]}const ht=`\0uniku-literal:`,gt=new Set([`inspect`,`validate`]),_t=new Set([`--completions`,`--log-level`]);function vt(e){return e.startsWith(ht)?e.slice(15):e}function yt(e){return`${ht}${e}`}function bt(e){for(let t=0;t<e.length;t+=1){let n=e[t];if(n.startsWith(`-`)){_t.has(n)&&(t+=1);continue}return gt.has(n)}return!1}const xt=s.string(`id`).pipe(s.withDescription(`The ID to inspect`)),St=l.choice(`type`,C).pipe(l.withDescription(`ID type (auto-detected if omitted)`),l.optional),Ct=l.boolean(`json`).pipe(l.withDescription(`Output as JSON`),l.withDefault(!1)),wt=c.make(`inspect`,{id:xt,type:St,json:Ct},r.fn(`cli.inspect`)(function*({id:e,type:t,json:n}){let r=yield*k,i=o.getOrUndefined(t),a=vt(e),s=it(a,i);if(!s)return yield*new E({code:`UNKNOWN_ID_TYPE`,message:`Could not identify ID type for: "${a}"`,hint:`Use --type to specify the ID type`});yield*r.write(Se(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 Tt=class e extends S.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 E({code:`STDIN_ERROR`,message:t.message})))}),process.stdin.resume()}))}))};const Et=s.string(`id`).pipe(s.withDescription(`The ID to validate`),s.optional),Dt=l.choice(`type`,C).pipe(l.withDescription(`Expected ID type (auto-detected if omitted)`),l.optional),Ot=l.boolean(`stdin`).pipe(l.withDescription(`Read IDs from stdin (one per line)`),l.withDefault(!1)),kt=l.boolean(`json`).pipe(l.withDescription(`Output validation results as JSON`),l.withDefault(!1)),At=l.boolean(`quiet`).pipe(l.withDescription(`No output, exit code only`),l.withDefault(!1)),jt=c.make(`validate`,{id:Et,type:Dt,stdin:Ot,json:kt,quiet:At},r.fn(`cli.validate`)(function*({id:e,type:t,stdin:n,json:r,quiet:i}){let a=yield*k,s=yield*Tt,c=o.getOrUndefined(t),l;if(n){if(l=yield*s.readLines(),l.length===0)return yield*new E({code:`NO_INPUT`,message:`No IDs provided on stdin`})}else if(o.isSome(e))l=[vt(e.value)];else return yield*new E({code:`NO_INPUT`,message:`No ID provided`,hint:`Pass an ID as argument or use --stdin`});let u=l.map(e=>c?Xe(e,c):q(e));if(i||(yield*a.write(xe(u),{json:r})),u.some(e=>!e.valid))return yield*new ue({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`}])),Mt=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 typeid --prefix user`,description:`Generate one user TypeID`},{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([ze,jt,wt,Be,Ve,He,Ue,We,Ge,Ke,qe])),Nt=e=>c.runWith(Mt,{version:e});function Pt(e){return e.includes(`--json`)}const Ft=w.type().pipe(w.tag(`CliError`,e=>e.exitCode),w.tag(`ValidationFailedError`,e=>e.exitCode),w.tag(`ShowHelp`,e=>+(e.errors.length>0)),w.tag(`UnrecognizedOption`,`DuplicateOption`,`MissingOption`,`MissingArgument`,`InvalidValue`,`UnknownSubcommand`,`UserError`,()=>1),w.exhaustive),It=r.fn(`cli.handleCliFailure`)(function*(e,t){yield*w.value(e).pipe(w.tag(`CliError`,`ValidationFailedError`,e=>k.use(n=>n.writeError(Ce(e),{json:Pt(t)}))),w.tag(`ShowHelp`,()=>r.void),w.tag(`UnrecognizedOption`,`DuplicateOption`,`MissingOption`,`MissingArgument`,`InvalidValue`,`UnknownSubcommand`,`UserError`,e=>ee.error(`Error: ${e.message}`)),w.exhaustive),process.exitCode=Ft(e)});var Y=class e extends S.Service()(`uniku/cli/UpdateCheckService`){static layer=a.sync(e,()=>Zt())};const X=`@uniku/cli`;function Lt(){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 Rt(){let e=Lt(),t=e?`uniku-update-check-${e}.json`:`uniku-update-check.json`;return ce(ae(),t)}const zt=Rt();function Bt(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 Vt(e,t){let n=Bt(e),r=Bt(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 Z(e){return T.option(T.string(e)).pipe(r.catch(()=>r.succeed(o.none())))}function Q(e){return o.isSome(e)&&e.value.length>0}const Ht=r.all({noUpdateNotifier:Z(`NO_UPDATE_NOTIFIER`),ci:Z(`CI`),continuousIntegration:Z(`CONTINUOUS_INTEGRATION`),nodeEnv:Z(`NODE_ENV`)});function Ut(e=process.stderr.isTTY){return Ht.pipe(r.map(t=>Q(t.noUpdateNotifier)||Q(t.ci)||Q(t.continuousIntegration)||o.isSome(t.nodeEnv)&&t.nodeEnv.value===`test`||!e))}function Wt(e,t){if(t){let t=e.isStandaloneBinary?`Download at https://github.com/jkomyno/uniku/releases`:`Run \`npm install -g ${X}\` 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 ${X}\`${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 Gt(e){return Z(`NO_COLOR`).pipe(r.map(t=>Wt(e,Q(t))))}function Kt(e,t){return o.isSome(t)&&!e.includes(`--json`)}function qt(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 Jt(e,t){try{te(se(t),{recursive:!0});let n=`${t}.tmp`;ie(n,JSON.stringify(e)),re(n,t)}catch{}}function Yt(e){return r.tryPromise({try:t=>fetch(`https://registry.npmjs.org/%40uniku%2Fcli/latest`,{headers:{Accept:`application/json`,"User-Agent":`${X}/${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 Xt(){try{return typeof __STANDALONE_BINARY__<`u`&&__STANDALONE_BINARY__===!0}catch{return!1}}function Zt(e={}){let t=e.cacheFile??zt,n=e.fetchLatestVersion??Yt,i=e.now??Date.now,a=e.isStandaloneBinary??Xt,s=e.isStderrTTY??(()=>process.stderr.isTTY),c=e.writeStderr??(e=>process.stderr.write(e));return Y.of({check:r.fn(`UpdateCheckService.check`)(function*(e){if(yield*Ut(s()))return o.none();let r=qt(t),c=i();if(r&&c-r.checkedAt<864e5)return r.latestVersion&&Vt(r.latestVersion,e)?o.some({currentVersion:e,latestVersion:r.latestVersion,isStandaloneBinary:a()}):o.none();let l=yield*n(e);return l===null?(Jt({checkedAt:c},t),o.none()):(Jt({latestVersion:l,checkedAt:c},t),Vt(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*Gt(e);yield*r.sync(()=>{c(t)})})})}var $=`0.5.0`;const Qt=Nt($),$t=a.mergeAll(k.layer,Tt.layer,Y.layer,t.layer);r.gen(function*(){let e=yield*Y,t=mt(process.argv.slice(2)),a=yield*r.forkChild(e.check($),{startImmediately:!0});yield*Qt(t).pipe(r.catch(e=>It(e,t)));let s=yield*i.join(a).pipe(r.timeoutOption(n.millis(250)));yield*i.interrupt(a);let c=o.flatten(s);Kt(t,c)&&(yield*e.notify(c.value))}).pipe(r.provide($t),e.runMain);export{};
7
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>","obj: { error: string; code: string; hint?: string }","ids: string[]","ids: 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/objectid.ts","../src/generators/typeid.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 { objectid } from 'uniku/objectid'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type ObjectidGenerateOptions = {\n readonly count: number\n readonly timestamp?: number\n}\n\nexport function generateObjectid(options: ObjectidGenerateOptions): 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 objectidOpts = options.timestamp != null ? { secs: options.timestamp } : undefined\n ids.push(objectid(objectidOpts))\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 { typeid } from 'uniku/typeid'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type TypeidGenerateOptions = {\n readonly count: number\n readonly prefix: string\n}\n\nexport function generateTypeid(options: TypeidGenerateOptions): 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(typeid(options.prefix))\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.prefix != null) {\n lines.push(`Prefix: ${result.prefix === '' ? '(empty)' : result.prefix}`)\n }\n if (result.suffix) {\n lines.push(`Suffix: ${result.suffix}`)\n }\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 { generateObjectid } from '@/src/generators/objectid'\nimport { generateTypeid } from '@/src/generators/typeid'\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// ── TypeID subcommand ───────────────────────────────────────────────\n\nconst typeidPrefixFlag = Flag.string('prefix').pipe(\n Flag.withAlias('p'),\n Flag.withDescription('Type prefix, e.g. \"user\" for user_... (empty by default)'),\n Flag.withDefault(''),\n)\n\nconst typeidSubcommand = Command.make(\n 'typeid',\n {\n count: countFlag,\n json: jsonFlag,\n prefix: typeidPrefixFlag,\n },\n Effect.fn('cli.generate.typeid')(function* ({ count, json, prefix }) {\n const output = yield* OutputService\n const ids = yield* generateTypeid({ count, prefix })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate TypeIDs'),\n Command.withExamples([\n { command: 'uniku typeid --prefix user', description: 'Generate a TypeID such as user_...' },\n { command: 'uniku typeid -p api_key -n 5 --json', description: 'Generate 5 api_key TypeIDs as JSON' },\n { command: 'uniku typeid', description: 'Generate a canonical prefixless TypeID' },\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// ── ObjectID subcommand ─────────────────────────────────────────────\n\nconst objectidTimestampFlag = Flag.string('timestamp').pipe(\n Flag.withDescription('Unix timestamp in seconds (or \"now\")'),\n Flag.optional,\n)\n\nconst objectidSubcommand = Command.make(\n 'objectid',\n {\n count: countFlag,\n json: jsonFlag,\n timestamp: objectidTimestampFlag,\n },\n Effect.fn('cli.generate.objectid')(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* generateObjectid({ count, timestamp })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate MongoDB ObjectIDs'),\n Command.withExamples([\n { command: 'uniku objectid -n 5 --json', description: 'Generate 5 ObjectIDs as a JSON array' },\n {\n command: 'uniku objectid --timestamp 1720000000',\n description: 'Generate an ObjectID for a fixed Unix timestamp (s)',\n },\n ]),\n)\n\n// ── Generate parent command ─────────────────────────────────────────\n\nexport const generateCommand = Command.make('generate').pipe(\n Command.withDescription('Generate new IDs'),\n Command.withSubcommands([\n uuidSubcommand,\n ulidSubcommand,\n typeidSubcommand,\n nanoidSubcommand,\n cuidSubcommand,\n ksuidSubcommand,\n objectidSubcommand,\n ]),\n Command.withExamples([\n { command: 'uniku generate uuid -n 5 --json', description: 'Generate 5 UUIDs as a JSON array' },\n { command: 'uniku generate typeid --prefix user', description: 'Generate one user TypeID' },\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 typeidShorthand = typeidSubcommand\nexport const nanoidShorthand = nanoidSubcommand\nexport const cuidShorthand = cuidSubcommand\nexport const ksuidShorthand = ksuidSubcommand\nexport const objectidShorthand = objectidSubcommand\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 { objectid } from 'uniku/objectid'\nimport { typeid } from 'uniku/typeid'\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 'typeid':\n return validateTypeid(id)\n case 'ksuid':\n return validateKsuid(id)\n case 'objectid':\n return validateObjectid(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 > TypeID > ULID > KSUID > ObjectID > CUID > Nanoid.\n *\n * ObjectID must be checked before CUID: CUID2's default validation regex\n * (`/^[a-z][0-9a-z]+$/`, default length 24) accepts any 24-character string\n * over 0-9a-z that starts with a letter. ObjectID's alphabet (0-9a-f) is a\n * strict subset of that at the same default length, so any ObjectID whose\n * first hex digit is a-f (~37.5% of generated IDs) would also satisfy\n * cuid2.isValid() if checked first.\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. TypeID (optional prefix + UUID v7 base32 suffix)\n if (typeid.isValid(id)) {\n return { id, valid: true, type: 'typeid', version: 7 }\n }\n\n // 3. ULID (26 chars, Crockford Base32)\n if (ulid.isValid(id)) {\n return { id, valid: true, type: 'ulid' }\n }\n\n // 4. KSUID (27 chars, Base62)\n if (ksuid.isValid(id)) {\n return { id, valid: true, type: 'ksuid' }\n }\n\n // 5. ObjectID (24 chars, hex) - must precede CUID2, see doc comment above\n if (objectid.isValid(id)) {\n return { id, valid: true, type: 'objectid' }\n }\n\n // 6. CUID (starts with letter, Base36)\n if (cuid2.isValid(id)) {\n return { id, valid: true, type: 'cuid' }\n }\n\n // 7. 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 validateTypeid(id: string): ValidationResult {\n if (typeid.isValid(id)) {\n return { id, valid: true, type: 'typeid', version: 7 }\n }\n return { id, valid: false, type: 'typeid', error: 'invalid TypeID 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 validateObjectid(id: string): ValidationResult {\n if (objectid.isValid(id)) {\n return { id, valid: true, type: 'objectid' }\n }\n return { id, valid: false, type: 'objectid', error: 'invalid ObjectID 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 { objectid } from 'uniku/objectid'\nimport { typeid } from 'uniku/typeid'\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 'typeid':\n return inspectTypeid(id)\n case 'ksuid':\n return inspectKsuid(id)\n case 'objectid':\n return inspectObjectid(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 inspectTypeid(id: string): InspectResult {\n if (!typeid.isValid(id)) {\n return {\n id,\n type: 'typeid',\n note: 'Unrecognized TypeID format.',\n }\n }\n\n const ms = typeid.timestamp(id)\n const bytes = typeid.toBytes(id)\n // UUID v7 random component: last 6 bytes (bytes 10-15)\n const random = Buffer.from(bytes.slice(10)).toString('hex')\n return {\n id,\n type: 'typeid',\n version: 7,\n prefix: typeid.prefix(id),\n suffix: typeid.suffix(id),\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 inspectObjectid(id: string): InspectResult {\n const ms = objectid.timestamp(id)\n const bytes = objectid.toBytes(id)\n // Random + counter tail: last 8 bytes (bytes 4-11)\n const random = Buffer.from(bytes.slice(4)).toString('hex')\n return {\n id,\n type: 'objectid',\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', 'typeid', 'nanoid', 'cuid', 'ksuid', 'objectid'] 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', 'typeid', 'nanoid', 'cuid', 'ksuid', 'objectid'] 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 objectidShorthand,\n typeidShorthand,\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 typeid --prefix user', description: 'Generate one user TypeID' },\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 typeidShorthand,\n nanoidShorthand,\n cuidShorthand,\n ksuidShorthand,\n objectidShorthand,\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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"}
1
+ {"version":3,"file":"bin.mjs","names":["jsonFlag","idArg","typeFlag","jsonFlag","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/objectid.ts","../src/generators/tsid.ts","../src/generators/typeid.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 { cuidv2 } from 'uniku/cuid/v2'\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(cuidv2({ 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 { objectid } from 'uniku/objectid'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type ObjectidGenerateOptions = {\n readonly count: number\n readonly timestamp?: number\n}\n\nexport function generateObjectid(options: ObjectidGenerateOptions): 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 objectidOpts = options.timestamp != null ? { secs: options.timestamp } : undefined\n ids.push(objectid(objectidOpts))\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 { tsid } from 'uniku/tsid'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type TsidGenerateOptions = {\n readonly count: number\n readonly timestamp?: number\n readonly node?: number\n readonly nodeBits?: number\n}\n\nexport function generateTsid(options: TsidGenerateOptions): Effect.Effect<string[], CliError> {\n return Effect.try({\n try: () => {\n // `tsid()` treats a *truthy* options object as a request for fully\n // deterministic output (bypassing the persistent node/counter state),\n // even if every field on it is `undefined`. So only build an options\n // object when at least one of timestamp/node/nodeBits was actually\n // requested - otherwise pass `undefined` to preserve the persistent,\n // stateful default behavior every other no-flag CLI invocation gets.\n const hasOptions = options.timestamp != null || options.node != null || options.nodeBits != null\n\n const ids: string[] = []\n\n if (!hasOptions) {\n for (let i = 0; i < options.count; i++) {\n // tsid() returns a bigint - convert immediately so no raw bigint\n // ever reaches this CLI-facing `string[]` surface.\n ids.push(tsid.toString(tsid()))\n }\n return ids\n }\n\n // Any of timestamp/node/nodeBits bypasses the core generator's persistent\n // counter (options bypass state entirely, per tsid()'s contract), so a\n // naive per-call options object would have each id draw an independent\n // random counter instead of an incrementing one - with a small counterBits\n // (e.g. --node-bits 20 leaves only 2 counter bits), that makes duplicate\n // ids within the batch near-certain. Step the counter across the loop\n // instead, rolling over into the timestamp on overflow, mirroring the\n // core generator's own clock-drift-ahead behavior (R7).\n const nodeBits = options.nodeBits ?? 10\n const counterRange = 2 ** (22 - nodeBits)\n const baseMsecs = options.timestamp ?? Date.now()\n\n for (let i = 0; i < options.count; i++) {\n const tsidOpts = {\n msecs: baseMsecs + Math.floor(i / counterRange),\n counter: i % counterRange,\n ...(options.node != null ? { node: options.node } : {}),\n ...(options.nodeBits != null ? { nodeBits: options.nodeBits } : {}),\n }\n ids.push(tsid.toString(tsid(tsidOpts)))\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 { typeid } from 'uniku/typeid'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type TypeidGenerateOptions = {\n readonly count: number\n readonly prefix: string\n}\n\nexport function generateTypeid(options: TypeidGenerateOptions): 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(typeid(options.prefix))\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.prefix != null) {\n lines.push(`Prefix: ${result.prefix === '' ? '(empty)' : result.prefix}`)\n }\n if (result.suffix) {\n lines.push(`Suffix: ${result.suffix}`)\n }\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 { generateObjectid } from '@/src/generators/objectid'\nimport { generateTsid } from '@/src/generators/tsid'\nimport { generateTypeid } from '@/src/generators/typeid'\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// ── TypeID subcommand ───────────────────────────────────────────────\n\nconst typeidPrefixFlag = Flag.string('prefix').pipe(\n Flag.withAlias('p'),\n Flag.withDescription('Type prefix, e.g. \"user\" for user_... (empty by default)'),\n Flag.withDefault(''),\n)\n\nconst typeidSubcommand = Command.make(\n 'typeid',\n {\n count: countFlag,\n json: jsonFlag,\n prefix: typeidPrefixFlag,\n },\n Effect.fn('cli.generate.typeid')(function* ({ count, json, prefix }) {\n const output = yield* OutputService\n const ids = yield* generateTypeid({ count, prefix })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate TypeIDs'),\n Command.withExamples([\n { command: 'uniku typeid --prefix user', description: 'Generate a TypeID such as user_...' },\n { command: 'uniku typeid -p api_key -n 5 --json', description: 'Generate 5 api_key TypeIDs as JSON' },\n { command: 'uniku typeid', description: 'Generate a canonical prefixless TypeID' },\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// ── ObjectID subcommand ─────────────────────────────────────────────\n\nconst objectidTimestampFlag = Flag.string('timestamp').pipe(\n Flag.withDescription('Unix timestamp in seconds (or \"now\")'),\n Flag.optional,\n)\n\nconst objectidSubcommand = Command.make(\n 'objectid',\n {\n count: countFlag,\n json: jsonFlag,\n timestamp: objectidTimestampFlag,\n },\n Effect.fn('cli.generate.objectid')(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* generateObjectid({ count, timestamp })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate MongoDB ObjectIDs'),\n Command.withExamples([\n { command: 'uniku objectid -n 5 --json', description: 'Generate 5 ObjectIDs as a JSON array' },\n {\n command: 'uniku objectid --timestamp 1720000000',\n description: 'Generate an ObjectID for a fixed Unix timestamp (s)',\n },\n ]),\n)\n\n// ── TSID subcommand ─────────────────────────────────────────────────\n\nconst tsidTimestampFlag = Flag.string('timestamp').pipe(\n Flag.withDescription('Unix timestamp in milliseconds (or \"now\")'),\n Flag.optional,\n)\n\n// KTD9: no existing precedent in this file pairs `Flag.integer` with\n// `Flag.optional` (every `Flag.integer` pairs with `Flag.withDefault`) - so\n// `--node`/`--node-bits` follow the verified `Flag.string` + inline-parse\n// idiom used for every timestamp flag instead of risking an unverified\n// combinator on the pinned Effect v4 beta.\nconst tsidNodeFlag = Flag.string('node').pipe(Flag.withDescription('Node ID (0 to 2^node-bits - 1)'), Flag.optional)\n\nconst tsidNodeBitsFlag = Flag.string('node-bits').pipe(\n Flag.withDescription('Number of bits allocated to the node ID (0-20, default 10)'),\n Flag.optional,\n)\n\nconst tsidSubcommand = Command.make(\n 'tsid',\n {\n count: countFlag,\n json: jsonFlag,\n timestamp: tsidTimestampFlag,\n node: tsidNodeFlag,\n nodeBits: tsidNodeBitsFlag,\n },\n Effect.fn('cli.generate.tsid')(function* ({\n count,\n json,\n timestamp: timestampOpt,\n node: nodeOpt,\n nodeBits: nodeBitsOpt,\n }) {\n const output = yield* OutputService\n const timestampInput = Option.getOrUndefined(timestampOpt)\n const timestamp = timestampInput !== undefined ? yield* parseTimestampMs(timestampInput) : undefined\n const nodeInput = Option.getOrUndefined(nodeOpt)\n const node = nodeInput !== undefined ? yield* parseNode(nodeInput) : undefined\n const nodeBitsInput = Option.getOrUndefined(nodeBitsOpt)\n const nodeBits = nodeBitsInput !== undefined ? yield* parseNodeBits(nodeBitsInput) : undefined\n const ids = yield* generateTsid({ count, timestamp, node, nodeBits })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate TSIDs (64-bit Snowflake-style, time-sorted)'),\n Command.withExamples([\n { command: 'uniku tsid -n 5 --json', description: 'Generate 5 TSIDs as a JSON array' },\n {\n command: 'uniku tsid --timestamp 1720000000000',\n description: 'Generate a TSID for a fixed Unix timestamp (ms)',\n },\n { command: 'uniku tsid --node 42 --node-bits 10', description: 'Generate a TSID for a fixed node ID' },\n ]),\n)\n\n// ── Generate parent command ─────────────────────────────────────────\n\nexport const generateCommand = Command.make('generate').pipe(\n Command.withDescription('Generate new IDs'),\n Command.withSubcommands([\n uuidSubcommand,\n ulidSubcommand,\n typeidSubcommand,\n nanoidSubcommand,\n cuidSubcommand,\n ksuidSubcommand,\n objectidSubcommand,\n tsidSubcommand,\n ]),\n Command.withExamples([\n { command: 'uniku generate uuid -n 5 --json', description: 'Generate 5 UUIDs as a JSON array' },\n { command: 'uniku generate typeid --prefix user', description: 'Generate one user TypeID' },\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 typeidShorthand = typeidSubcommand\nexport const nanoidShorthand = nanoidSubcommand\nexport const cuidShorthand = cuidSubcommand\nexport const ksuidShorthand = ksuidSubcommand\nexport const objectidShorthand = objectidSubcommand\nexport const tsidShorthand = tsidSubcommand\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\nconst parseNonNegativeInt = Effect.fn('cli.generate.parseNonNegativeInt')(function* (\n input: string,\n code: string,\n label: string,\n hint: string,\n) {\n const n = Number(input)\n if (!Number.isInteger(n) || n < 0) {\n return yield* new CliError({ code, message: `Invalid ${label}: \"${input}\"`, hint })\n }\n return n\n})\n\nconst parseNode = (input: string): Effect.Effect<number, CliError> =>\n parseNonNegativeInt(input, 'INVALID_NODE', 'node', 'Provide a non-negative integer for --node')\n\nconst parseNodeBits = (input: string): Effect.Effect<number, CliError> =>\n parseNonNegativeInt(input, 'INVALID_NODE_BITS', 'node-bits', 'Provide a non-negative integer (0-20) for --node-bits')\n","import { cuidv2 } from 'uniku/cuid/v2'\nimport { ksuid } from 'uniku/ksuid'\nimport { nanoid } from 'uniku/nanoid'\nimport { objectid } from 'uniku/objectid'\nimport { tsid } from 'uniku/tsid'\nimport { typeid } from 'uniku/typeid'\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 'typeid':\n return validateTypeid(id)\n case 'ksuid':\n return validateKsuid(id)\n case 'objectid':\n return validateObjectid(id)\n case 'cuid':\n return validateCuid(id)\n case 'nanoid':\n return validateNanoid(id)\n case 'tsid':\n return validateTsid(id)\n }\n}\n\n/**\n * Auto-detect ID type and validate.\n * Detection order: UUID > TypeID > ULID > KSUID > ObjectID > TSID > CUID > Nanoid.\n *\n * ObjectID must be checked before CUID: CUID2's default validation regex\n * (`/^[a-z][0-9a-z]+$/`, default length 24) accepts any 24-character string\n * over 0-9a-z that starts with a letter. ObjectID's alphabet (0-9a-f) is a\n * strict subset of that at the same default length, so any ObjectID whose\n * first hex digit is a-f (~37.5% of generated IDs) would also satisfy\n * cuidv2.isValid() if checked first.\n *\n * TSID must also be checked before CUID2 (and before Nanoid's catch-all),\n * for the same reason: CUID2's `isValid` only checks length in [2, 32] with\n * no other length or alphabet constraint, so a 13-char TSID string whose\n * leading digit happens to be a lowercase hex letter (a-f) would otherwise\n * also match `/^[a-z][0-9a-z]+$/`. Restricting TSID's leading character to\n * 0-9A-F does *not* by itself rule out this collision (CUID2's regex has no\n * length ceiling) - only checking TSID first actually prevents it. Nanoid's\n * fallback check (last, catch-all, no length constraint) must also come\n * after TSID's check for the same reason.\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. TypeID (optional prefix + UUID v7 base32 suffix)\n if (typeid.isValid(id)) {\n return { id, valid: true, type: 'typeid', version: 7 }\n }\n\n // 3. ULID (26 chars, Crockford Base32)\n if (ulid.isValid(id)) {\n return { id, valid: true, type: 'ulid' }\n }\n\n // 4. KSUID (27 chars, Base62)\n if (ksuid.isValid(id)) {\n return { id, valid: true, type: 'ksuid' }\n }\n\n // 5. ObjectID (24 chars, hex) - must precede CUID2, see doc comment above\n if (objectid.isValid(id)) {\n return { id, valid: true, type: 'objectid' }\n }\n\n // 6. TSID (13 chars, Crockford Base32) - must precede CUID2/Nanoid, see doc comment above\n if (validateTsid(id).valid) {\n return { id, valid: true, type: 'tsid' }\n }\n\n // 7. CUID (starts with letter, Base36)\n if (cuidv2.isValid(id)) {\n return { id, valid: true, type: 'cuid' }\n }\n\n // 8. 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 validateTypeid(id: string): ValidationResult {\n if (typeid.isValid(id)) {\n return { id, valid: true, type: 'typeid', version: 7 }\n }\n return { id, valid: false, type: 'typeid', error: 'invalid TypeID 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 validateObjectid(id: string): ValidationResult {\n if (objectid.isValid(id)) {\n return { id, valid: true, type: 'objectid' }\n }\n return { id, valid: false, type: 'objectid', error: 'invalid ObjectID format' }\n}\n\nfunction validateCuid(id: string): ValidationResult {\n if (cuidv2.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\nfunction validateTsid(id: string): ValidationResult {\n // Unlike every other generator's `type.isValid(idString)`, `tsid.isValid`\n // operates on the bigint primary type (a bounds check), not a string\n // format check, so it cannot validate a string input directly. Instead,\n // attempt to parse the canonical string form and treat a thrown\n // `ParseError` (wrong length, invalid character, or leading character\n // outside the valid 0-9A-F range) as invalidity.\n try {\n tsid.fromString(id)\n return { id, valid: true, type: 'tsid' }\n } catch {\n return { id, valid: false, type: 'tsid', error: 'invalid TSID format' }\n }\n}\n","import { ksuid } from 'uniku/ksuid'\nimport { objectid } from 'uniku/objectid'\nimport { tsid } from 'uniku/tsid'\nimport { typeid } from 'uniku/typeid'\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 'typeid':\n return inspectTypeid(id)\n case 'ksuid':\n return inspectKsuid(id)\n case 'objectid':\n return inspectObjectid(id)\n case 'cuid':\n return inspectCuid(id)\n case 'nanoid':\n return inspectNanoid(id)\n case 'tsid':\n return inspectTsid(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 inspectTypeid(id: string): InspectResult {\n if (!typeid.isValid(id)) {\n return {\n id,\n type: 'typeid',\n note: 'Unrecognized TypeID format.',\n }\n }\n\n const ms = typeid.timestamp(id)\n const bytes = typeid.toBytes(id)\n // UUID v7 random component: last 6 bytes (bytes 10-15)\n const random = Buffer.from(bytes.slice(10)).toString('hex')\n return {\n id,\n type: 'typeid',\n version: 7,\n prefix: typeid.prefix(id),\n suffix: typeid.suffix(id),\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 inspectObjectid(id: string): InspectResult {\n const ms = objectid.timestamp(id)\n const bytes = objectid.toBytes(id)\n // Random + counter tail: last 8 bytes (bytes 4-11)\n const random = Buffer.from(bytes.slice(4)).toString('hex')\n return {\n id,\n type: 'objectid',\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\nfunction inspectTsid(id: string): InspectResult {\n let value: bigint\n try {\n value = tsid.fromString(id)\n } catch {\n return {\n id,\n type: 'tsid',\n note: 'Unrecognized TSID format.',\n }\n }\n\n const ms = tsid.timestamp(value)\n // Combined node + counter tail: low 22 bits of the packed bigint. The\n // node/counter split isn't self-describing without knowing the nodeBits\n // used at generation time (see KTD6), so the combined tail is exposed\n // as-is rather than decomposed - matching objectid's inspector for its\n // own `random` field.\n const random = (value & 0x3fffffn).toString(16)\n return {\n id,\n type: 'tsid',\n timestamp: new Date(ms).toISOString(),\n timestamp_ms: ms,\n random,\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 { ID_GENERATORS, 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', ID_GENERATORS).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 { ID_GENERATORS, type IdType, type 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', ID_GENERATORS).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 objectidShorthand,\n tsidShorthand,\n typeidShorthand,\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 typeid --prefix user', description: 'Generate one user TypeID' },\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 typeidShorthand,\n nanoidShorthand,\n cuidShorthand,\n ksuidShorthand,\n objectidShorthand,\n tsidShorthand,\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.4.0",
4
+ "version": "0.5.0",
5
5
  "description": "CLI tool for generating and validating unique identifiers",
6
6
  "author": {
7
7
  "name": "Alberto Schiabel",
@@ -30,14 +30,14 @@
30
30
  "README.md"
31
31
  ],
32
32
  "dependencies": {
33
- "effect": "4.0.0-beta.93",
34
33
  "@effect/platform-bun": "4.0.0-beta.93",
35
- "uniku": "0.2.0"
34
+ "effect": "4.0.0-beta.93",
35
+ "uniku": "0.3.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@types/bun": "^1.3.8",
39
38
  "@effect/vitest": "4.0.0-beta.93",
40
- "vitest": "^4.1.9"
39
+ "@types/bun": "^1.3.14",
40
+ "vitest": "^4.1.10"
41
41
  },
42
42
  "scripts": {
43
43
  "clean": "rimraf build .turbo",
package/build/bin.d.mts DELETED
@@ -1 +0,0 @@
1
- export { };