opencode-qwen-oauth 1.1.0 → 2.0.1

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/dist/retry.js ADDED
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Retry logic with exponential backoff for network requests
3
+ */
4
+ import { NetworkError, isRecoverableError } from "./errors.js";
5
+ import { debugLog } from "./logger.js";
6
+ const defaultOptions = {
7
+ maxRetries: 3,
8
+ baseDelay: 1000,
9
+ maxDelay: 30000,
10
+ timeout: 30000,
11
+ };
12
+ /**
13
+ * Retry a function with exponential backoff
14
+ */
15
+ export async function retryWithBackoff(fn, options = {}) {
16
+ const opts = { ...defaultOptions, ...options };
17
+ let lastError;
18
+ for (let attempt = 0; attempt < opts.maxRetries; attempt++) {
19
+ try {
20
+ debugLog(`Attempt ${attempt + 1}/${opts.maxRetries}`);
21
+ // Add timeout wrapper
22
+ const result = await Promise.race([
23
+ fn(),
24
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Request timeout")), opts.timeout)),
25
+ ]);
26
+ debugLog(`Attempt ${attempt + 1} succeeded`);
27
+ return result;
28
+ }
29
+ catch (error) {
30
+ lastError = error instanceof Error ? error : new Error(String(error));
31
+ // Don't retry if error is not recoverable
32
+ if (!isRecoverableError(error)) {
33
+ debugLog(`Non-recoverable error, not retrying: ${lastError.message}`);
34
+ throw lastError;
35
+ }
36
+ // Don't retry on last attempt
37
+ if (attempt === opts.maxRetries - 1) {
38
+ debugLog(`Max retries (${opts.maxRetries}) reached`);
39
+ break;
40
+ }
41
+ // Calculate delay with exponential backoff and jitter
42
+ const exponentialDelay = opts.baseDelay * Math.pow(2, attempt);
43
+ const jitter = Math.random() * 0.1 * exponentialDelay; // 10% jitter
44
+ const delay = Math.min(exponentialDelay + jitter, opts.maxDelay);
45
+ debugLog(`Retrying in ${Math.round(delay)}ms...`, {
46
+ attempt: attempt + 1,
47
+ error: lastError.message,
48
+ });
49
+ await new Promise((resolve) => setTimeout(resolve, delay));
50
+ }
51
+ }
52
+ throw new NetworkError(`Failed after ${opts.maxRetries} retries: ${lastError?.message}`);
53
+ }
54
+ /**
55
+ * Retry fetch with exponential backoff
56
+ */
57
+ export async function fetchWithRetry(url, init, options = {}) {
58
+ return retryWithBackoff(async () => {
59
+ const response = await fetch(url, init);
60
+ // Throw on HTTP errors for retry logic
61
+ if (!response.ok) {
62
+ // Check for rate limiting
63
+ if (response.status === 429) {
64
+ const retryAfter = response.headers.get("Retry-After");
65
+ const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : 60000;
66
+ throw new NetworkError(`Rate limited (429)`, `Rate limit exceeded. Please wait ${Math.ceil(waitTime / 1000)} seconds.`);
67
+ }
68
+ // Other HTTP errors
69
+ throw new NetworkError(`HTTP ${response.status}: ${response.statusText}`);
70
+ }
71
+ return response;
72
+ }, options);
73
+ }
74
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Input validation and security utilities
3
+ */
4
+ /**
5
+ * Validate URL is HTTPS and from qwen.ai domain
6
+ */
7
+ export declare function validateQwenUrl(url: string): boolean;
8
+ /**
9
+ * Validate device code format
10
+ */
11
+ export declare function validateDeviceCode(code: string): void;
12
+ /**
13
+ * Validate user code format
14
+ */
15
+ export declare function validateUserCode(code: string): void;
16
+ /**
17
+ * Validate access token format
18
+ */
19
+ export declare function validateToken(token: string): void;
20
+ /**
21
+ * Validate expires_in value
22
+ */
23
+ export declare function validateExpiresIn(expiresIn: number): void;
24
+ /**
25
+ * Validate interval for polling
26
+ */
27
+ export declare function validateInterval(interval: number): void;
28
+ /**
29
+ * Sanitize log data by removing sensitive fields
30
+ */
31
+ export declare function sanitizeLogData(data: any): any;
32
+ /**
33
+ * Validate OAuth error response
34
+ */
35
+ export declare function validateOAuthError(error: any): {
36
+ error: string;
37
+ error_description?: string;
38
+ };
39
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAYpD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAOrD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQnD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAOjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAQzD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAQvD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CA8B9C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAWA"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Input validation and security utilities
3
+ */
4
+ import { ValidationError } from "./errors.js";
5
+ /**
6
+ * Validate URL is HTTPS and from qwen.ai domain
7
+ */
8
+ export function validateQwenUrl(url) {
9
+ try {
10
+ const parsed = new URL(url);
11
+ return (parsed.protocol === "https:" &&
12
+ (parsed.hostname === "chat.qwen.ai" ||
13
+ parsed.hostname === "portal.qwen.ai" ||
14
+ parsed.hostname.endsWith(".qwen.ai")));
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ /**
21
+ * Validate device code format
22
+ */
23
+ export function validateDeviceCode(code) {
24
+ if (!code || typeof code !== "string") {
25
+ throw new ValidationError("Device code must be a non-empty string", "device_code");
26
+ }
27
+ if (code.length < 10 || code.length > 100) {
28
+ throw new ValidationError("Device code has invalid length", "device_code");
29
+ }
30
+ }
31
+ /**
32
+ * Validate user code format
33
+ */
34
+ export function validateUserCode(code) {
35
+ if (!code || typeof code !== "string") {
36
+ throw new ValidationError("User code must be a non-empty string", "user_code");
37
+ }
38
+ // User codes are typically short alphanumeric codes
39
+ if (!/^[A-Z0-9-]{4,12}$/i.test(code)) {
40
+ throw new ValidationError("User code has invalid format", "user_code");
41
+ }
42
+ }
43
+ /**
44
+ * Validate access token format
45
+ */
46
+ export function validateToken(token) {
47
+ if (!token || typeof token !== "string") {
48
+ throw new ValidationError("Token must be a non-empty string", "token");
49
+ }
50
+ if (token.length < 20) {
51
+ throw new ValidationError("Token is too short", "token");
52
+ }
53
+ }
54
+ /**
55
+ * Validate expires_in value
56
+ */
57
+ export function validateExpiresIn(expiresIn) {
58
+ if (!Number.isInteger(expiresIn) || expiresIn <= 0) {
59
+ throw new ValidationError("expires_in must be a positive integer", "expires_in");
60
+ }
61
+ // Sanity check: shouldn't be more than 1 year
62
+ if (expiresIn > 365 * 24 * 60 * 60) {
63
+ throw new ValidationError("expires_in value is unreasonably large", "expires_in");
64
+ }
65
+ }
66
+ /**
67
+ * Validate interval for polling
68
+ */
69
+ export function validateInterval(interval) {
70
+ if (!Number.isInteger(interval) || interval <= 0) {
71
+ throw new ValidationError("Interval must be a positive integer", "interval");
72
+ }
73
+ // Minimum 1 second, maximum 60 seconds
74
+ if (interval < 1 || interval > 60) {
75
+ throw new ValidationError("Interval must be between 1 and 60 seconds", "interval");
76
+ }
77
+ }
78
+ /**
79
+ * Sanitize log data by removing sensitive fields
80
+ */
81
+ export function sanitizeLogData(data) {
82
+ if (!data || typeof data !== "object") {
83
+ return data;
84
+ }
85
+ const sensitiveFields = [
86
+ "access_token",
87
+ "refresh_token",
88
+ "api_key",
89
+ "apiKey",
90
+ "secret",
91
+ "password",
92
+ "verifier",
93
+ "device_code",
94
+ ];
95
+ const sanitized = Array.isArray(data) ? [] : {};
96
+ for (const [key, value] of Object.entries(data)) {
97
+ const lowerKey = key.toLowerCase();
98
+ if (sensitiveFields.some((field) => lowerKey.includes(field))) {
99
+ sanitized[key] = "[REDACTED]";
100
+ }
101
+ else if (value && typeof value === "object") {
102
+ sanitized[key] = sanitizeLogData(value);
103
+ }
104
+ else {
105
+ sanitized[key] = value;
106
+ }
107
+ }
108
+ return sanitized;
109
+ }
110
+ /**
111
+ * Validate OAuth error response
112
+ */
113
+ export function validateOAuthError(error) {
114
+ if (!error || typeof error !== "object") {
115
+ throw new ValidationError("Invalid OAuth error response");
116
+ }
117
+ if (!error.error || typeof error.error !== "string") {
118
+ throw new ValidationError("OAuth error must have an error field");
119
+ }
120
+ return {
121
+ error: error.error,
122
+ error_description: error.error_description,
123
+ };
124
+ }
125
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "opencode-qwen-oauth",
3
- "version": "1.1.0",
3
+ "version": "2.0.1",
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",
7
7
  "types": "dist/index.d.ts",
8
8
  "bin": {
9
- "opencode-qwen-oauth": "./bin/install.js"
9
+ "opencode-qwen-oauth": "bin/install.js"
10
10
  },
11
11
  "files": [
12
12
  "dist",
@@ -18,7 +18,8 @@
18
18
  "build": "tsc -p tsconfig.json",
19
19
  "dev": "tsc -p tsconfig.json --watch",
20
20
  "prepublishOnly": "npm run build",
21
- "test": "echo \"No tests specified\" && exit 0"
21
+ "test": "bun test",
22
+ "test:watch": "bun test --watch"
22
23
  },
23
24
  "keywords": [
24
25
  "opencode",
@@ -33,7 +34,7 @@
33
34
  "license": "MIT",
34
35
  "repository": {
35
36
  "type": "git",
36
- "url": "https://github.com/yourusername/opencode-qwen-oauth.git"
37
+ "url": "git+https://github.com/yourusername/opencode-qwen-oauth.git"
37
38
  },
38
39
  "bugs": {
39
40
  "url": "https://github.com/yourusername/opencode-qwen-oauth/issues"