oauth-callback 1.2.1 β†’ 1.2.3

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
@@ -4,6 +4,7 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/oauth-callback.svg)](https://npmjs.com/package/oauth-callback)
5
5
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/kriasoft/oauth-callback/blob/main/LICENSE)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
7
+ [![Run on Replit](https://img.shields.io/badge/Run%20on-Replit-orange.svg)](https://replit.com/@kriasoft/oauth-callback)
7
8
 
8
9
  A lightweight OAuth 2.0 callback handler for Node.js, Deno, and Bun with built-in browser flow and MCP SDK integration. Perfect for CLI tools, desktop applications, and development environments that need to capture OAuth authorization codes.
9
10
 
@@ -16,7 +17,7 @@ A lightweight OAuth 2.0 callback handler for Node.js, Deno, and Bun with built-i
16
17
  - πŸš€ **Multi-runtime support** - Works with Node.js 18+, Deno, and Bun
17
18
  - πŸ”’ **Secure localhost-only server** for OAuth callbacks
18
19
  - πŸ€– **MCP SDK integration** - Built-in OAuth provider for Model Context Protocol
19
- - ⚑ **Minimal dependencies** - Only requires `open` package
20
+ - ⚑ **Single dependency** - Only requires `open` for browser launching
20
21
  - 🎯 **TypeScript support** out of the box
21
22
  - πŸ›‘οΈ **Comprehensive OAuth error handling** with detailed error classes
22
23
  - πŸ”„ **Automatic server cleanup** after callback
@@ -106,34 +107,6 @@ const result = await getAuthCode({
106
107
  });
107
108
  ```
108
109
 
109
- ### Handling Different OAuth Providers
110
-
111
- ```typescript
112
- // Google OAuth
113
- const googleAuth = await getAuthCode(
114
- "https://accounts.google.com/o/oauth2/v2/auth?" +
115
- new URLSearchParams({
116
- client_id: process.env.GOOGLE_CLIENT_ID,
117
- redirect_uri: "http://localhost:3000/callback",
118
- response_type: "code",
119
- scope: "openid email profile",
120
- access_type: "offline",
121
- }),
122
- );
123
-
124
- // Microsoft OAuth
125
- const microsoftAuth = await getAuthCode(
126
- "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?" +
127
- new URLSearchParams({
128
- client_id: process.env.MICROSOFT_CLIENT_ID,
129
- redirect_uri: "http://localhost:3000/callback",
130
- response_type: "code",
131
- scope: "user.read",
132
- response_mode: "query",
133
- }),
134
- );
135
- ```
136
-
137
110
  ### MCP SDK Integration
138
111
 
139
112
  The `browserAuth()` function provides a drop-in OAuth provider for the Model Context Protocol SDK:
@@ -327,18 +300,30 @@ TokenStore implementation for persistent token storage.
327
300
 
328
301
  ## How It Works
329
302
 
330
- 1. **Server Creation**: Creates a temporary HTTP server on the specified port
331
- 2. **Browser Launch**: Opens the authorization URL in the user's default browser
332
- 3. **Callback Handling**: Waits for the OAuth provider to redirect back with the authorization code
333
- 4. **Cleanup**: Automatically closes the server after receiving the callback
334
- 5. **Result**: Returns the authorization code and any additional parameters
303
+ ```
304
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
305
+ β”‚ Your App │────▢│Local Server │────▢│ Browser │────▢│OAuth Server β”‚
306
+ β”‚ β”‚ β”‚ :3000 β”‚ β”‚ β”‚ β”‚ β”‚
307
+ β”‚ getAuthCode β”‚ β”‚ │◀────│ Callback │◀────│ Redirect β”‚
308
+ β”‚ β–Ό │◀────│ Returns β”‚ β”‚ /callback β”‚ β”‚ with code β”‚
309
+ β”‚ {code} β”‚ β”‚ auth code β”‚ β”‚ β”‚ β”‚ β”‚
310
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
311
+ ```
312
+
313
+ 1. **Server Creation** β€” Spins up a temporary localhost HTTP server
314
+ 2. **Browser Launch** β€” Opens the authorization URL in the default browser
315
+ 3. **User Authorization** β€” User grants permission on the OAuth provider's page
316
+ 4. **Callback Capture** β€” Provider redirects to localhost with the authorization code
317
+ 5. **Cleanup** β€” Server closes automatically, code is returned to your app
335
318
 
336
319
  ## Security Considerations
337
320
 
338
- - The server only accepts connections from localhost
339
- - Server is closed immediately after receiving the callback
340
- - No data is stored persistently
341
- - State parameter validation should be implemented by the application
321
+ - **Localhost-only binding** β€” Server rejects non-local connections
322
+ - **Ephemeral server** β€” Shuts down immediately after receiving the callback
323
+ - **No credential logging** β€” Tokens and codes are never written to logs
324
+ - **State parameter support** β€” Pass and validate state to prevent CSRF attacks
325
+ - **Configurable timeouts** β€” Server auto-terminates if callback isn't received
326
+ - **PKCE compatible** β€” Works with authorization servers that require PKCE
342
327
 
343
328
  ## Running the Examples
344
329
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=error.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.test.d.ts","sourceRoot":"","sources":["../src/error.test.ts"],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -27,16 +27,15 @@ var __export = (target, all) => {
27
27
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
28
28
 
29
29
  // node_modules/open/index.js
30
- import process6 from "node:process";
31
- import { Buffer } from "node:buffer";
30
+ import process7 from "node:process";
32
31
  import path from "node:path";
33
32
  import { fileURLToPath } from "node:url";
34
- import { promisify as promisify5 } from "node:util";
35
- import childProcess from "node:child_process";
33
+ import childProcess3 from "node:child_process";
36
34
  import fs5, { constants as fsConstants2 } from "node:fs/promises";
37
35
 
38
36
  // node_modules/wsl-utils/index.js
39
- import process2 from "node:process";
37
+ import { promisify as promisify2 } from "node:util";
38
+ import childProcess2 from "node:child_process";
40
39
  import fs4, { constants as fsConstants } from "node:fs/promises";
41
40
 
42
41
  // node_modules/is-wsl/index.js
@@ -108,7 +107,54 @@ var isWsl = () => {
108
107
  };
109
108
  var is_wsl_default = process.env.__IS_WSL_TEST__ ? isWsl : isWsl();
110
109
 
110
+ // node_modules/powershell-utils/index.js
111
+ import process2 from "node:process";
112
+ import { Buffer } from "node:buffer";
113
+ import { promisify } from "node:util";
114
+ import childProcess from "node:child_process";
115
+ var execFile = promisify(childProcess.execFile);
116
+ var powerShellPath = () => `${process2.env.SYSTEMROOT || process2.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
117
+ var executePowerShell = async (command, options = {}) => {
118
+ const {
119
+ powerShellPath: psPath,
120
+ ...execFileOptions
121
+ } = options;
122
+ const encodedCommand = executePowerShell.encodeCommand(command);
123
+ return execFile(psPath ?? powerShellPath(), [
124
+ ...executePowerShell.argumentsPrefix,
125
+ encodedCommand
126
+ ], {
127
+ encoding: "utf8",
128
+ ...execFileOptions
129
+ });
130
+ };
131
+ executePowerShell.argumentsPrefix = [
132
+ "-NoProfile",
133
+ "-NonInteractive",
134
+ "-ExecutionPolicy",
135
+ "Bypass",
136
+ "-EncodedCommand"
137
+ ];
138
+ executePowerShell.encodeCommand = (command) => Buffer.from(command, "utf16le").toString("base64");
139
+ executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
140
+
141
+ // node_modules/wsl-utils/utilities.js
142
+ function parseMountPointFromConfig(content) {
143
+ for (const line of content.split(`
144
+ `)) {
145
+ if (/^\s*#/.test(line)) {
146
+ continue;
147
+ }
148
+ const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
149
+ if (!match) {
150
+ continue;
151
+ }
152
+ return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
153
+ }
154
+ }
155
+
111
156
  // node_modules/wsl-utils/index.js
157
+ var execFile2 = promisify2(childProcess2.execFile);
112
158
  var wslDrivesMountPoint = (() => {
113
159
  const defaultMountPoint = "/mnt/";
114
160
  let mountPoint;
@@ -126,11 +172,11 @@ var wslDrivesMountPoint = (() => {
126
172
  return defaultMountPoint;
127
173
  }
128
174
  const configContent = await fs4.readFile(configFilePath, { encoding: "utf8" });
129
- const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
130
- if (!configMountPoint) {
175
+ const parsedMountPoint = parseMountPointFromConfig(configContent);
176
+ if (parsedMountPoint === undefined) {
131
177
  return defaultMountPoint;
132
178
  }
133
- mountPoint = configMountPoint.groups.mountPoint.trim();
179
+ mountPoint = parsedMountPoint;
134
180
  mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
135
181
  return mountPoint;
136
182
  };
@@ -139,11 +185,36 @@ var powerShellPathFromWsl = async () => {
139
185
  const mountPoint = await wslDrivesMountPoint();
140
186
  return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
141
187
  };
142
- var powerShellPath = async () => {
143
- if (is_wsl_default) {
144
- return powerShellPathFromWsl();
188
+ var powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
189
+ var canAccessPowerShellPromise;
190
+ var canAccessPowerShell = async () => {
191
+ canAccessPowerShellPromise ??= (async () => {
192
+ try {
193
+ const psPath = await powerShellPath2();
194
+ await fs4.access(psPath, fsConstants.X_OK);
195
+ return true;
196
+ } catch {
197
+ return false;
198
+ }
199
+ })();
200
+ return canAccessPowerShellPromise;
201
+ };
202
+ var wslDefaultBrowser = async () => {
203
+ const psPath = await powerShellPath2();
204
+ const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
205
+ const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
206
+ return stdout.trim();
207
+ };
208
+ var convertWslPathToWindows = async (path) => {
209
+ if (/^[a-z]+:\/\//i.test(path)) {
210
+ return path;
211
+ }
212
+ try {
213
+ const { stdout } = await execFile2("wslpath", ["-aw", path], { encoding: "utf8" });
214
+ return stdout.trim();
215
+ } catch {
216
+ return path;
145
217
  }
146
- return `${process2.env.SYSTEMROOT || process2.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
147
218
  };
148
219
 
149
220
  // node_modules/define-lazy-prop/index.js
@@ -165,15 +236,15 @@ function defineLazyProperty(object, propertyName, valueGetter) {
165
236
  }
166
237
 
167
238
  // node_modules/default-browser/index.js
168
- import { promisify as promisify4 } from "node:util";
239
+ import { promisify as promisify6 } from "node:util";
169
240
  import process5 from "node:process";
170
- import { execFile as execFile4 } from "node:child_process";
241
+ import { execFile as execFile6 } from "node:child_process";
171
242
 
172
243
  // node_modules/default-browser-id/index.js
173
- import { promisify } from "node:util";
244
+ import { promisify as promisify3 } from "node:util";
174
245
  import process3 from "node:process";
175
- import { execFile } from "node:child_process";
176
- var execFileAsync = promisify(execFile);
246
+ import { execFile as execFile3 } from "node:child_process";
247
+ var execFileAsync = promisify3(execFile3);
177
248
  async function defaultBrowserId() {
178
249
  if (process3.platform !== "darwin") {
179
250
  throw new Error("macOS only");
@@ -185,9 +256,9 @@ async function defaultBrowserId() {
185
256
 
186
257
  // node_modules/run-applescript/index.js
187
258
  import process4 from "node:process";
188
- import { promisify as promisify2 } from "node:util";
189
- import { execFile as execFile2, execFileSync } from "node:child_process";
190
- var execFileAsync2 = promisify2(execFile2);
259
+ import { promisify as promisify4 } from "node:util";
260
+ import { execFile as execFile4, execFileSync } from "node:child_process";
261
+ var execFileAsync2 = promisify4(execFile4);
191
262
  async function runAppleScript(script, { humanReadableOutput = true } = {}) {
192
263
  if (process4.platform !== "darwin") {
193
264
  throw new Error("macOS only");
@@ -204,20 +275,28 @@ tell application "System Events" to get value of property list item "CFBundleNam
204
275
  }
205
276
 
206
277
  // node_modules/default-browser/windows.js
207
- import { promisify as promisify3 } from "node:util";
208
- import { execFile as execFile3 } from "node:child_process";
209
- var execFileAsync3 = promisify3(execFile3);
278
+ import { promisify as promisify5 } from "node:util";
279
+ import { execFile as execFile5 } from "node:child_process";
280
+ var execFileAsync3 = promisify5(execFile5);
210
281
  var windowsBrowserProgIds = {
211
- AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
212
- MSEdgeDHTML: { name: "Edge", id: "com.microsoft.edge" },
213
282
  MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
214
- "IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" },
215
- FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
283
+ MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
284
+ MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
285
+ AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
216
286
  ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
287
+ ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
288
+ ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
289
+ ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
217
290
  BraveHTML: { name: "Brave", id: "com.brave.Browser" },
218
291
  BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
219
- BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" }
292
+ BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
293
+ BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
294
+ FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
295
+ OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
296
+ VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
297
+ "IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
220
298
  };
299
+ var _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
221
300
 
222
301
  class UnknownBrowserError extends Error {
223
302
  }
@@ -241,7 +320,7 @@ async function defaultBrowser(_execFileAsync = execFileAsync3) {
241
320
  }
242
321
 
243
322
  // node_modules/default-browser/index.js
244
- var execFileAsync4 = promisify4(execFile4);
323
+ var execFileAsync4 = promisify6(execFile6);
245
324
  var titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
246
325
  async function defaultBrowser2() {
247
326
  if (process5.platform === "darwin") {
@@ -261,42 +340,29 @@ async function defaultBrowser2() {
261
340
  throw new Error("Only macOS, Linux, and Windows are supported");
262
341
  }
263
342
 
343
+ // node_modules/is-in-ssh/index.js
344
+ import process6 from "node:process";
345
+ var isInSsh = Boolean(process6.env.SSH_CONNECTION || process6.env.SSH_CLIENT || process6.env.SSH_TTY);
346
+ var is_in_ssh_default = isInSsh;
347
+
264
348
  // node_modules/open/index.js
265
- var execFile5 = promisify5(childProcess.execFile);
266
- var __dirname2 = path.dirname(fileURLToPath(import.meta.url));
349
+ var fallbackAttemptSymbol = Symbol("fallbackAttempt");
350
+ var __dirname2 = import.meta.url ? path.dirname(fileURLToPath(import.meta.url)) : "";
267
351
  var localXdgOpenPath = path.join(__dirname2, "xdg-open");
268
- var { platform, arch } = process6;
269
- async function getWindowsDefaultBrowserFromWsl() {
270
- const powershellPath = await powerShellPath();
271
- const rawCommand = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
272
- const encodedCommand = Buffer.from(rawCommand, "utf16le").toString("base64");
273
- const { stdout } = await execFile5(powershellPath, [
274
- "-NoProfile",
275
- "-NonInteractive",
276
- "-ExecutionPolicy",
277
- "Bypass",
278
- "-EncodedCommand",
279
- encodedCommand
280
- ], { encoding: "utf8" });
281
- const progId = stdout.trim();
282
- const browserMap = {
283
- ChromeHTML: "com.google.chrome",
284
- BraveHTML: "com.brave.Browser",
285
- MSEdgeHTM: "com.microsoft.edge",
286
- FirefoxURL: "org.mozilla.firefox"
287
- };
288
- return browserMap[progId] ? { id: browserMap[progId] } : {};
289
- }
290
- var pTryEach = async (array, mapper) => {
291
- let latestError;
292
- for (const item of array) {
352
+ var { platform, arch } = process7;
353
+ var tryEachApp = async (apps, opener) => {
354
+ if (apps.length === 0) {
355
+ return;
356
+ }
357
+ const errors = [];
358
+ for (const app of apps) {
293
359
  try {
294
- return await mapper(item);
360
+ return await opener(app);
295
361
  } catch (error) {
296
- latestError = error;
362
+ errors.push(error);
297
363
  }
298
364
  }
299
- throw latestError;
365
+ throw new AggregateError(errors, "Failed to open in all supported apps");
300
366
  };
301
367
  var baseOpen = async (options) => {
302
368
  options = {
@@ -306,34 +372,39 @@ var baseOpen = async (options) => {
306
372
  allowNonzeroExitCode: false,
307
373
  ...options
308
374
  };
375
+ const isFallbackAttempt = options[fallbackAttemptSymbol] === true;
376
+ delete options[fallbackAttemptSymbol];
309
377
  if (Array.isArray(options.app)) {
310
- return pTryEach(options.app, (singleApp) => baseOpen({
378
+ return tryEachApp(options.app, (singleApp) => baseOpen({
311
379
  ...options,
312
- app: singleApp
380
+ app: singleApp,
381
+ [fallbackAttemptSymbol]: true
313
382
  }));
314
383
  }
315
384
  let { name: app, arguments: appArguments = [] } = options.app ?? {};
316
385
  appArguments = [...appArguments];
317
386
  if (Array.isArray(app)) {
318
- return pTryEach(app, (appName) => baseOpen({
387
+ return tryEachApp(app, (appName) => baseOpen({
319
388
  ...options,
320
389
  app: {
321
390
  name: appName,
322
391
  arguments: appArguments
323
- }
392
+ },
393
+ [fallbackAttemptSymbol]: true
324
394
  }));
325
395
  }
326
396
  if (app === "browser" || app === "browserPrivate") {
327
397
  const ids = {
328
398
  "com.google.chrome": "chrome",
329
399
  "google-chrome.desktop": "chrome",
330
- "com.brave.Browser": "brave",
400
+ "com.brave.browser": "brave",
331
401
  "org.mozilla.firefox": "firefox",
332
402
  "firefox.desktop": "firefox",
333
403
  "com.microsoft.msedge": "edge",
334
404
  "com.microsoft.edge": "edge",
335
405
  "com.microsoft.edgemac": "edge",
336
- "microsoft-edge.desktop": "edge"
406
+ "microsoft-edge.desktop": "edge",
407
+ "com.apple.safari": "safari"
337
408
  };
338
409
  const flags = {
339
410
  chrome: "--incognito",
@@ -341,10 +412,20 @@ var baseOpen = async (options) => {
341
412
  firefox: "--private-window",
342
413
  edge: "--inPrivate"
343
414
  };
344
- const browser = is_wsl_default ? await getWindowsDefaultBrowserFromWsl() : await defaultBrowser2();
415
+ let browser;
416
+ if (is_wsl_default) {
417
+ const progId = await wslDefaultBrowser();
418
+ const browserInfo = _windowsBrowserProgIdMap.get(progId);
419
+ browser = browserInfo ?? {};
420
+ } else {
421
+ browser = await defaultBrowser2();
422
+ }
345
423
  if (browser.id in ids) {
346
- const browserName = ids[browser.id];
424
+ const browserName = ids[browser.id.toLowerCase()];
347
425
  if (app === "browserPrivate") {
426
+ if (browserName === "safari") {
427
+ throw new Error("Safari doesn't support opening in private mode via command line");
428
+ }
348
429
  appArguments.push(flags[browserName]);
349
430
  }
350
431
  return baseOpen({
@@ -360,6 +441,10 @@ var baseOpen = async (options) => {
360
441
  let command;
361
442
  const cliArguments = [];
362
443
  const childProcessOptions = {};
444
+ let shouldUseWindowsInWsl = false;
445
+ if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
446
+ shouldUseWindowsInWsl = await canAccessPowerShell();
447
+ }
363
448
  if (platform === "darwin") {
364
449
  command = "open";
365
450
  if (options.wait) {
@@ -374,29 +459,35 @@ var baseOpen = async (options) => {
374
459
  if (app) {
375
460
  cliArguments.push("-a", app);
376
461
  }
377
- } else if (platform === "win32" || is_wsl_default && !isInsideContainer() && !app) {
378
- command = await powerShellPath();
379
- cliArguments.push("-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-EncodedCommand");
462
+ } else if (platform === "win32" || shouldUseWindowsInWsl) {
463
+ command = await powerShellPath2();
464
+ cliArguments.push(...executePowerShell.argumentsPrefix);
380
465
  if (!is_wsl_default) {
381
466
  childProcessOptions.windowsVerbatimArguments = true;
382
467
  }
383
- const encodedArguments = ["Start"];
468
+ if (is_wsl_default && options.target) {
469
+ options.target = await convertWslPathToWindows(options.target);
470
+ }
471
+ const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
384
472
  if (options.wait) {
385
473
  encodedArguments.push("-Wait");
386
474
  }
387
475
  if (app) {
388
- encodedArguments.push(`"\`"${app}\`""`);
476
+ encodedArguments.push(executePowerShell.escapeArgument(app));
389
477
  if (options.target) {
390
478
  appArguments.push(options.target);
391
479
  }
392
480
  } else if (options.target) {
393
- encodedArguments.push(`"${options.target}"`);
481
+ encodedArguments.push(executePowerShell.escapeArgument(options.target));
394
482
  }
395
483
  if (appArguments.length > 0) {
396
- appArguments = appArguments.map((argument) => `"\`"${argument}\`""`);
484
+ appArguments = appArguments.map((argument) => executePowerShell.escapeArgument(argument));
397
485
  encodedArguments.push("-ArgumentList", appArguments.join(","));
398
486
  }
399
- options.target = Buffer.from(encodedArguments.join(" "), "utf16le").toString("base64");
487
+ options.target = executePowerShell.encodeCommand(encodedArguments.join(" "));
488
+ if (!options.wait) {
489
+ childProcessOptions.stdio = "ignore";
490
+ }
400
491
  } else {
401
492
  if (app) {
402
493
  command = app;
@@ -407,7 +498,7 @@ var baseOpen = async (options) => {
407
498
  await fs5.access(localXdgOpenPath, fsConstants2.X_OK);
408
499
  exeLocalXdgOpen = true;
409
500
  } catch {}
410
- const useSystemXdgOpen = process6.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
501
+ const useSystemXdgOpen = process7.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
411
502
  command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
412
503
  }
413
504
  if (appArguments.length > 0) {
@@ -424,12 +515,12 @@ var baseOpen = async (options) => {
424
515
  if (options.target) {
425
516
  cliArguments.push(options.target);
426
517
  }
427
- const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
518
+ const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
428
519
  if (options.wait) {
429
520
  return new Promise((resolve, reject) => {
430
521
  subprocess.once("error", reject);
431
522
  subprocess.once("close", (exitCode) => {
432
- if (!options.allowNonzeroExitCode && exitCode > 0) {
523
+ if (!options.allowNonzeroExitCode && exitCode !== 0) {
433
524
  reject(new Error(`Exited with code ${exitCode}`));
434
525
  return;
435
526
  }
@@ -437,8 +528,30 @@ var baseOpen = async (options) => {
437
528
  });
438
529
  });
439
530
  }
531
+ if (isFallbackAttempt) {
532
+ return new Promise((resolve, reject) => {
533
+ subprocess.once("error", reject);
534
+ subprocess.once("spawn", () => {
535
+ subprocess.once("close", (exitCode) => {
536
+ subprocess.off("error", reject);
537
+ if (exitCode !== 0) {
538
+ reject(new Error(`Exited with code ${exitCode}`));
539
+ return;
540
+ }
541
+ subprocess.unref();
542
+ resolve(subprocess);
543
+ });
544
+ });
545
+ });
546
+ }
440
547
  subprocess.unref();
441
- return subprocess;
548
+ return new Promise((resolve, reject) => {
549
+ subprocess.once("error", reject);
550
+ subprocess.once("spawn", () => {
551
+ subprocess.off("error", reject);
552
+ resolve(subprocess);
553
+ });
554
+ });
442
555
  };
443
556
  var open = (target, options) => {
444
557
  if (typeof target !== "string") {
@@ -459,7 +572,7 @@ function detectArchBinary(binary) {
459
572
  }
460
573
  return archBinary;
461
574
  }
462
- function detectPlatformBinary({ [platform]: platformBinary }, { wsl }) {
575
+ function detectPlatformBinary({ [platform]: platformBinary }, { wsl } = {}) {
463
576
  if (wsl && is_wsl_default) {
464
577
  return detectArchBinary(wsl);
465
578
  }
@@ -468,11 +581,14 @@ function detectPlatformBinary({ [platform]: platformBinary }, { wsl }) {
468
581
  }
469
582
  return detectArchBinary(platformBinary);
470
583
  }
471
- var apps = {};
584
+ var apps = {
585
+ browser: "browser",
586
+ browserPrivate: "browserPrivate"
587
+ };
472
588
  defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
473
589
  darwin: "google chrome",
474
590
  win32: "chrome",
475
- linux: ["google-chrome", "google-chrome-stable", "chromium"]
591
+ linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
476
592
  }, {
477
593
  wsl: {
478
594
  ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
@@ -503,8 +619,9 @@ defineLazyProperty(apps, "edge", () => detectPlatformBinary({
503
619
  }, {
504
620
  wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
505
621
  }));
506
- defineLazyProperty(apps, "browser", () => "browser");
507
- defineLazyProperty(apps, "browserPrivate", () => "browserPrivate");
622
+ defineLazyProperty(apps, "safari", () => detectPlatformBinary({
623
+ darwin: "Safari"
624
+ }));
508
625
  var open_default = open;
509
626
 
510
627
  // src/errors.ts
@@ -675,6 +792,10 @@ class BunCallbackServer extends BaseCallbackServer {
675
792
  async stopServer() {
676
793
  if (!this.server)
677
794
  return;
795
+ while (this.server.pendingRequests > 0) {
796
+ await new Promise((resolve) => setTimeout(resolve, 10));
797
+ }
798
+ await new Promise((resolve) => setTimeout(resolve, 100));
678
799
  this.server.stop();
679
800
  this.server = undefined;
680
801
  }
@@ -725,6 +846,7 @@ class NodeCallbackServer extends BaseCallbackServer {
725
846
  async stopServer() {
726
847
  if (!this.server)
727
848
  return;
849
+ this.server.closeAllConnections();
728
850
  return new Promise((resolve) => {
729
851
  this.server?.close(() => {
730
852
  this.server = undefined;