@molecule/api-password 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +170 -0
  2. package/package.json +9 -8
package/README.md ADDED
@@ -0,0 +1,170 @@
1
+ <!--
2
+ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
+ Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
+ Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
+ To change this document, edit the module-level JSDoc in src/index.ts.
6
+ Generated: 2026-08-04T01:48:50.513Z
7
+ -->
8
+
9
+ # @molecule/api-password
10
+
11
+ > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
12
+ > It is written to be read by coding agents as much as by people, and is generated from this
13
+ > package's source — edit `src/index.ts` JSDoc, not this file.
14
+
15
+ Password hashing interface for molecule.dev.
16
+
17
+ Defines the standard interface for password hashing providers.
18
+
19
+ ## Quick Start
20
+
21
+ ```ts
22
+ import { hash, compare } from '@molecule/api-password'
23
+
24
+ // Register: store ONLY the hash.
25
+ const passwordHash = await hash(req.body.password)
26
+ await createUser({ email, passwordHash })
27
+
28
+ // Log in: constant-time compare; never `user.passwordHash === x`.
29
+ const ok = await compare(req.body.password, user.passwordHash)
30
+ if (!ok) return res.status(401).json({ error: 'Invalid credentials.' }) // don't reveal which field
31
+ ```
32
+
33
+ ## Type
34
+
35
+ `core`
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ npm install @molecule/api-password @molecule/api-bond @molecule/api-i18n
41
+ ```
42
+
43
+ ## API
44
+
45
+ ### Interfaces
46
+
47
+ #### `PasswordProvider`
48
+
49
+ Password provider interface.
50
+
51
+ All password providers must implement this interface.
52
+
53
+ ```typescript
54
+ interface PasswordProvider {
55
+ /**
56
+ * Hashes a plain-text password.
57
+ *
58
+ * @param password - The plain-text password to hash
59
+ * @param saltRounds - Number of salt rounds (cost factor)
60
+ * @returns The hashed password string
61
+ */
62
+ hash(password: string, saltRounds?: number): Promise<string>
63
+
64
+ /**
65
+ * Compares a plain-text password against a hash.
66
+ *
67
+ * @param password - The plain-text password to check
68
+ * @param passwordHash - The hash to compare against
69
+ * @returns true if the password matches the hash
70
+ */
71
+ compare(password: string, passwordHash: string): Promise<boolean>
72
+ }
73
+ ```
74
+
75
+ ### Functions
76
+
77
+ #### `compare(password, passwordHash)`
78
+
79
+ Compares a plain-text password against a stored hash using the bonded provider.
80
+
81
+ ```typescript
82
+ function compare(password: string, passwordHash: string): Promise<boolean>
83
+ ```
84
+
85
+ - `password` — The plain-text password to check.
86
+ - `passwordHash` — The stored hash to compare against.
87
+
88
+ **Returns:** `true` if the password matches the hash.
89
+
90
+ #### `getProvider()`
91
+
92
+ Retrieves the bonded password provider, throwing if none is configured.
93
+
94
+ ```typescript
95
+ function getProvider(): PasswordProvider
96
+ ```
97
+
98
+ **Returns:** The bonded password provider.
99
+
100
+ #### `hash(password, saltRounds)`
101
+
102
+ Hashes a plain-text password using the bonded provider.
103
+
104
+ ```typescript
105
+ function hash(password: string, saltRounds?: number): Promise<string>
106
+ ```
107
+
108
+ - `password` — The plain-text password to hash. The env-derived default is clamped to a sane bcrypt-cost range of 10–16 (mirroring `@molecule/api-password-bcrypt`'s own default): the cost factor is EXPONENTIAL (each +1 doubles the work), so a misread `SALT_ROUNDS=32` would otherwise hang every signup for hours with zero error output, and `SALT_ROUNDS=4` would silently produce weak hashes. An explicitly passed `saltRounds` argument is honored as-is (a deliberate caller choice, e.g. fast test fixtures).
109
+ - `saltRounds` — Number of salt rounds (cost factor); defaults to the `SALT_ROUNDS` env var (clamped to 10–16) or 12.
110
+
111
+ **Returns:** The resulting password hash string.
112
+
113
+ #### `hasProvider()`
114
+
115
+ Checks whether a password provider is currently bonded.
116
+
117
+ ```typescript
118
+ function hasProvider(): boolean
119
+ ```
120
+
121
+ **Returns:** `true` if a password provider is bonded.
122
+
123
+ #### `setProvider(provider)`
124
+
125
+ Registers a password hashing provider as the active singleton. Called by
126
+ bond packages during application startup.
127
+
128
+ ```typescript
129
+ function setProvider(provider: PasswordProvider): void
130
+ ```
131
+
132
+ - `provider` — The password hashing provider implementation to bond.
133
+
134
+ ## Available Providers
135
+
136
+ | Provider | Package |
137
+ | -------- | ------------------------------- |
138
+ | bcrypt | `@molecule/api-password-bcrypt` |
139
+
140
+ ## Injection Notes
141
+
142
+ ### Requirements
143
+
144
+ Peer dependencies:
145
+
146
+ - `@molecule/api-bond` ^1.0.1
147
+ - `@molecule/api-i18n` ^1.0.1
148
+
149
+ ### Runtime Dependencies
150
+
151
+ - `@molecule/api-bond`
152
+ - `@molecule/api-i18n`
153
+
154
+ Use {@link hash} and {@link compare} from the bonded provider — NEVER roll your own
155
+ password hashing.
156
+
157
+ - **Never store, log, or return a password OR its hash to the client.** Persist only the
158
+ hash server-side; a login response returns a session/token, never the hash.
159
+ - **Compare with {@link compare}, never `===`.** It is a constant-time check via the bond
160
+ (bcrypt); a plain string/hash equality is a timing oracle and won't even match a salted
161
+ hash.
162
+ - Do not implement your own MD5/SHA/salt scheme, and never put a password in a URL, query
163
+ string, or GET request (it lands in logs/history).
164
+ - `hash()` uses `SALT_ROUNDS` (default 12, env value clamped to 10–16) from config —
165
+ don't hardcode a weaker cost. The cost is EXPONENTIAL (each +1 doubles the work), so
166
+ an unclamped 32 would hang every signup for hours.
167
+ - **bcrypt only reads the first 72 BYTES of a password** — two passwords sharing the
168
+ same first 72 bytes compare equal. Don't prepend a long app-controlled prefix (pepper,
169
+ username) to the password before hashing, and don't reject long passphrases thinking
170
+ extra length past ~72 bytes (fewer with multi-byte UTF-8) adds strength.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-password",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Password hashing interface for molecule.dev",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -17,7 +17,8 @@
17
17
  }
18
18
  },
19
19
  "files": [
20
- "dist"
20
+ "dist",
21
+ "README.md"
21
22
  ],
22
23
  "keywords": [
23
24
  "molecule",
@@ -27,21 +28,21 @@
27
28
  ],
28
29
  "license": "Apache-2.0",
29
30
  "peerDependencies": {
30
- "@molecule/api-bond": "^1.0.0",
31
- "@molecule/api-i18n": "^1.0.0"
31
+ "@molecule/api-bond": "^1.0.1",
32
+ "@molecule/api-i18n": "^1.0.1"
32
33
  },
33
34
  "devDependencies": {
34
- "@molecule/api-bond": "1.0.0",
35
- "@molecule/api-i18n": "1.0.0",
35
+ "@molecule/api-bond": "1.0.2",
36
+ "@molecule/api-i18n": "1.0.3",
36
37
  "typescript": "6.0.3",
37
- "vitest": "4.1.10"
38
+ "vitest": "4.1.11"
38
39
  },
39
40
  "repository": {
40
41
  "type": "git",
41
42
  "url": "https://github.com/molecule-dev/molecule.git",
42
43
  "directory": "packages/api/core/password"
43
44
  },
44
- "homepage": "https://github.com/molecule-dev/molecule/tree/main/packages/api/core/password",
45
+ "homepage": "https://www.molecule.dev/packages/api-password",
45
46
  "bugs": "https://github.com/molecule-dev/molecule/issues",
46
47
  "publishConfig": {
47
48
  "access": "public"