opencode-qwen-oauth 1.0.0 → 1.1.0

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/bin/install.js CHANGED
@@ -2,13 +2,19 @@
2
2
 
3
3
  /**
4
4
  * Qwen OAuth Plugin Installer
5
- *
5
+ *
6
6
  * Usage:
7
7
  * npx opencode-qwen-oauth install
8
8
  * bunx opencode-qwen-oauth install
9
9
  */
10
10
 
11
- import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync } from "node:fs";
11
+ import {
12
+ readFileSync,
13
+ writeFileSync,
14
+ existsSync,
15
+ mkdirSync,
16
+ appendFileSync,
17
+ } from "node:fs";
12
18
  import { join } from "node:path";
13
19
  import { homedir } from "node:os";
14
20
 
@@ -64,8 +70,12 @@ function install() {
64
70
  ensureDir(opencodeDir);
65
71
 
66
72
  // Read or create config
67
- let config = { "$schema": "https://opencode.ai/config.json", plugin: [], provider: {} };
68
-
73
+ let config = {
74
+ $schema: "https://opencode.ai/config.json",
75
+ plugin: [],
76
+ provider: {},
77
+ };
78
+
69
79
  if (existsSync(configPath)) {
70
80
  try {
71
81
  const content = readFileSync(configPath, "utf-8");
@@ -123,7 +133,7 @@ function install() {
123
133
  // Install npm package in .opencode
124
134
  const opencodePackagePath = join(opencodeDir, "package.json");
125
135
  let opencodePackage = { dependencies: {} };
126
-
136
+
127
137
  if (existsSync(opencodePackagePath)) {
128
138
  try {
129
139
  opencodePackage = JSON.parse(readFileSync(opencodePackagePath, "utf-8"));
@@ -139,18 +149,22 @@ function install() {
139
149
  }
140
150
 
141
151
  try {
142
- writeFileSync(opencodePackagePath, JSON.stringify(opencodePackage, null, 2) + "\n", "utf-8");
152
+ writeFileSync(
153
+ opencodePackagePath,
154
+ JSON.stringify(opencodePackage, null, 2) + "\n",
155
+ "utf-8",
156
+ );
143
157
  } catch (e) {
144
158
  error(`Failed to write package.json: ${e.message}`);
145
159
  process.exit(1);
146
160
  }
147
161
 
148
- log("\n✅ Installation complete!");
149
- log("\nNext steps:");
150
- log(" 1. Run: opencode");
151
- log(" 2. Connect: /connect (select 'Qwen Code (qwen.ai OAuth)')");
152
- log(" 3. Use model: /model qwen/qwen3-coder-plus");
153
- log("\nDebug mode: QWEN_OAUTH_DEBUG=true opencode");
162
+ log("Installation complete!");
163
+ log("Next steps:");
164
+ log("1. Run: opencode");
165
+ log("2. Connect: /connect (select 'Qwen Code (qwen.ai OAuth)')");
166
+ log("3. Use model: /model qwen/qwen3-coder-plus");
167
+ log("Debug mode: QWEN_OAUTH_DEBUG=true opencode");
154
168
  }
155
169
 
156
170
  // ============================================
@@ -161,7 +175,7 @@ function uninstall() {
161
175
  log("Uninstalling Qwen OAuth plugin...");
162
176
 
163
177
  const configPath = getOpencodeConfigPath();
164
-
178
+
165
179
  if (!existsSync(configPath)) {
166
180
  log("No config file found, nothing to uninstall");
167
181
  return;
@@ -198,9 +212,9 @@ function uninstall() {
198
212
  process.exit(1);
199
213
  }
200
214
 
201
- log("\n✅ Uninstallation complete!");
215
+ log("Uninstallation complete!");
202
216
  log("Note: You may want to manually remove the npm package:");
203
- log(" npm uninstall opencode-qwen-auth");
217
+ log("npm uninstall opencode-qwen-auth");
204
218
  }
205
219
 
206
220
  // ============================================
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Browser utilities for opening URLs
3
+ */
4
+ export declare function openBrowser(url: string): void;
5
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAmB7C"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Browser utilities for opening URLs
3
+ */
4
+ import { spawn } from "node:child_process";
5
+ export function openBrowser(url) {
6
+ try {
7
+ const platform = process.platform;
8
+ const command = platform === "darwin"
9
+ ? "open"
10
+ : platform === "win32"
11
+ ? "rundll32"
12
+ : "xdg-open";
13
+ const args = platform === "win32" ? ["url.dll,FileProtocolHandler", url] : [url];
14
+ const child = spawn(command, args, {
15
+ stdio: "ignore",
16
+ detached: true,
17
+ });
18
+ child.unref?.();
19
+ }
20
+ catch {
21
+ // Ignore errors
22
+ }
23
+ }
24
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,MAAM,OAAO,GACX,QAAQ,KAAK,QAAQ;YACnB,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,QAAQ,KAAK,OAAO;gBACpB,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,UAAU,CAAC;QACnB,MAAM,IAAI,GACR,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACtE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACjC,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Constants for Qwen OAuth Plugin
3
+ */
4
+ export declare const QWEN_OAUTH_BASE_URL = "https://chat.qwen.ai";
5
+ export declare const QWEN_DEVICE_CODE_ENDPOINT = "/api/v1/oauth2/device/code";
6
+ export declare const QWEN_TOKEN_ENDPOINT = "/api/v1/oauth2/token";
7
+ export declare const QWEN_CLIENT_ID = "f0304373b74a44d2b584a3fb70ca9e56";
8
+ export declare const QWEN_SCOPES: string[];
9
+ export declare const QWEN_API_BASE_URL = "https://portal.qwen.ai/v1";
10
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAC1D,eAAO,MAAM,yBAAyB,+BAA+B,CAAC;AACtE,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAC1D,eAAO,MAAM,cAAc,qCAAqC,CAAC;AACjE,eAAO,MAAM,WAAW,UAAqD,CAAC;AAC9E,eAAO,MAAM,iBAAiB,8BAA8B,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Constants for Qwen OAuth Plugin
3
+ */
4
+ export const QWEN_OAUTH_BASE_URL = "https://chat.qwen.ai";
5
+ export const QWEN_DEVICE_CODE_ENDPOINT = "/api/v1/oauth2/device/code";
6
+ export const QWEN_TOKEN_ENDPOINT = "/api/v1/oauth2/token";
7
+ export const QWEN_CLIENT_ID = "f0304373b74a44d2b584a3fb70ca9e56";
8
+ export const QWEN_SCOPES = ["openid", "profile", "email", "model.completion"];
9
+ export const QWEN_API_BASE_URL = "https://portal.qwen.ai/v1";
10
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAAsB,CAAC;AAC1D,MAAM,CAAC,MAAM,yBAAyB,GAAG,4BAA4B,CAAC;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAAsB,CAAC;AAC1D,MAAM,CAAC,MAAM,cAAc,GAAG,kCAAkC,CAAC;AACjE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,iBAAiB,GAAG,2BAA2B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAkP/D,eAAO,MAAM,eAAe,EAAE,MAuF7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAM/D,eAAO,MAAM,eAAe,EAAE,MAiG7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -4,175 +4,16 @@
4
4
  *
5
5
  * @packageDocumentation
6
6
  */
7
- import { createHash, randomBytes } from "node:crypto";
8
- import { spawn } from "node:child_process";
9
- import { appendFileSync, mkdirSync, existsSync } from "node:fs";
10
- import { join } from "node:path";
11
- import { homedir } from "node:os";
12
- // ============================================
13
- // Constants
14
- // ============================================
15
- const QWEN_OAUTH_BASE_URL = "https://chat.qwen.ai";
16
- const QWEN_DEVICE_CODE_ENDPOINT = "/api/v1/oauth2/device/code";
17
- const QWEN_TOKEN_ENDPOINT = "/api/v1/oauth2/token";
18
- const QWEN_CLIENT_ID = "f0304373b74a44d2b584a3fb70ca9e56";
19
- const QWEN_SCOPES = ["openid", "profile", "email", "model.completion"];
20
- const QWEN_API_BASE_URL = "https://portal.qwen.ai/v1";
21
- // ============================================
22
- // Logging
23
- // ============================================
24
- function getLogDir() {
25
- const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
26
- return join(xdgConfig, "opencode", "logs");
27
- }
28
- function getLogFilePath() {
29
- return join(getLogDir(), "qwen-oauth.log");
30
- }
31
- function ensureLogDir() {
32
- const logDir = getLogDir();
33
- if (!existsSync(logDir)) {
34
- mkdirSync(logDir, { recursive: true, mode: 0o700 });
35
- }
36
- }
37
- function writeLog(message) {
38
- try {
39
- ensureLogDir();
40
- const timestamp = new Date().toISOString();
41
- const logLine = `[${timestamp}] ${message}\n`;
42
- appendFileSync(getLogFilePath(), logLine, { encoding: "utf-8" });
43
- }
44
- catch {
45
- // Silently ignore log write errors
46
- }
47
- }
48
- const DEBUG = process.env.QWEN_OAUTH_DEBUG === "true" || process.env.QWEN_OAUTH_DEBUG === "1";
49
- function debugLog(message, data) {
50
- const logMessage = data ? `${message} ${JSON.stringify(data)}` : message;
51
- writeLog(logMessage);
52
- if (DEBUG) {
53
- console.log(`[Qwen OAuth] ${message}`, data ? JSON.stringify(data, null, 2) : "");
54
- }
55
- }
56
- // ============================================
57
- // PKCE
58
- // ============================================
59
- function base64UrlEncode(buffer) {
60
- return buffer
61
- .toString("base64")
62
- .replace(/\+/g, "-")
63
- .replace(/\//g, "_")
64
- .replace(/=+$/, "");
65
- }
66
- function createPkcePair() {
67
- const verifier = base64UrlEncode(randomBytes(32));
68
- const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
69
- return { verifier, challenge };
70
- }
71
- // ============================================
72
- // Browser
73
- // ============================================
74
- function openBrowser(url) {
75
- try {
76
- const platform = process.platform;
77
- const command = platform === "darwin"
78
- ? "open"
79
- : platform === "win32"
80
- ? "rundll32"
81
- : "xdg-open";
82
- const args = platform === "win32"
83
- ? ["url.dll,FileProtocolHandler", url]
84
- : [url];
85
- const child = spawn(command, args, {
86
- stdio: "ignore",
87
- detached: true,
88
- });
89
- child.unref?.();
90
- }
91
- catch {
92
- // Ignore errors
93
- }
94
- }
95
- async function authorizeDevice() {
96
- const { verifier, challenge } = createPkcePair();
97
- const params = new URLSearchParams({
98
- client_id: QWEN_CLIENT_ID,
99
- scope: QWEN_SCOPES.join(" "),
100
- code_challenge: challenge,
101
- code_challenge_method: "S256",
7
+ import { QWEN_API_BASE_URL } from "./constants.js";
8
+ import { debugLog } from "./logger.js";
9
+ import { openBrowser } from "./browser.js";
10
+ import { authorizeDevice, pollForToken } from "./oauth.js";
11
+ export const QwenOAuthPlugin = async ({ project, client, $, directory, worktree, }) => {
12
+ debugLog("Plugin initialized", {
13
+ directory,
14
+ worktree,
15
+ project: project?.name || "N/A",
102
16
  });
103
- const response = await fetch(`${QWEN_OAUTH_BASE_URL}${QWEN_DEVICE_CODE_ENDPOINT}`, {
104
- method: "POST",
105
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
106
- body: params.toString(),
107
- });
108
- if (!response.ok) {
109
- throw new Error(`Failed to start device flow: ${response.statusText}`);
110
- }
111
- const data = (await response.json());
112
- return {
113
- device_code: data.device_code,
114
- user_code: data.user_code,
115
- verification_uri: data.verification_uri,
116
- verification_uri_complete: data.verification_uri_complete,
117
- expires_in: data.expires_in,
118
- interval: data.interval || 5,
119
- verifier,
120
- };
121
- }
122
- async function pollForToken(deviceCode, codeVerifier, intervalSeconds, expiresIn) {
123
- const timeoutMs = expiresIn * 1000;
124
- const startTime = Date.now();
125
- let currentInterval = intervalSeconds * 1000;
126
- debugLog("Starting token polling", { timeoutMs, interval: currentInterval });
127
- while (Date.now() - startTime < timeoutMs) {
128
- await new Promise((resolve) => setTimeout(resolve, currentInterval));
129
- const params = new URLSearchParams({
130
- client_id: QWEN_CLIENT_ID,
131
- grant_type: "urn:ietf:params:oauth:grant-type:device_code",
132
- device_code: deviceCode,
133
- code_verifier: codeVerifier,
134
- });
135
- debugLog("Polling for token...");
136
- const response = await fetch(`${QWEN_OAUTH_BASE_URL}${QWEN_TOKEN_ENDPOINT}`, {
137
- method: "POST",
138
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
139
- body: params.toString(),
140
- });
141
- if (response.ok) {
142
- const data = (await response.json());
143
- debugLog("Token received successfully");
144
- return {
145
- success: true,
146
- access_token: data.access_token,
147
- refresh_token: data.refresh_token,
148
- expires_in: data.expires_in,
149
- };
150
- }
151
- const error = (await response.json().catch(() => ({})));
152
- if (error.error === "authorization_pending") {
153
- debugLog("Authorization pending, retrying...");
154
- continue;
155
- }
156
- if (error.error === "slow_down") {
157
- currentInterval += 5000;
158
- debugLog("Server requested slow down, new interval:", { interval: currentInterval });
159
- continue;
160
- }
161
- if (error.error === "expired_token") {
162
- debugLog("Device code expired");
163
- return { success: false, error: "Device code expired. Please try again." };
164
- }
165
- debugLog(`Token polling failed: ${error.error_description || "unknown error"}`);
166
- return { success: false, error: error.error_description || "Authentication failed" };
167
- }
168
- debugLog("Polling timeout exceeded");
169
- return { success: false, error: "Polling timeout - device code expired" };
170
- }
171
- // ============================================
172
- // Plugin
173
- // ============================================
174
- export const QwenOAuthPlugin = async ({ project, client, $, directory, worktree }) => {
175
- debugLog("Plugin initialized", { directory, worktree, project: project?.name || "N/A" });
176
17
  return {
177
18
  auth: {
178
19
  provider: "qwen",
@@ -192,9 +33,6 @@ export const QwenOAuthPlugin = async ({ project, client, $, directory, worktree
192
33
  expires_in: device.expires_in,
193
34
  interval: device.interval,
194
35
  });
195
- // Show essential info to user
196
- console.log(`\n📱 Qwen OAuth: Visit ${url}`);
197
- console.log(`🔑 Enter code: ${device.user_code}\n`);
198
36
  return {
199
37
  url,
200
38
  instructions: `Enter code: ${device.user_code}`,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Logging utilities for Qwen OAuth Plugin
3
+ */
4
+ export declare const DEBUG: boolean;
5
+ export declare function debugLog(message: string, data?: Record<string, unknown>): void;
6
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiCH,eAAO,MAAM,KAAK,SAEoB,CAAC;AAEvC,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAG9E"}
package/dist/logger.js ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Logging utilities for Qwen OAuth Plugin
3
+ */
4
+ import { appendFileSync, mkdirSync, existsSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { homedir } from "node:os";
7
+ function getLogDir() {
8
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
9
+ return join(xdgConfig, "opencode", "logs");
10
+ }
11
+ function getLogFilePath() {
12
+ return join(getLogDir(), "qwen-oauth.log");
13
+ }
14
+ function ensureLogDir() {
15
+ const logDir = getLogDir();
16
+ if (!existsSync(logDir)) {
17
+ mkdirSync(logDir, { recursive: true, mode: 0o700 });
18
+ }
19
+ }
20
+ function writeLog(message) {
21
+ try {
22
+ ensureLogDir();
23
+ const timestamp = new Date().toISOString();
24
+ const logLine = `[${timestamp}] ${message}\n`;
25
+ appendFileSync(getLogFilePath(), logLine, { encoding: "utf-8" });
26
+ }
27
+ catch {
28
+ // Silently ignore log write errors
29
+ }
30
+ }
31
+ export const DEBUG = process.env.QWEN_OAUTH_DEBUG === "true" ||
32
+ process.env.QWEN_OAUTH_DEBUG === "1";
33
+ export function debugLog(message, data) {
34
+ const logMessage = data ? `${message} ${JSON.stringify(data)}` : message;
35
+ writeLog(logMessage);
36
+ }
37
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,SAAS,SAAS;IAChB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC5E,OAAO,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,cAAc;IACrB,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,IAAI,CAAC;QACH,YAAY,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAI,SAAS,KAAK,OAAO,IAAI,CAAC;QAC9C,cAAc,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;IACrC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAChB,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,MAAM;IACvC,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,GAAG,CAAC;AAEvC,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,IAA8B;IACtE,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;IACzE,QAAQ,CAAC,UAAU,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * OAuth Device Flow implementation for Qwen
3
+ */
4
+ export interface DeviceAuthorization {
5
+ device_code: string;
6
+ user_code: string;
7
+ verification_uri: string;
8
+ verification_uri_complete: string;
9
+ expires_in: number;
10
+ interval: number;
11
+ verifier: string;
12
+ }
13
+ export declare function authorizeDevice(): Promise<DeviceAuthorization>;
14
+ export declare function pollForToken(deviceCode: string, codeVerifier: string, intervalSeconds: number, expiresIn: number): Promise<{
15
+ success: boolean;
16
+ access_token?: string;
17
+ refresh_token?: string;
18
+ expires_in?: number;
19
+ error?: string;
20
+ }>;
21
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yBAAyB,EAAE,MAAM,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAiBD,wBAAsB,eAAe,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAiCpE;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA4ED"}
package/dist/oauth.js ADDED
@@ -0,0 +1,91 @@
1
+ /**
2
+ * OAuth Device Flow implementation for Qwen
3
+ */
4
+ import { QWEN_OAUTH_BASE_URL, QWEN_DEVICE_CODE_ENDPOINT, QWEN_TOKEN_ENDPOINT, QWEN_CLIENT_ID, QWEN_SCOPES, } from "./constants.js";
5
+ import { createPkcePair } from "./pkce.js";
6
+ import { debugLog } from "./logger.js";
7
+ export async function authorizeDevice() {
8
+ const { verifier, challenge } = createPkcePair();
9
+ const params = new URLSearchParams({
10
+ client_id: QWEN_CLIENT_ID,
11
+ scope: QWEN_SCOPES.join(" "),
12
+ code_challenge: challenge,
13
+ code_challenge_method: "S256",
14
+ });
15
+ const response = await fetch(`${QWEN_OAUTH_BASE_URL}${QWEN_DEVICE_CODE_ENDPOINT}`, {
16
+ method: "POST",
17
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
18
+ body: params.toString(),
19
+ });
20
+ if (!response.ok) {
21
+ throw new Error(`Failed to start device flow: ${response.statusText}`);
22
+ }
23
+ const data = (await response.json());
24
+ return {
25
+ device_code: data.device_code,
26
+ user_code: data.user_code,
27
+ verification_uri: data.verification_uri,
28
+ verification_uri_complete: data.verification_uri_complete,
29
+ expires_in: data.expires_in,
30
+ interval: data.interval || 5,
31
+ verifier,
32
+ };
33
+ }
34
+ export async function pollForToken(deviceCode, codeVerifier, intervalSeconds, expiresIn) {
35
+ const timeoutMs = expiresIn * 1000;
36
+ const startTime = Date.now();
37
+ let currentInterval = intervalSeconds * 1000;
38
+ debugLog("Starting token polling", { timeoutMs, interval: currentInterval });
39
+ while (Date.now() - startTime < timeoutMs) {
40
+ await new Promise((resolve) => setTimeout(resolve, currentInterval));
41
+ const params = new URLSearchParams({
42
+ client_id: QWEN_CLIENT_ID,
43
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
44
+ device_code: deviceCode,
45
+ code_verifier: codeVerifier,
46
+ });
47
+ debugLog("Polling for token...");
48
+ const response = await fetch(`${QWEN_OAUTH_BASE_URL}${QWEN_TOKEN_ENDPOINT}`, {
49
+ method: "POST",
50
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
51
+ body: params.toString(),
52
+ });
53
+ if (response.ok) {
54
+ const data = (await response.json());
55
+ debugLog("Token received successfully");
56
+ return {
57
+ success: true,
58
+ access_token: data.access_token,
59
+ refresh_token: data.refresh_token,
60
+ expires_in: data.expires_in,
61
+ };
62
+ }
63
+ const error = (await response.json().catch(() => ({})));
64
+ if (error.error === "authorization_pending") {
65
+ debugLog("Authorization pending, retrying...");
66
+ continue;
67
+ }
68
+ if (error.error === "slow_down") {
69
+ currentInterval += 5000;
70
+ debugLog("Server requested slow down, new interval:", {
71
+ interval: currentInterval,
72
+ });
73
+ continue;
74
+ }
75
+ if (error.error === "expired_token") {
76
+ debugLog("Device code expired");
77
+ return {
78
+ success: false,
79
+ error: "Device code expired. Please try again.",
80
+ };
81
+ }
82
+ debugLog(`Token polling failed: ${error.error_description || "unknown error"}`);
83
+ return {
84
+ success: false,
85
+ error: error.error_description || "Authentication failed",
86
+ };
87
+ }
88
+ debugLog("Polling timeout exceeded");
89
+ return { success: false, error: "Polling timeout - device code expired" };
90
+ }
91
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
package/dist/pkce.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * PKCE (Proof Key for Code Exchange) utilities
3
+ */
4
+ export declare function createPkcePair(): {
5
+ verifier: string;
6
+ challenge: string;
7
+ };
8
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../src/pkce.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,wBAAgB,cAAc,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAMxE"}
package/dist/pkce.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * PKCE (Proof Key for Code Exchange) utilities
3
+ */
4
+ import { createHash, randomBytes } from "node:crypto";
5
+ function base64UrlEncode(buffer) {
6
+ return buffer
7
+ .toString("base64")
8
+ .replace(/\+/g, "-")
9
+ .replace(/\//g, "_")
10
+ .replace(/=+$/, "");
11
+ }
12
+ export function createPkcePair() {
13
+ const verifier = base64UrlEncode(randomBytes(32));
14
+ const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
15
+ return { verifier, challenge };
16
+ }
17
+ //# sourceMappingURL=pkce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../src/pkce.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,SAAS,eAAe,CAAC,MAAc;IACrC,OAAO,MAAM;SACV,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,eAAe,CAC/B,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAC/C,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-qwen-oauth",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Qwen OAuth authentication plugin for OpenCode - authenticate with Qwen.ai using OAuth device flow",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",