smart-passphrase 1.0.2 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,44 +1,52 @@
1
+ Human-readable, secure password generator for developers and CLI usage.
1
2
  # smart-passphrase
2
3
 
3
4
  A lightweight, secure, and memorable passphrase generator for Node.js and modern browsers. Built to work smoothly in React, Next.js, Vite, and plain Node projects.
4
5
 
5
6
  ## Features
6
- - Human‑readable passphrases with strong randomness
7
- - Cryptographically secure randomness (via `crypto.getRandomValues`)
8
- - Works in React, Next.js, Vite, and Node 18+
9
- - Fully typed TypeScript API
10
- - Configurable casing, symbols, numbers, and word patterns
11
- - Custom dictionary support
7
+ - **Memorable**: Human‑readable passphrases that are easy to type and remember.
8
+ - **Secure**: Uses cryptographically secure randomness (via `crypto.getRandomValues`).
9
+ - **Versatile**: Works in React, Next.js, Vite, and Node 18+.
10
+ - **Premium CLI**: Beautifully styled terminal output with colors and animations.
11
+ - **Clipboard Support**: Copy passphrases instantly from the CLI.
12
+ - **Zero Dependencies (Core)**: Only adds dependencies for the CLI tool.
13
+ - **Fully Typed**: Written in TypeScript with a complete API.
12
14
 
13
15
  ## Install
14
16
  ```bash
15
17
  npm install smart-passphrase
16
18
  ```
17
19
 
18
- ## Quick Start
19
- ```ts
20
- import { generatePassphrase } from "smart-passphrase";
21
-
22
- const passphrase = generatePassphrase();
23
- console.log(passphrase);
20
+ ## Quick Start (Terminal)
21
+ Generate a passphrase instantly with a premium experience:
22
+ ```bash
23
+ npx smart-passphrase
24
24
  ```
25
25
 
26
- ## Example Output
26
+ **Pro Tip (Copy to clipboard):**
27
+ ```bash
28
+ npx smart-passphrase copy
29
+ # or
30
+ npx smart-passphrase -c
27
31
  ```
28
- SilentGOOSE^mark324
29
- BrAveTiger#run891
30
- quickROCKET=jump472
32
+
33
+ **Custom Strength:**
34
+ ```bash
35
+ npx smart-passphrase --strength ultra
31
36
  ```
32
37
 
33
- ## Usage in React / Next.js / Vite
34
- ```tsx
38
+ ## Quick Start (Code)
39
+ ```ts
35
40
  import { generatePassphrase } from "smart-passphrase";
36
41
 
37
- export default function App() {
38
- return <h2>{generatePassphrase()}</h2>;
39
- }
42
+ const passphrase = generatePassphrase();
43
+ console.log(passphrase);
44
+ // Output: SilentGOOSE^mark324
40
45
  ```
41
46
 
47
+ ## Example Output
48
+ The CLI provides a vibrant, gradient-colored output that stands out!
49
+
42
50
  ## API
43
51
 
44
52
  ### `generatePassphrase(options?)`
@@ -71,102 +79,48 @@ const bits = entropyEstimate({ words: 4, symbols: true, numbers: true });
71
79
  ## Options
72
80
 
73
81
  ### `words`
74
- Number of word tokens in the passphrase.
75
-
76
- ```ts
77
- generatePassphrase({ words: 4 });
78
- ```
82
+ Number of word tokens in the passphrase. Default is `3`.
79
83
 
80
84
  ### `numbers`
81
- - `true` (default) to add digits
82
- - `{ digits: number }` to control length
83
-
84
- ```ts
85
- generatePassphrase({ numbers: { digits: 4 } });
86
- ```
85
+ - `true` (default): Adds digits.
86
+ - `{ digits: number }`: Controls the number of digits.
87
+ - `false`: Removes digits.
87
88
 
88
89
  ### `symbols`
89
- - `true` (default) to include symbols
90
- - `string[]` to provide your own symbol list
91
-
92
- ```ts
93
- generatePassphrase({ symbols: ["$", "-", "_"] });
94
- ```
90
+ - `true` (default): Includes one random symbol.
91
+ - `string[]`: Provide your own symbol list to pick from.
92
+ - `false`: Removes symbols.
95
93
 
96
94
  ### `uppercaseStyle`
97
- Controls casing:
98
-
99
- ```ts
100
- "none" | "random" | "title" | "upper" | "lower"
101
- ```
102
-
103
- Example:
104
- ```ts
105
- generatePassphrase({ uppercaseStyle: "title" });
106
- ```
107
-
108
- ### `separator`
109
- String inserted between all parts.
110
-
111
- ```ts
112
- generatePassphrase({ separator: "-" });
113
- ```
114
-
115
- ### `unique`
116
- Avoid repeating words within the same passphrase.
117
-
118
- ```ts
119
- generatePassphrase({ unique: true });
120
- ```
95
+ Controls casing style for the words:
96
+ `"none" | "random" | "title" | "upper" | "lower"`
121
97
 
122
98
  ### `strength`
123
- Preset security tiers:
124
-
125
- ```ts
126
- "medium" | "strong" | "ultra"
127
- ```
128
-
129
- Each tier increases words, digits, and entropy.
99
+ Preset security tiers that adjust words, symbols, and digits.
130
100
 
131
- ```ts
132
- generatePassphrase({ strength: "ultra" });
133
- ```
101
+ | Tier | Words | Symbols | Digits | Approx. Entropy |
102
+ | :--- | :--- | :--- | :--- | :--- |
103
+ | `medium` | 3 | Yes | 3 | ~45-50 bits |
104
+ | `strong` | 4 | Yes | 4 | ~60-70 bits |
105
+ | `ultra` | 5 | Yes | 5 | ~80+ bits |
134
106
 
135
- ### `pattern`
136
- Custom order of word types.
137
-
138
- ```ts
139
- generatePassphrase({ pattern: ["adj", "noun", "verb"] });
140
- ```
141
-
142
- Available word kinds:
143
- ```ts
144
- "adj" | "noun" | "verb"
145
- ```
107
+ ## CLI Reference
108
+ Run `npx smart-passphrase [command] [options]` or install globally.
146
109
 
147
- ### `dictionary`
148
- Override the default word lists.
110
+ ### Commands
111
+ - `[default]` - Generate a passphrase.
112
+ - `copy` - Generate and copy to clipboard immediately.
149
113
 
150
- ```ts
151
- generatePassphrase({
152
- dictionary: {
153
- adjectives: ["silent", "rapid"],
154
- nouns: ["fox", "river"],
155
- verbs: ["glide", "spark"]
156
- }
157
- });
158
- ```
114
+ ### Options
115
+ - `-w, --words <n>` - Set the number of words (default: 3).
116
+ - `-s, --strength <tier>` - Set tier (medium, strong, ultra).
117
+ - `-c, --copy` - Copy generated passphrase to clipboard.
118
+ - `-n, --no-numbers` - Disable numbers.
119
+ - `-S, --no-symbols` - Disable symbols.
159
120
 
160
121
  ## Security Notes
161
122
  - Uses `crypto.getRandomValues` for strong randomness.
162
123
  - Requires Node 18+ or a modern browser runtime.
163
- - For even higher entropy, increase `words`, `digits`, or use `strength: "ultra"`.
164
124
 
165
125
  ## License
166
- MIT
167
- ```
168
-
169
- If you want, I can also add:
170
- 1. A `COPY` helper utility example
171
- 2. A CLI usage snippet
172
- 3. A comparison table for `strength` presets
126
+ MIT
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const ora_1 = __importDefault(require("ora"));
10
+ const clipboardy_1 = __importDefault(require("clipboardy"));
11
+ const gradient_string_1 = __importDefault(require("gradient-string"));
12
+ const generator_js_1 = require("./generator.js");
13
+ const program = new commander_1.Command();
14
+ program
15
+ .name("smart-passphrase")
16
+ .description("Generate secure and memorable passphrases with style")
17
+ .version("2.0.0")
18
+ .option("-w, --words <number>", "number of words", (val) => parseInt(val), 3)
19
+ .option("-s, --strength <tier>", "security tier (medium, strong, ultra)", "medium")
20
+ .option("-n, --no-numbers", "do not include numbers")
21
+ .option("-S, --no-symbols", "do not include symbols")
22
+ .option("-c, --copy", "copy to clipboard")
23
+ .action(async (options) => {
24
+ console.log("");
25
+ const spinner = (0, ora_1.default)({
26
+ text: chalk_1.default.cyan("Locking the gears..."),
27
+ color: "cyan"
28
+ }).start();
29
+ // Small delay for "fancy" feel
30
+ await new Promise((resolve) => setTimeout(resolve, 600));
31
+ try {
32
+ const password = (0, generator_js_1.generatePassword)({
33
+ words: options.words,
34
+ strength: options.strength,
35
+ numbers: options.numbers,
36
+ symbols: options.symbols,
37
+ });
38
+ spinner.succeed(chalk_1.default.green("Secure passphrase ready!"));
39
+ console.log("");
40
+ const styledPassword = gradient_string_1.default.pastel.multiline(password);
41
+ console.log(" " + chalk_1.default.bold(styledPassword));
42
+ console.log("");
43
+ if (options.copy) {
44
+ clipboardy_1.default.writeSync(password);
45
+ console.log(chalk_1.default.dim(" 📋 Copied to clipboard!"));
46
+ console.log("");
47
+ }
48
+ }
49
+ catch (error) {
50
+ spinner.fail(chalk_1.default.red("Generation failed"));
51
+ console.error(chalk_1.default.red(` Error: ${error.message}`));
52
+ process.exit(1);
53
+ }
54
+ });
55
+ // Handle the "copy" as a shorthand command too
56
+ program
57
+ .command("copy")
58
+ .description("Generate and copy to clipboard immediately")
59
+ .action(async () => {
60
+ const spinner = (0, ora_1.default)(chalk_1.default.cyan("Generating and copying...")).start();
61
+ await new Promise((resolve) => setTimeout(resolve, 400));
62
+ const password = (0, generator_js_1.generatePassword)();
63
+ clipboardy_1.default.writeSync(password);
64
+ spinner.succeed(chalk_1.default.green("Generated and copied to clipboard!"));
65
+ console.log("");
66
+ console.log(" " + gradient_string_1.default.pastel(password));
67
+ console.log("");
68
+ });
69
+ program.parse();
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generatePassphrase = generatePassphrase;
4
4
  exports.generatePassword = generatePassword;
5
5
  exports.entropyEstimate = entropyEstimate;
6
- const wordlist_1 = require("./wordlist");
7
- const utils_1 = require("./utils");
6
+ const wordlist_js_1 = require("./wordlist.js");
7
+ const utils_js_1 = require("./utils.js");
8
8
  const strengthDefaults = {
9
9
  medium: { words: 3, symbols: true, digits: 3 },
10
10
  strong: { words: 4, symbols: true, digits: 4 },
@@ -12,9 +12,9 @@ const strengthDefaults = {
12
12
  };
13
13
  function buildDictionary(overrides) {
14
14
  return {
15
- adjectives: overrides?.adjectives ?? wordlist_1.adjectives,
16
- nouns: overrides?.nouns ?? wordlist_1.nouns,
17
- verbs: overrides?.verbs ?? wordlist_1.verbs
15
+ adjectives: overrides?.adjectives ?? wordlist_js_1.adjectives,
16
+ nouns: overrides?.nouns ?? wordlist_js_1.nouns,
17
+ verbs: overrides?.verbs ?? wordlist_js_1.verbs
18
18
  };
19
19
  }
20
20
  function chooseWords(dictionary, kinds, unique) {
@@ -25,11 +25,11 @@ function chooseWords(dictionary, kinds, unique) {
25
25
  if (list.length === 0) {
26
26
  throw new Error(`Dictionary list for ${kind} is empty`);
27
27
  }
28
- let picked = (0, utils_1.randomItem)(list);
28
+ let picked = (0, utils_js_1.randomItem)(list);
29
29
  if (unique) {
30
30
  let attempts = 0;
31
31
  while (used.has(picked) && attempts < 25) {
32
- picked = (0, utils_1.randomItem)(list);
32
+ picked = (0, utils_js_1.randomItem)(list);
33
33
  attempts += 1;
34
34
  }
35
35
  }
@@ -60,17 +60,17 @@ function generatePassphrase(options = {}) {
60
60
  if (pattern.length !== wordCount) {
61
61
  throw new Error("pattern length must match words");
62
62
  }
63
- const words = chooseWords(dictionary, pattern, unique).map((word) => (0, utils_1.applyCase)(word, uppercaseStyle));
63
+ const words = chooseWords(dictionary, pattern, unique).map((word) => (0, utils_js_1.applyCase)(word, uppercaseStyle));
64
64
  const parts = [];
65
65
  for (const word of words) {
66
66
  parts.push(word);
67
67
  }
68
68
  if (useSymbols) {
69
- const symbols = Array.isArray(useSymbols) ? useSymbols : utils_1.defaultSymbols;
70
- parts.push((0, utils_1.randomItem)(symbols));
69
+ const symbols = Array.isArray(useSymbols) ? useSymbols : utils_js_1.defaultSymbols;
70
+ parts.push((0, utils_js_1.randomItem)(symbols));
71
71
  }
72
72
  if (numbersOption) {
73
- parts.push(String((0, utils_1.randomNumberByDigits)(digits)));
73
+ parts.push(String((0, utils_js_1.randomNumberByDigits)(digits)));
74
74
  }
75
75
  if (separator) {
76
76
  return parts.join(separator);
@@ -93,7 +93,7 @@ function entropyEstimate(options = {}) {
93
93
  return list.length || 1;
94
94
  });
95
95
  const wordSpace = sizes.reduce((acc, size) => acc * size, 1);
96
- const symbolSpace = useSymbols ? (Array.isArray(useSymbols) ? useSymbols.length : utils_1.defaultSymbols.length) : 1;
96
+ const symbolSpace = useSymbols ? (Array.isArray(useSymbols) ? useSymbols.length : utils_js_1.defaultSymbols.length) : 1;
97
97
  const numberSpace = numbersOption ? Math.pow(10, digits) : 1;
98
98
  const total = wordSpace * symbolSpace * numberSpace;
99
99
  return Math.log2(total);
package/dist/cjs/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.entropyEstimate = exports.generatePassword = exports.generatePassphrase = void 0;
4
- var generator_1 = require("./generator");
5
- Object.defineProperty(exports, "generatePassphrase", { enumerable: true, get: function () { return generator_1.generatePassphrase; } });
6
- Object.defineProperty(exports, "generatePassword", { enumerable: true, get: function () { return generator_1.generatePassword; } });
7
- Object.defineProperty(exports, "entropyEstimate", { enumerable: true, get: function () { return generator_1.entropyEstimate; } });
4
+ var generator_js_1 = require("./generator.js");
5
+ Object.defineProperty(exports, "generatePassphrase", { enumerable: true, get: function () { return generator_js_1.generatePassphrase; } });
6
+ Object.defineProperty(exports, "generatePassword", { enumerable: true, get: function () { return generator_js_1.generatePassword; } });
7
+ Object.defineProperty(exports, "entropyEstimate", { enumerable: true, get: function () { return generator_js_1.entropyEstimate; } });
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import chalk from "chalk";
4
+ import ora from "ora";
5
+ import clipboardy from "clipboardy";
6
+ import gradient from "gradient-string";
7
+ import { generatePassword } from "./generator.js";
8
+ const program = new Command();
9
+ program
10
+ .name("smart-passphrase")
11
+ .description("Generate secure and memorable passphrases with style")
12
+ .version("2.0.0")
13
+ .option("-w, --words <number>", "number of words", (val) => parseInt(val), 3)
14
+ .option("-s, --strength <tier>", "security tier (medium, strong, ultra)", "medium")
15
+ .option("-n, --no-numbers", "do not include numbers")
16
+ .option("-S, --no-symbols", "do not include symbols")
17
+ .option("-c, --copy", "copy to clipboard")
18
+ .action(async (options) => {
19
+ console.log("");
20
+ const spinner = ora({
21
+ text: chalk.cyan("Locking the gears..."),
22
+ color: "cyan"
23
+ }).start();
24
+ // Small delay for "fancy" feel
25
+ await new Promise((resolve) => setTimeout(resolve, 600));
26
+ try {
27
+ const password = generatePassword({
28
+ words: options.words,
29
+ strength: options.strength,
30
+ numbers: options.numbers,
31
+ symbols: options.symbols,
32
+ });
33
+ spinner.succeed(chalk.green("Secure passphrase ready!"));
34
+ console.log("");
35
+ const styledPassword = gradient.pastel.multiline(password);
36
+ console.log(" " + chalk.bold(styledPassword));
37
+ console.log("");
38
+ if (options.copy) {
39
+ clipboardy.writeSync(password);
40
+ console.log(chalk.dim(" 📋 Copied to clipboard!"));
41
+ console.log("");
42
+ }
43
+ }
44
+ catch (error) {
45
+ spinner.fail(chalk.red("Generation failed"));
46
+ console.error(chalk.red(` Error: ${error.message}`));
47
+ process.exit(1);
48
+ }
49
+ });
50
+ // Handle the "copy" as a shorthand command too
51
+ program
52
+ .command("copy")
53
+ .description("Generate and copy to clipboard immediately")
54
+ .action(async () => {
55
+ const spinner = ora(chalk.cyan("Generating and copying...")).start();
56
+ await new Promise((resolve) => setTimeout(resolve, 400));
57
+ const password = generatePassword();
58
+ clipboardy.writeSync(password);
59
+ spinner.succeed(chalk.green("Generated and copied to clipboard!"));
60
+ console.log("");
61
+ console.log(" " + gradient.pastel(password));
62
+ console.log("");
63
+ });
64
+ program.parse();
@@ -1,4 +1,4 @@
1
- import type { GenerateOptions } from "./types";
1
+ import type { GenerateOptions } from "./types.js";
2
2
  export declare function generatePassphrase(options?: GenerateOptions): string;
3
3
  export declare function generatePassword(options?: GenerateOptions): string;
4
4
  export declare function entropyEstimate(options?: GenerateOptions): number;
@@ -0,0 +1,95 @@
1
+ import { adjectives, nouns, verbs } from "./wordlist.js";
2
+ import { applyCase, defaultSymbols, randomItem, randomNumberByDigits } from "./utils.js";
3
+ const strengthDefaults = {
4
+ medium: { words: 3, symbols: true, digits: 3 },
5
+ strong: { words: 4, symbols: true, digits: 4 },
6
+ ultra: { words: 5, symbols: true, digits: 5 }
7
+ };
8
+ function buildDictionary(overrides) {
9
+ return {
10
+ adjectives: overrides?.adjectives ?? adjectives,
11
+ nouns: overrides?.nouns ?? nouns,
12
+ verbs: overrides?.verbs ?? verbs
13
+ };
14
+ }
15
+ function chooseWords(dictionary, kinds, unique) {
16
+ const used = new Set();
17
+ const output = [];
18
+ for (const kind of kinds) {
19
+ const list = kind === "adj" ? dictionary.adjectives : kind === "noun" ? dictionary.nouns : dictionary.verbs;
20
+ if (list.length === 0) {
21
+ throw new Error(`Dictionary list for ${kind} is empty`);
22
+ }
23
+ let picked = randomItem(list);
24
+ if (unique) {
25
+ let attempts = 0;
26
+ while (used.has(picked) && attempts < 25) {
27
+ picked = randomItem(list);
28
+ attempts += 1;
29
+ }
30
+ }
31
+ used.add(picked);
32
+ output.push(picked);
33
+ }
34
+ return output;
35
+ }
36
+ function defaultPattern(words) {
37
+ const pool = ["adj", "noun", "verb"];
38
+ const output = [];
39
+ for (let i = 0; i < words; i += 1) {
40
+ output.push(pool[i % pool.length]);
41
+ }
42
+ return output;
43
+ }
44
+ export function generatePassphrase(options = {}) {
45
+ const defaults = options.strength ? strengthDefaults[options.strength] : strengthDefaults.medium;
46
+ const wordCount = options.words ?? defaults.words;
47
+ const useSymbols = options.symbols ?? defaults.symbols;
48
+ const numbersOption = options.numbers ?? true;
49
+ const digits = typeof numbersOption === "object" ? numbersOption.digits ?? defaults.digits : defaults.digits;
50
+ const separator = options.separator ?? "";
51
+ const uppercaseStyle = options.uppercaseStyle ?? "random";
52
+ const unique = options.unique ?? true;
53
+ const dictionary = buildDictionary(options.dictionary);
54
+ const pattern = options.pattern ?? defaultPattern(wordCount);
55
+ if (pattern.length !== wordCount) {
56
+ throw new Error("pattern length must match words");
57
+ }
58
+ const words = chooseWords(dictionary, pattern, unique).map((word) => applyCase(word, uppercaseStyle));
59
+ const parts = [];
60
+ for (const word of words) {
61
+ parts.push(word);
62
+ }
63
+ if (useSymbols) {
64
+ const symbols = Array.isArray(useSymbols) ? useSymbols : defaultSymbols;
65
+ parts.push(randomItem(symbols));
66
+ }
67
+ if (numbersOption) {
68
+ parts.push(String(randomNumberByDigits(digits)));
69
+ }
70
+ if (separator) {
71
+ return parts.join(separator);
72
+ }
73
+ return parts.join("");
74
+ }
75
+ export function generatePassword(options = {}) {
76
+ return generatePassphrase(options);
77
+ }
78
+ export function entropyEstimate(options = {}) {
79
+ const defaults = options.strength ? strengthDefaults[options.strength] : strengthDefaults.medium;
80
+ const wordCount = options.words ?? defaults.words;
81
+ const useSymbols = options.symbols ?? defaults.symbols;
82
+ const numbersOption = options.numbers ?? true;
83
+ const digits = typeof numbersOption === "object" ? numbersOption.digits ?? defaults.digits : defaults.digits;
84
+ const dictionary = buildDictionary(options.dictionary);
85
+ const pattern = options.pattern ?? defaultPattern(wordCount);
86
+ const sizes = pattern.map((kind) => {
87
+ const list = kind === "adj" ? dictionary.adjectives : kind === "noun" ? dictionary.nouns : dictionary.verbs;
88
+ return list.length || 1;
89
+ });
90
+ const wordSpace = sizes.reduce((acc, size) => acc * size, 1);
91
+ const symbolSpace = useSymbols ? (Array.isArray(useSymbols) ? useSymbols.length : defaultSymbols.length) : 1;
92
+ const numberSpace = numbersOption ? Math.pow(10, digits) : 1;
93
+ const total = wordSpace * symbolSpace * numberSpace;
94
+ return Math.log2(total);
95
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { generatePassphrase, generatePassword, entropyEstimate } from "./generator";
2
- export type { GenerateOptions, Dictionary, UppercaseStyle, Strength, WordKind } from "./types";
1
+ export { generatePassphrase, generatePassword, entropyEstimate } from "./generator.js";
2
+ export type { GenerateOptions, Dictionary, UppercaseStyle, Strength, WordKind } from "./types.js";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { generatePassphrase, generatePassword, entropyEstimate } from "./generator.js";
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/utils.js ADDED
@@ -0,0 +1,51 @@
1
+ export const defaultSymbols = ["@", "#", "^", "=", ")", "!", "*", "%"];
2
+ export function secureRandomInt(maxExclusive) {
3
+ if (!Number.isInteger(maxExclusive) || maxExclusive <= 0) {
4
+ throw new Error("maxExclusive must be a positive integer");
5
+ }
6
+ const cryptoObj = globalThis.crypto;
7
+ if (!cryptoObj || typeof cryptoObj.getRandomValues !== "function") {
8
+ throw new Error("Secure crypto is not available in this environment");
9
+ }
10
+ const range = 0x100000000;
11
+ const limit = range - (range % maxExclusive);
12
+ const buf = new Uint32Array(1);
13
+ let value = 0;
14
+ do {
15
+ cryptoObj.getRandomValues(buf);
16
+ value = buf[0];
17
+ } while (value >= limit);
18
+ return value % maxExclusive;
19
+ }
20
+ export function randomItem(items) {
21
+ if (items.length === 0) {
22
+ throw new Error("Cannot choose from an empty list");
23
+ }
24
+ return items[secureRandomInt(items.length)];
25
+ }
26
+ export function randomBool() {
27
+ return secureRandomInt(2) === 1;
28
+ }
29
+ export function applyCase(word, style) {
30
+ if (style === "none")
31
+ return word;
32
+ if (style === "upper")
33
+ return word.toUpperCase();
34
+ if (style === "lower")
35
+ return word.toLowerCase();
36
+ if (style === "title")
37
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
38
+ return word
39
+ .split("")
40
+ .map((ch) => (randomBool() ? ch.toUpperCase() : ch.toLowerCase()))
41
+ .join("");
42
+ }
43
+ export function randomNumberByDigits(digits) {
44
+ if (!Number.isInteger(digits) || digits <= 0) {
45
+ throw new Error("digits must be a positive integer");
46
+ }
47
+ const min = Math.pow(10, digits - 1);
48
+ const max = Math.pow(10, digits) - 1;
49
+ const span = max - min + 1;
50
+ return min + secureRandomInt(span);
51
+ }
@@ -0,0 +1,110 @@
1
+ export const adjectives = [
2
+ // Original
3
+ "quick", "silent", "brave", "fancy", "eager", "bright",
4
+ "gentle", "proud", "curious", "steady", "bold", "calm",
5
+ // Advanced originals
6
+ "resilient", "ephemeral", "luminous", "tenacious", "serene",
7
+ "voracious", "ethereal", "stoic", "audacious", "fleeting",
8
+ "mellifluous", "incisive", "unyielding", "sublime", "transient",
9
+ "ferocious", "cunning", "reclusive", "radiant", "somber",
10
+ "deft", "keen", "vigilant", "nimble", "profound",
11
+ // New: memorial + solemn / meaningful tone
12
+ "memorial",
13
+ "immortal",
14
+ "reverent",
15
+ "hallowed",
16
+ "eternal",
17
+ "venerable",
18
+ "sacred",
19
+ "mournful",
20
+ "remnant",
21
+ "honored",
22
+ "legendary",
23
+ "fabled",
24
+ "timeless",
25
+ "perpetual",
26
+ "solemn",
27
+ "devoted",
28
+ "faithful",
29
+ "righteous",
30
+ "valiant",
31
+ "gallant",
32
+ "exalted",
33
+ "revered",
34
+ "venerated",
35
+ "undying",
36
+ "everlasting"
37
+ ];
38
+ export const nouns = [
39
+ // Original
40
+ "tiger", "goose", "rocket", "mask", "forest", "ocean",
41
+ "ember", "comet", "cipher", "garden", "river", "mountain",
42
+ // Advanced originals
43
+ "phantom", "echo", "horizon", "sentinel", "abyss", "beacon",
44
+ "shroud", "monolith", "specter", "harbinger", "labyrinth",
45
+ "oracle", "crucible", "vigil", "rift", "veil", "tempest",
46
+ "solstice", "requiem", "synapse", "nexus", "axiom", "enigma",
47
+ "relic", "citadel",
48
+ // New: memorial + meaningful / legacy words
49
+ "memorial",
50
+ "monument",
51
+ "epitaph",
52
+ "shrine",
53
+ "tomb",
54
+ "grave",
55
+ "remembrance",
56
+ "legacy",
57
+ "heritage",
58
+ "echo",
59
+ "keepsake",
60
+ "memento",
61
+ "relic",
62
+ "vestige",
63
+ "tribute",
64
+ "offering",
65
+ "vow",
66
+ "oath",
67
+ "covenant",
68
+ "pillar",
69
+ "obelisk",
70
+ "chapel",
71
+ "sanctum",
72
+ "archive",
73
+ "chronicle"
74
+ ];
75
+ export const verbs = [
76
+ // Original
77
+ "run", "jump", "build", "mark", "drift", "spark",
78
+ "forge", "glide", "shift", "trace", "craft", "sprint",
79
+ // Advanced originals
80
+ "lunge", "flicker", "shatter", "conceal", "summon", "evade",
81
+ "descend", "ascend", "sunder", "kindle", "lurk", "surge",
82
+ "fracture", "unravel", "coalesce", "sever", "ignite", "linger",
83
+ "plummet", "scatter", "converge", "diverge", "emanate", "sear", "wither",
84
+ // New: memorial / reverent / legacy actions
85
+ "honor",
86
+ "cherish",
87
+ "enshrine",
88
+ "lament",
89
+ "mourn",
90
+ "remember",
91
+ "immortalize",
92
+ "consecrate",
93
+ "dedicate",
94
+ "sanctify",
95
+ "preserve",
96
+ "bequeath",
97
+ "endure",
98
+ "inscribe",
99
+ "carve",
100
+ "engrave",
101
+ "invoke",
102
+ "recall",
103
+ "revere",
104
+ "venerate",
105
+ "exalt",
106
+ "glorify",
107
+ "commemorate",
108
+ "memorialize",
109
+ "pay homage"
110
+ ];
package/package.json CHANGED
@@ -1,16 +1,14 @@
1
1
  {
2
2
  "name": "smart-passphrase",
3
- "version": "1.0.2",
3
+ "version": "2.0.1",
4
4
  "description": "Memorable, secure passphrase generator for web and Node.",
5
5
  "license": "MIT",
6
6
  "author": "Ayush Solanki <ayushsolanki2901@gmail.com> (https://github.com/ayushsolanki29)",
7
7
  "type": "module",
8
-
9
8
  "repository": {
10
9
  "type": "git",
11
10
  "url": "https://github.com/ayushsolanki29/smart-passphrase"
12
11
  },
13
-
14
12
  "keywords": [
15
13
  "password",
16
14
  "passphrase",
@@ -18,29 +16,38 @@
18
16
  "security",
19
17
  "typescript"
20
18
  ],
21
-
19
+ "bin": {
20
+ "smart-passphrase": "./dist/cli.js"
21
+ },
22
22
  "exports": {
23
23
  ".": {
24
24
  "types": "./dist/index.d.ts",
25
- "import": "./dist/esm/index.js",
25
+ "import": "./dist/index.js",
26
26
  "require": "./dist/cjs/index.cjs"
27
27
  }
28
28
  },
29
-
30
29
  "main": "./dist/cjs/index.cjs",
31
- "module": "./dist/esm/index.js",
30
+ "module": "./dist/index.js",
32
31
  "types": "./dist/index.d.ts",
33
-
34
- "files": ["dist"],
32
+ "files": [
33
+ "dist"
34
+ ],
35
35
  "sideEffects": false,
36
-
37
36
  "scripts": {
38
37
  "build:esm": "tsc -p tsconfig.esm.json",
39
38
  "build:cjs": "tsc -p tsconfig.cjs.json",
40
39
  "build": "npm run build:esm && npm run build:cjs"
41
40
  },
42
-
43
41
  "devDependencies": {
42
+ "@types/gradient-string": "^1.1.6",
43
+ "@types/node": "^25.6.0",
44
44
  "typescript": "^5.5.4"
45
+ },
46
+ "dependencies": {
47
+ "chalk": "^5.6.2",
48
+ "clipboardy": "^5.3.1",
49
+ "commander": "^14.0.3",
50
+ "gradient-string": "^3.0.0",
51
+ "ora": "^9.3.0"
45
52
  }
46
- }
53
+ }