@openai-oauth/web 2.0.0-beta.2 → 2.0.0-beta.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
@@ -26,9 +26,9 @@ await fetch("/api/chat", {
26
26
 
27
27
  ### Hosted Sign-in
28
28
 
29
- Hosted browser sign-in uses the open-source [Sign in with ChatGPT Chrome extension](https://chromewebstore.google.com/detail/sign-in-with-chatgpt/odbgboachaefbbbdiffcefhpkekhfcna) to complete OpenAI's local OAuth callback. The extension shows the destination app for confirmation and then returns the callback directly to it.
29
+ Hosted browser sign-in uses the open-source Sign in with ChatGPT extension for [Chrome](https://chromewebstore.google.com/detail/sign-in-with-chatgpt/odbgboachaefbbbdiffcefhpkekhfcna) or [Firefox](https://addons.mozilla.org/firefox/addon/sign-in-with-chatgpt/) to complete OpenAI's local OAuth callback. The extension shows the destination app for confirmation and then returns the callback directly to it.
30
30
 
31
- `startLogin()` uses this extension flow by default. When installation is needed, it returns the official Chrome Web Store URL for your interface to display:
31
+ `startLogin()` uses this extension flow by default. When installation is needed, it returns the correct Chrome Web Store or Firefox Add-ons URL for your interface to display:
32
32
 
33
33
  ```ts
34
34
  import { startLogin } from "@openai-oauth/web";
@@ -43,7 +43,7 @@ if (result.status === "needs-extension") {
43
43
 
44
44
  After installation, call `startLogin()` again when the user returns to your app or presses Sign in again. It will start OAuth once the extension is available.
45
45
 
46
- The extension uses a single static redirect for `http://localhost:1455/auth/callback`. After the user confirms the destination, call `completeLogin()` on the returned app URL to exchange the code and save the browser session.
46
+ The extension redirects only `http://localhost:1455/auth/callback`. After the user confirms the destination, call `completeLogin()` on the returned app URL to exchange the code and save the browser session.
47
47
 
48
48
  `startLogin()` returns `{ status: "started" }` when OAuth begins or `{ status: "needs-extension", installUrl }` when your interface should show installation UI. Provide an explicit `redirectUri` only when your environment handles its own registered callback without the extension.
49
49
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -10,7 +10,10 @@ const browserExtensionStatePrefix = "oo2_";
10
10
  const browserExtensionRedirectUri = "http://localhost:1455/auth/callback";
11
11
  const browserExtensionId = "odbgboachaefbbbdiffcefhpkekhfcna";
12
12
  const browserExtensionInstalledPath = "src/installed.json";
13
- const browserExtensionInstallUrl = "https://chromewebstore.google.com/detail/sign-in-with-chatgpt/odbgboachaefbbbdiffcefhpkekhfcna";
13
+ const chromeExtensionInstallUrl = "https://chromewebstore.google.com/detail/sign-in-with-chatgpt/odbgboachaefbbbdiffcefhpkekhfcna";
14
+ const firefoxExtensionInstallUrl = "https://addons.mozilla.org/firefox/addon/sign-in-with-chatgpt/";
15
+ const firefoxExtensionDetectionUrl = "http://localhost:1455/openai-oauth/installed";
16
+ const browserExtensionMarkerType = "openai-oauth:browser-extension-installed";
14
17
  const browserExtensionDetectionTimeoutMs = 750;
15
18
  const refreshExpiryMarginMs = 5 * 60 * 1000;
16
19
  const refreshIntervalMs = 55 * 60 * 1000;
@@ -28,7 +31,9 @@ const assertBrowserWindow = () => {
28
31
  }
29
32
  return window;
30
33
  };
31
- const isBrowserExtensionInstalled = async () => {
34
+ const isFirefox = () => typeof navigator !== "undefined" &&
35
+ navigator.userAgent.toLowerCase().includes("firefox/");
36
+ const isChromeExtensionInstalled = async () => {
32
37
  const fetchImpl = globalThis.fetch;
33
38
  if (!fetchImpl) {
34
39
  return false;
@@ -57,6 +62,52 @@ const isBrowserExtensionInstalled = async () => {
57
62
  }
58
63
  }
59
64
  };
65
+ const isFirefoxExtensionInstalled = (browserWindow) => new Promise((resolve) => {
66
+ const document = browserWindow.document;
67
+ const parent = document?.body ?? document?.documentElement;
68
+ if (!document?.createElement || !parent) {
69
+ resolve(false);
70
+ return;
71
+ }
72
+ const iframe = document.createElement("iframe");
73
+ iframe.hidden = true;
74
+ iframe.setAttribute("aria-hidden", "true");
75
+ iframe.src = firefoxExtensionDetectionUrl;
76
+ let settled = false;
77
+ const finish = (installed) => {
78
+ if (settled) {
79
+ return;
80
+ }
81
+ settled = true;
82
+ globalThis.clearTimeout(timeout);
83
+ browserWindow.removeEventListener("message", onMessage);
84
+ iframe.remove();
85
+ resolve(installed);
86
+ };
87
+ const onMessage = (event) => {
88
+ const data = event.data;
89
+ if (event.source === iframe.contentWindow &&
90
+ event.origin.startsWith("moz-extension://") &&
91
+ data?.type === browserExtensionMarkerType &&
92
+ data.name === "sign-in-with-chatgpt" &&
93
+ data.protocol === "openai-oauth-browser-extension" &&
94
+ data.protocolVersion === 1) {
95
+ finish(true);
96
+ }
97
+ };
98
+ const timeout = globalThis.setTimeout(() => finish(false), browserExtensionDetectionTimeoutMs);
99
+ browserWindow.addEventListener("message", onMessage);
100
+ parent.appendChild(iframe);
101
+ });
102
+ const getBrowserExtension = (browserWindow) => isFirefox()
103
+ ? {
104
+ installUrl: firefoxExtensionInstallUrl,
105
+ isInstalled: () => isFirefoxExtensionInstalled(browserWindow),
106
+ }
107
+ : {
108
+ installUrl: chromeExtensionInstallUrl,
109
+ isInstalled: isChromeExtensionInstalled,
110
+ };
60
111
  const requestToPromise = (request) => new Promise((resolve, reject) => {
61
112
  request.onsuccess = () => resolve(request.result);
62
113
  request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed."));
@@ -370,10 +421,11 @@ const createBrowserExtensionState = (callbackUrl, appState) => {
370
421
  export const startLogin = async (options = {}) => {
371
422
  const browserWindow = assertBrowserWindow();
372
423
  const usesBrowserExtension = options.redirectUri === undefined;
373
- if (usesBrowserExtension && !(await isBrowserExtensionInstalled())) {
424
+ const browserExtension = getBrowserExtension(browserWindow);
425
+ if (usesBrowserExtension && !(await browserExtension.isInstalled())) {
374
426
  return {
375
427
  status: "needs-extension",
376
- installUrl: browserExtensionInstallUrl,
428
+ installUrl: browserExtension.installUrl,
377
429
  };
378
430
  }
379
431
  const returnTo = options.returnTo ?? getCurrentRelativeUrl();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openai-oauth/web",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.3",
4
4
  "description": "Browser credential storage and web utilities for openai-oauth.",
5
5
  "keywords": [
6
6
  "openai",
@@ -41,7 +41,7 @@
41
41
  "access": "public"
42
42
  },
43
43
  "dependencies": {
44
- "@openai-oauth/core": "2.0.0-beta.2"
44
+ "@openai-oauth/core": "2.0.0-beta.3"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/node": "20.17.24",