bun-types 1.2.21-canary.20250822T140708 → 1.2.21-canary.20250823T140535

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/bun.d.ts CHANGED
@@ -1844,6 +1844,10 @@ declare module "bun" {
1844
1844
  hideConsole?: boolean;
1845
1845
  icon?: string;
1846
1846
  title?: string;
1847
+ publisher?: string;
1848
+ version?: string;
1849
+ description?: string;
1850
+ copyright?: string;
1847
1851
  };
1848
1852
  }
1849
1853
 
@@ -2120,6 +2124,287 @@ declare module "bun" {
2120
2124
  ): string;
2121
2125
  };
2122
2126
 
2127
+ /**
2128
+ * Securely store and retrieve sensitive credentials using the operating system's native credential storage.
2129
+ *
2130
+ * Uses platform-specific secure storage:
2131
+ * - **macOS**: Keychain Services
2132
+ * - **Linux**: libsecret (GNOME Keyring, KWallet, etc.)
2133
+ * - **Windows**: Windows Credential Manager
2134
+ *
2135
+ * @category Security
2136
+ *
2137
+ * @example
2138
+ * ```ts
2139
+ * import { secrets } from "bun";
2140
+ *
2141
+ * // Store a credential
2142
+ * await secrets.set({
2143
+ * service: "my-cli-tool",
2144
+ * name: "github-token",
2145
+ * value: "ghp_xxxxxxxxxxxxxxxxxxxx"
2146
+ * });
2147
+ *
2148
+ * // Retrieve a credential
2149
+ * const token = await secrets.get({
2150
+ * service: "my-cli-tool",
2151
+ * name: "github-token"
2152
+ * });
2153
+ *
2154
+ * if (token) {
2155
+ * console.log("Token found:", token);
2156
+ * } else {
2157
+ * console.log("Token not found");
2158
+ * }
2159
+ *
2160
+ * // Delete a credential
2161
+ * const deleted = await secrets.delete({
2162
+ * service: "my-cli-tool",
2163
+ * name: "github-token"
2164
+ * });
2165
+ * console.log("Deleted:", deleted); // true if deleted, false if not found
2166
+ * ```
2167
+ *
2168
+ * @example
2169
+ * ```ts
2170
+ * // Replace plaintext config files
2171
+ * import { secrets } from "bun";
2172
+ *
2173
+ * // Instead of storing in ~/.npmrc
2174
+ * await secrets.set({
2175
+ * service: "npm-registry",
2176
+ * name: "https://registry.npmjs.org",
2177
+ * value: "npm_xxxxxxxxxxxxxxxxxxxx"
2178
+ * });
2179
+ *
2180
+ * // Instead of storing in ~/.aws/credentials
2181
+ * await secrets.set({
2182
+ * service: "aws-cli",
2183
+ * name: "default",
2184
+ * value: process.env.AWS_SECRET_ACCESS_KEY
2185
+ * });
2186
+ *
2187
+ * // Load at runtime with fallback
2188
+ * const apiKey = await secrets.get({
2189
+ * service: "my-app",
2190
+ * name: "api-key"
2191
+ * }) || process.env.API_KEY;
2192
+ * ```
2193
+ */
2194
+ const secrets: {
2195
+ /**
2196
+ * Retrieve a stored credential from the operating system's secure storage.
2197
+ *
2198
+ * @param options - The service and name identifying the credential
2199
+ * @returns The stored credential value, or null if not found
2200
+ *
2201
+ * @example
2202
+ * ```ts
2203
+ * const password = await Bun.secrets.get({
2204
+ * service: "my-database",
2205
+ * name: "admin"
2206
+ * });
2207
+ *
2208
+ * if (password) {
2209
+ * await connectToDatabase(password);
2210
+ * }
2211
+ * ```
2212
+ *
2213
+ * @example
2214
+ * ```ts
2215
+ * // Check multiple possible locations
2216
+ * const token =
2217
+ * await Bun.secrets.get({ service: "github", name: "token" }) ||
2218
+ * await Bun.secrets.get({ service: "gh-cli", name: "github.com" }) ||
2219
+ * process.env.GITHUB_TOKEN;
2220
+ * ```
2221
+ */
2222
+ get(options: {
2223
+ /**
2224
+ * The service or application name.
2225
+ *
2226
+ * Use a unique identifier for your application to avoid conflicts.
2227
+ * Consider using reverse domain notation for production apps (e.g., "com.example.myapp").
2228
+ */
2229
+ service: string;
2230
+
2231
+ /**
2232
+ * The account name, username, or resource identifier.
2233
+ *
2234
+ * This identifies the specific credential within the service.
2235
+ * Common patterns include usernames, email addresses, or resource URLs.
2236
+ */
2237
+ name: string;
2238
+ }): Promise<string | null>;
2239
+
2240
+ /**
2241
+ * Store or update a credential in the operating system's secure storage.
2242
+ *
2243
+ * If a credential already exists for the given service/name combination, it will be replaced.
2244
+ * The credential is encrypted by the operating system and only accessible to the current user.
2245
+ *
2246
+ * @param options - The service and name identifying the credential
2247
+ * @param value - The secret value to store (e.g., password, API key, token)
2248
+ *
2249
+ * @example
2250
+ * ```ts
2251
+ * // Store an API key
2252
+ * await Bun.secrets.set({
2253
+ * service: "openai-api",
2254
+ * name: "production",
2255
+ * value: "sk-proj-xxxxxxxxxxxxxxxxxxxx"
2256
+ * });
2257
+ * ```
2258
+ *
2259
+ * @example
2260
+ * ```ts
2261
+ * // Update an existing credential
2262
+ * const newPassword = generateSecurePassword();
2263
+ * await Bun.secrets.set({
2264
+ * service: "email-server",
2265
+ * name: "admin@example.com",
2266
+ * value: newPassword
2267
+ * });
2268
+ * ```
2269
+ *
2270
+ * @example
2271
+ * ```ts
2272
+ * // Store credentials from environment variables
2273
+ * if (process.env.DATABASE_PASSWORD) {
2274
+ * await Bun.secrets.set({
2275
+ * service: "postgres",
2276
+ * name: "production",
2277
+ * value: process.env.DATABASE_PASSWORD
2278
+ * });
2279
+ * delete process.env.DATABASE_PASSWORD; // Remove from memory
2280
+ * }
2281
+ * ```
2282
+ *
2283
+ * @example
2284
+ * ```ts
2285
+ * // Delete a credential using empty string (equivalent to delete())
2286
+ * await Bun.secrets.set({
2287
+ * service: "my-service",
2288
+ * name: "api-key",
2289
+ * value: "" // Empty string deletes the credential
2290
+ * });
2291
+ * ```
2292
+ *
2293
+ * @example
2294
+ * ```ts
2295
+ * // Store credential with unrestricted access for CI environments
2296
+ * await Bun.secrets.set({
2297
+ * service: "github-actions",
2298
+ * name: "deploy-token",
2299
+ * value: process.env.DEPLOY_TOKEN,
2300
+ * allowUnrestrictedAccess: true // Allows access without user interaction on macOS
2301
+ * });
2302
+ * ```
2303
+ */
2304
+ set(options: {
2305
+ /**
2306
+ * The service or application name.
2307
+ *
2308
+ * Use a unique identifier for your application to avoid conflicts.
2309
+ * Consider using reverse domain notation for production apps (e.g., "com.example.myapp").
2310
+ */
2311
+ service: string;
2312
+
2313
+ /**
2314
+ * The account name, username, or resource identifier.
2315
+ *
2316
+ * This identifies the specific credential within the service.
2317
+ * Common patterns include usernames, email addresses, or resource URLs.
2318
+ */
2319
+ name: string;
2320
+
2321
+ /**
2322
+ * The secret value to store.
2323
+ *
2324
+ * This should be a sensitive credential like a password, API key, or token.
2325
+ * The value is encrypted by the operating system before storage.
2326
+ *
2327
+ * Note: To delete a credential, use the delete() method or pass an empty string.
2328
+ * An empty string value will delete the credential if it exists.
2329
+ */
2330
+ value: string;
2331
+
2332
+ /**
2333
+ * Allow unrestricted access to stored credentials on macOS.
2334
+ *
2335
+ * When true, allows all applications to access this keychain item without user interaction.
2336
+ * This is useful for CI environments but reduces security.
2337
+ *
2338
+ * @default false
2339
+ * @platform macOS - Only affects macOS keychain behavior. Ignored on other platforms.
2340
+ */
2341
+ allowUnrestrictedAccess?: boolean;
2342
+ }): Promise<void>;
2343
+
2344
+ /**
2345
+ * Delete a stored credential from the operating system's secure storage.
2346
+ *
2347
+ * @param options - The service and name identifying the credential
2348
+ * @returns true if a credential was deleted, false if not found
2349
+ *
2350
+ * @example
2351
+ * ```ts
2352
+ * // Delete a single credential
2353
+ * const deleted = await Bun.secrets.delete({
2354
+ * service: "my-app",
2355
+ * name: "api-key"
2356
+ * });
2357
+ *
2358
+ * if (deleted) {
2359
+ * console.log("Credential removed successfully");
2360
+ * } else {
2361
+ * console.log("Credential was not found");
2362
+ * }
2363
+ * ```
2364
+ *
2365
+ * @example
2366
+ * ```ts
2367
+ * // Clean up multiple credentials
2368
+ * const services = ["github", "npm", "docker"];
2369
+ * for (const service of services) {
2370
+ * await Bun.secrets.delete({
2371
+ * service,
2372
+ * name: "token"
2373
+ * });
2374
+ * }
2375
+ * ```
2376
+ *
2377
+ * @example
2378
+ * ```ts
2379
+ * // Clean up on uninstall
2380
+ * if (process.argv.includes("--uninstall")) {
2381
+ * const deleted = await Bun.secrets.delete({
2382
+ * service: "my-cli-tool",
2383
+ * name: "config"
2384
+ * });
2385
+ * process.exit(deleted ? 0 : 1);
2386
+ * }
2387
+ * ```
2388
+ */
2389
+ delete(options: {
2390
+ /**
2391
+ * The service or application name.
2392
+ *
2393
+ * Use a unique identifier for your application to avoid conflicts.
2394
+ * Consider using reverse domain notation for production apps (e.g., "com.example.myapp").
2395
+ */
2396
+ service: string;
2397
+
2398
+ /**
2399
+ * The account name, username, or resource identifier.
2400
+ *
2401
+ * This identifies the specific credential within the service.
2402
+ * Common patterns include usernames, email addresses, or resource URLs.
2403
+ */
2404
+ name: string;
2405
+ }): Promise<boolean>;
2406
+ };
2407
+
2123
2408
  /**
2124
2409
  * A build artifact represents a file that was generated by the bundler @see {@link Bun.build}
2125
2410
  *
package/docs/api/fetch.md CHANGED
@@ -336,7 +336,7 @@ This will print the request and response headers to your terminal:
336
336
  ```sh
337
337
  [fetch] > HTTP/1.1 GET http://example.com/
338
338
  [fetch] > Connection: keep-alive
339
- [fetch] > User-Agent: Bun/1.2.21-canary.20250822T140708
339
+ [fetch] > User-Agent: Bun/1.2.21-canary.20250823T140535
340
340
  [fetch] > Accept: */*
341
341
  [fetch] > Host: example.com
342
342
  [fetch] > Accept-Encoding: gzip, deflate, br
@@ -0,0 +1,319 @@
1
+ Store and retrieve sensitive credentials securely using the operating system's native credential storage APIs.
2
+
3
+ **Experimental:** This API is new and experimental. It may change in the future.
4
+
5
+ ```typescript
6
+ import { secrets } from "bun";
7
+
8
+ const githubToken = await secrets.get({
9
+ service: "my-cli-tool",
10
+ name: "github-token",
11
+ });
12
+
13
+ if (!githubToken) {
14
+ const response = await fetch("https://api.github.com/name", {
15
+ headers: { "Authorization": `token ${githubToken}` },
16
+ });
17
+ console.log("Please enter your GitHub token");
18
+ } else {
19
+ await secrets.set({
20
+ service: "my-cli-tool",
21
+ name: "github-token",
22
+ value: prompt("Please enter your GitHub token"),
23
+ });
24
+ console.log("GitHub token stored");
25
+ }
26
+ ```
27
+
28
+ ## Overview
29
+
30
+ `Bun.secrets` provides a cross-platform API for managing sensitive credentials that CLI tools and development applications typically store in plaintext files like `~/.npmrc`, `~/.aws/credentials`, or `.env` files. It uses:
31
+
32
+ - **macOS**: Keychain Services
33
+ - **Linux**: libsecret (GNOME Keyring, KWallet, etc.)
34
+ - **Windows**: Windows Credential Manager
35
+
36
+ All operations are asynchronous and non-blocking, running on Bun's threadpool.
37
+
38
+ Note: in the future, we may add an additional `provider` option to make this better for production deployment secrets, but today this API is mostly useful for local development tools.
39
+
40
+ ## API
41
+
42
+ ### `Bun.secrets.get(options)`
43
+
44
+ Retrieve a stored credential.
45
+
46
+ ```typescript
47
+ import { secrets } from "bun";
48
+
49
+ const password = await Bun.secrets.get({
50
+ service: "my-app",
51
+ name: "alice@example.com",
52
+ });
53
+ // Returns: string | null
54
+
55
+ // Or if you prefer without an object
56
+ const password = await Bun.secrets.get("my-app", "alice@example.com");
57
+ ```
58
+
59
+ **Parameters:**
60
+
61
+ - `options.service` (string, required) - The service or application name
62
+ - `options.name` (string, required) - The username or account identifier
63
+
64
+ **Returns:**
65
+
66
+ - `Promise<string | null>` - The stored password, or `null` if not found
67
+
68
+ ### `Bun.secrets.set(options, value)`
69
+
70
+ Store or update a credential.
71
+
72
+ ```typescript
73
+ import { secrets } from "bun";
74
+
75
+ await secrets.set({
76
+ service: "my-app",
77
+ name: "alice@example.com",
78
+ value: "super-secret-password",
79
+ });
80
+ ```
81
+
82
+ **Parameters:**
83
+
84
+ - `options.service` (string, required) - The service or application name
85
+ - `options.name` (string, required) - The username or account identifier
86
+ - `value` (string, required) - The password or secret to store
87
+
88
+ **Notes:**
89
+
90
+ - If a credential already exists for the given service/name combination, it will be replaced
91
+ - The stored value is encrypted by the operating system
92
+
93
+ ### `Bun.secrets.delete(options)`
94
+
95
+ Delete a stored credential.
96
+
97
+ ```typescript
98
+ const deleted = await Bun.secrets.delete({
99
+ service: "my-app",
100
+ name: "alice@example.com",
101
+ value: "super-secret-password",
102
+ });
103
+ // Returns: boolean
104
+ ```
105
+
106
+ **Parameters:**
107
+
108
+ - `options.service` (string, required) - The service or application name
109
+ - `options.name` (string, required) - The username or account identifier
110
+
111
+ **Returns:**
112
+
113
+ - `Promise<boolean>` - `true` if a credential was deleted, `false` if not found
114
+
115
+ ## Examples
116
+
117
+ ### Storing CLI Tool Credentials
118
+
119
+ ```javascript
120
+ // Store GitHub CLI token (instead of ~/.config/gh/hosts.yml)
121
+ await Bun.secrets.set({
122
+ service: "my-app.com",
123
+ name: "github-token",
124
+ value: "ghp_xxxxxxxxxxxxxxxxxxxx",
125
+ });
126
+
127
+ // Or if you prefer without an object
128
+ await Bun.secrets.set("my-app.com", "github-token", "ghp_xxxxxxxxxxxxxxxxxxxx");
129
+
130
+ // Store npm registry token (instead of ~/.npmrc)
131
+ await Bun.secrets.set({
132
+ service: "npm-registry",
133
+ name: "https://registry.npmjs.org",
134
+ value: "npm_xxxxxxxxxxxxxxxxxxxx",
135
+ });
136
+
137
+ // Retrieve for API calls
138
+ const token = await Bun.secrets.get({
139
+ service: "gh-cli",
140
+ name: "github.com",
141
+ });
142
+
143
+ if (token) {
144
+ const response = await fetch("https://api.github.com/name", {
145
+ headers: {
146
+ "Authorization": `token ${token}`,
147
+ },
148
+ });
149
+ }
150
+ ```
151
+
152
+ ### Migrating from Plaintext Config Files
153
+
154
+ ```javascript
155
+ // Instead of storing in ~/.aws/credentials
156
+ await Bun.secrets.set({
157
+ service: "aws-cli",
158
+ name: "AWS_SECRET_ACCESS_KEY",
159
+ value: process.env.AWS_SECRET_ACCESS_KEY,
160
+ });
161
+
162
+ // Instead of .env files with sensitive data
163
+ await Bun.secrets.set({
164
+ service: "my-app",
165
+ name: "api-key",
166
+ value: "sk_live_xxxxxxxxxxxxxxxxxxxx",
167
+ });
168
+
169
+ // Load at runtime
170
+ const apiKey =
171
+ (await Bun.secrets.get({
172
+ service: "my-app",
173
+ name: "api-key",
174
+ })) || process.env.API_KEY; // Fallback for CI/production
175
+ ```
176
+
177
+ ### Error Handling
178
+
179
+ ```javascript
180
+ try {
181
+ await Bun.secrets.set({
182
+ service: "my-app",
183
+ name: "alice",
184
+ value: "password123",
185
+ });
186
+ } catch (error) {
187
+ console.error("Failed to store credential:", error.message);
188
+ }
189
+
190
+ // Check if a credential exists
191
+ const password = await Bun.secrets.get({
192
+ service: "my-app",
193
+ name: "alice",
194
+ });
195
+
196
+ if (password === null) {
197
+ console.log("No credential found");
198
+ }
199
+ ```
200
+
201
+ ### Updating Credentials
202
+
203
+ ```javascript
204
+ // Initial password
205
+ await Bun.secrets.set({
206
+ service: "email-server",
207
+ name: "admin@example.com",
208
+ value: "old-password",
209
+ });
210
+
211
+ // Update to new password
212
+ await Bun.secrets.set({
213
+ service: "email-server",
214
+ name: "admin@example.com",
215
+ value: "new-password",
216
+ });
217
+
218
+ // The old password is replaced
219
+ ```
220
+
221
+ ## Platform Behavior
222
+
223
+ ### macOS (Keychain)
224
+
225
+ - Credentials are stored in the name's login keychain
226
+ - The keychain may prompt for access permission on first use
227
+ - Credentials persist across system restarts
228
+ - Accessible by the name who stored them
229
+
230
+ ### Linux (libsecret)
231
+
232
+ - Requires a secret service daemon (GNOME Keyring, KWallet, etc.)
233
+ - Credentials are stored in the default collection
234
+ - May prompt for unlock if the keyring is locked
235
+ - The secret service must be running
236
+
237
+ ### Windows (Credential Manager)
238
+
239
+ - Credentials are stored in Windows Credential Manager
240
+ - Visible in Control Panel → Credential Manager → Windows Credentials
241
+ - Persist with `CRED_PERSIST_ENTERPRISE` flag so it's scoped per user
242
+ - Encrypted using Windows Data Protection API
243
+
244
+ ## Security Considerations
245
+
246
+ 1. **Encryption**: Credentials are encrypted by the operating system's credential manager
247
+ 2. **Access Control**: Only the name who stored the credential can retrieve it
248
+ 3. **No Plain Text**: Passwords are never stored in plain text
249
+ 4. **Memory Safety**: Bun zeros out password memory after use
250
+ 5. **Process Isolation**: Credentials are isolated per name account
251
+
252
+ ## Limitations
253
+
254
+ - Maximum password length varies by platform (typically 2048-4096 bytes)
255
+ - Service and name names should be reasonable lengths (< 256 characters)
256
+ - Some special characters may need escaping depending on the platform
257
+ - Requires appropriate system services:
258
+ - Linux: Secret service daemon must be running
259
+ - macOS: Keychain Access must be available
260
+ - Windows: Credential Manager service must be enabled
261
+
262
+ ## Comparison with Environment Variables
263
+
264
+ Unlike environment variables, `Bun.secrets`:
265
+
266
+ - ✅ Encrypts credentials at rest (thanks to the operating system)
267
+ - ✅ Avoids exposing secrets in process memory dumps (memory is zeroed after its no longer needed)
268
+ - ✅ Survives application restarts
269
+ - ✅ Can be updated without restarting the application
270
+ - ✅ Provides name-level access control
271
+ - ❌ Requires OS credential service
272
+ - ❌ Not very useful for deployment secrets (use environment variables in production)
273
+
274
+ ## Best Practices
275
+
276
+ 1. **Use descriptive service names**: Match the tool or application name
277
+ If you're building a CLI for external use, you probably should use a UTI (Uniform Type Identifier) for the service name.
278
+
279
+ ```javascript
280
+ // Good - matches the actual tool
281
+ { service: "com.docker.hub", name: "username" }
282
+ { service: "com.vercel.cli", name: "team-name" }
283
+
284
+ // Avoid - too generic
285
+ { service: "api", name: "key" }
286
+ ```
287
+
288
+ 2. **Credentials-only**: Don't store application configuration in this API
289
+ This API is slow, you probably still need to use a config file for some things.
290
+
291
+ 3. **Use for local development tools**:
292
+ - ✅ CLI tools (gh, npm, docker, kubectl)
293
+ - ✅ Local development servers
294
+ - ✅ Personal API keys for testing
295
+ - ❌ Production servers (use proper secret management)
296
+
297
+ ## TypeScript
298
+
299
+ ```typescript
300
+ namespace Bun {
301
+ interface SecretsOptions {
302
+ service: string;
303
+ name: string;
304
+ }
305
+
306
+ interface Secrets {
307
+ get(options: SecretsOptions): Promise<string | null>;
308
+ set(options: SecretsOptions, value: string): Promise<void>;
309
+ delete(options: SecretsOptions): Promise<boolean>;
310
+ }
311
+
312
+ const secrets: Secrets;
313
+ }
314
+ ```
315
+
316
+ ## See Also
317
+
318
+ - [Environment Variables](./env.md) - For deployment configuration
319
+ - [Bun.password](./password.md) - For password hashing and verification
package/docs/api/spawn.md CHANGED
@@ -140,7 +140,7 @@ You can read results from the subprocess via the `stdout` and `stderr` propertie
140
140
  ```ts
141
141
  const proc = Bun.spawn(["bun", "--version"]);
142
142
  const text = await proc.stdout.text();
143
- console.log(text); // => "1.2.21-canary.20250822T140708\n"
143
+ console.log(text); // => "1.2.21-canary.20250823T140535\n"
144
144
  ```
145
145
 
146
146
  Configure the output stream by passing one of the following values to `stdout/stderr`: