n8n-nodes-github-copilot 3.31.31 → 3.32.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/credentials/GitHubCopilotApi.credentials.d.ts +2 -2
- package/dist/credentials/GitHubCopilotApi.credentials.js +38 -38
- package/dist/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.js +15 -8
- package/dist/nodes/GitHubCopilotOpenAI/GitHubCopilotOpenAI.node.js +12 -0
- package/dist/package.json +1 -1
- package/dist/shared/utils/GitHubCopilotApiUtils.d.ts +5 -0
- package/dist/shared/utils/GitHubCopilotApiUtils.js +25 -6
- package/dist/shared/utils/OAuthTokenManager.d.ts +19 -0
- package/dist/shared/utils/OAuthTokenManager.js +121 -0
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ICredentialType, INodeProperties, ICredentialTestRequest,
|
|
1
|
+
import { ICredentialType, INodeProperties, ICredentialTestRequest, IHttpRequestOptions, ICredentialDataDecryptedObject } from "n8n-workflow";
|
|
2
2
|
export declare class GitHubCopilotApi implements ICredentialType {
|
|
3
3
|
name: string;
|
|
4
4
|
displayName: string;
|
|
5
5
|
documentationUrl: string;
|
|
6
6
|
properties: INodeProperties[];
|
|
7
|
-
authenticate:
|
|
7
|
+
authenticate(credentials: ICredentialDataDecryptedObject, requestOptions: IHttpRequestOptions): Promise<IHttpRequestOptions>;
|
|
8
8
|
test: ICredentialTestRequest;
|
|
9
9
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GitHubCopilotApi = void 0;
|
|
4
4
|
const GitHubCopilotEndpoints_1 = require("../shared/utils/GitHubCopilotEndpoints");
|
|
5
|
+
const OAuthTokenManager_1 = require("../shared/utils/OAuthTokenManager");
|
|
5
6
|
class GitHubCopilotApi {
|
|
6
7
|
constructor() {
|
|
7
8
|
this.name = "githubCopilotApi";
|
|
@@ -9,34 +10,20 @@ class GitHubCopilotApi {
|
|
|
9
10
|
this.documentationUrl = "https://docs.github.com/en/copilot/github-copilot-chat/copilot-chat-in-ides/using-github-copilot-chat-in-your-ide";
|
|
10
11
|
this.properties = [
|
|
11
12
|
{
|
|
12
|
-
displayName: "
|
|
13
|
-
name: "
|
|
13
|
+
displayName: "Setup Instructions",
|
|
14
|
+
name: "setupNotice",
|
|
14
15
|
type: "notice",
|
|
15
|
-
default: ""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
type: "notice",
|
|
27
|
-
default: "Add a new workflow and insert the 'GitHub Copilot Auth Helper' trigger node.",
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
displayName: "▶️ Step 2: Activate & Access",
|
|
31
|
-
name: "helperNotice3",
|
|
32
|
-
type: "notice",
|
|
33
|
-
default: "Activate the workflow, then click 'Test workflow' to open the visual token generator in your browser.",
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
displayName: "📋 Step 3: Copy Token",
|
|
37
|
-
name: "helperNotice4",
|
|
38
|
-
type: "notice",
|
|
39
|
-
default: "Follow the on-screen instructions to authenticate with GitHub and copy the generated 'gho_' token back here.",
|
|
16
|
+
default: "ℹ️ Auto OAuth Token Generation\n" +
|
|
17
|
+
"Your GitHub CLI token will be used to automatically generate OAuth tokens. Tokens are cached and refreshed automatically before expiration (every ~20 minutes). No manual intervention needed!\n\n" +
|
|
18
|
+
"⚠️ IMPORTANT: GitHub CLI Token Required\n\n" +
|
|
19
|
+
"🚀 Don't have GitHub CLI installed?\n" +
|
|
20
|
+
"Use the visual 'GitHub Copilot Auth Helper' node to generate your token without touching the terminal!\n\n" +
|
|
21
|
+
"📝 Step 1: Create Helper Workflow\n" +
|
|
22
|
+
"Add a new workflow and insert the 'GitHub Copilot Auth Helper' trigger node.\n\n" +
|
|
23
|
+
"▶️ Step 2: Activate & Access\n" +
|
|
24
|
+
"Activate the workflow, then click 'Test workflow' to open the visual token generator in your browser.\n\n" +
|
|
25
|
+
"📋 Step 3: Copy Token\n" +
|
|
26
|
+
"Follow the on-screen instructions to authenticate with GitHub and copy the generated 'gho_' token back here.",
|
|
40
27
|
},
|
|
41
28
|
{
|
|
42
29
|
displayName: "GitHub CLI Token",
|
|
@@ -47,20 +34,10 @@ class GitHubCopilotApi {
|
|
|
47
34
|
},
|
|
48
35
|
default: "",
|
|
49
36
|
required: true,
|
|
50
|
-
description: "Token generated by GitHub CLI (starts with 'gho_').
|
|
37
|
+
description: "Token generated by GitHub CLI (starts with 'gho_'). OAuth tokens will be auto-generated and refreshed from this token.",
|
|
51
38
|
placeholder: "gho_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
|
52
39
|
},
|
|
53
40
|
];
|
|
54
|
-
this.authenticate = {
|
|
55
|
-
type: "generic",
|
|
56
|
-
properties: {
|
|
57
|
-
headers: {
|
|
58
|
-
Authorization: "=Bearer {{$credentials.token}}",
|
|
59
|
-
Accept: "application/json",
|
|
60
|
-
"Content-Type": "application/json",
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
41
|
this.test = {
|
|
65
42
|
request: {
|
|
66
43
|
baseURL: GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.BASE_URL,
|
|
@@ -69,5 +46,28 @@ class GitHubCopilotApi {
|
|
|
69
46
|
},
|
|
70
47
|
};
|
|
71
48
|
}
|
|
49
|
+
async authenticate(credentials, requestOptions) {
|
|
50
|
+
const githubToken = credentials.token;
|
|
51
|
+
if (!githubToken) {
|
|
52
|
+
throw new Error("GitHub CLI token is required");
|
|
53
|
+
}
|
|
54
|
+
if (!githubToken.startsWith("gho_")) {
|
|
55
|
+
throw new Error("Invalid token format. GitHub CLI token must start with 'gho_'");
|
|
56
|
+
}
|
|
57
|
+
let authToken;
|
|
58
|
+
try {
|
|
59
|
+
authToken = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
throw new Error(`Failed to generate OAuth token: ${error instanceof Error ? error.message : String(error)}`);
|
|
63
|
+
}
|
|
64
|
+
if (!requestOptions.headers) {
|
|
65
|
+
requestOptions.headers = {};
|
|
66
|
+
}
|
|
67
|
+
requestOptions.headers.Authorization = `Bearer ${authToken}`;
|
|
68
|
+
requestOptions.headers.Accept = "application/json";
|
|
69
|
+
requestOptions.headers["Content-Type"] = "application/json";
|
|
70
|
+
return requestOptions;
|
|
71
|
+
}
|
|
72
72
|
}
|
|
73
73
|
exports.GitHubCopilotApi = GitHubCopilotApi;
|
|
@@ -31,7 +31,7 @@ class GitHubCopilotChatAPI {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
async execute() {
|
|
34
|
-
var _a, _b, _c, _d;
|
|
34
|
+
var _a, _b, _c, _d, _e, _f;
|
|
35
35
|
const items = this.getInputData();
|
|
36
36
|
const returnData = [];
|
|
37
37
|
for (let i = 0; i < items.length; i++) {
|
|
@@ -109,34 +109,41 @@ class GitHubCopilotChatAPI {
|
|
|
109
109
|
const hasMedia = includeMedia;
|
|
110
110
|
let response = null;
|
|
111
111
|
let attempt = 1;
|
|
112
|
-
|
|
112
|
+
const totalAttempts = maxRetries + 1;
|
|
113
|
+
let retriesUsed = 0;
|
|
114
|
+
while (attempt <= totalAttempts) {
|
|
113
115
|
try {
|
|
114
116
|
response = await (0, utils_1.makeApiRequest)(this, GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ENDPOINTS.CHAT_COMPLETIONS, requestBody, hasMedia);
|
|
117
|
+
retriesUsed = ((_a = response._retryMetadata) === null || _a === void 0 ? void 0 : _a.retries) || 0;
|
|
118
|
+
attempt = ((_b = response._retryMetadata) === null || _b === void 0 ? void 0 : _b.attempts) || 1;
|
|
115
119
|
break;
|
|
116
120
|
}
|
|
117
121
|
catch (error) {
|
|
118
|
-
const isLastAttempt = attempt >=
|
|
122
|
+
const isLastAttempt = attempt >= totalAttempts;
|
|
119
123
|
const errorObj = error;
|
|
120
|
-
const is403Error = errorObj.status === 403 || ((
|
|
124
|
+
const is403Error = errorObj.status === 403 || ((_c = errorObj.message) === null || _c === void 0 ? void 0 : _c.includes("403"));
|
|
121
125
|
if (is403Error && enableRetry && !isLastAttempt) {
|
|
122
126
|
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000);
|
|
123
|
-
console.log(`GitHub Copilot API attempt ${attempt} failed with 403, retrying in ${delay}ms...`);
|
|
127
|
+
console.log(`GitHub Copilot API attempt ${attempt}/${totalAttempts} failed with 403, retrying in ${delay}ms...`);
|
|
124
128
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
125
129
|
attempt++;
|
|
126
130
|
continue;
|
|
127
131
|
}
|
|
132
|
+
retriesUsed = attempt - 1;
|
|
128
133
|
throw error;
|
|
129
134
|
}
|
|
130
135
|
}
|
|
131
136
|
if (!response) {
|
|
132
|
-
throw new Error(
|
|
137
|
+
throw new Error(`Failed to get response from GitHub Copilot API after ${totalAttempts} attempts (${retriesUsed} retries)`);
|
|
133
138
|
}
|
|
134
139
|
const result = {
|
|
135
|
-
message: ((
|
|
140
|
+
message: ((_e = (_d = response.choices[0]) === null || _d === void 0 ? void 0 : _d.message) === null || _e === void 0 ? void 0 : _e.content) || "",
|
|
136
141
|
model,
|
|
137
142
|
operation,
|
|
138
143
|
usage: response.usage || null,
|
|
139
|
-
finish_reason: ((
|
|
144
|
+
finish_reason: ((_f = response.choices[0]) === null || _f === void 0 ? void 0 : _f.finish_reason) || "unknown",
|
|
145
|
+
retries: retriesUsed,
|
|
146
|
+
attempts: attempt,
|
|
140
147
|
};
|
|
141
148
|
returnData.push({
|
|
142
149
|
json: result,
|
|
@@ -30,6 +30,7 @@ class GitHubCopilotOpenAI {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
async execute() {
|
|
33
|
+
var _a, _b;
|
|
33
34
|
const items = this.getInputData();
|
|
34
35
|
const returnData = [];
|
|
35
36
|
for (let i = 0; i < items.length; i++) {
|
|
@@ -163,6 +164,11 @@ class GitHubCopilotOpenAI {
|
|
|
163
164
|
requestBody.seed = seed;
|
|
164
165
|
}
|
|
165
166
|
const response = await (0, utils_1.makeApiRequest)(this, GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ENDPOINTS.CHAT_COMPLETIONS, requestBody, false);
|
|
167
|
+
const retriesUsed = ((_a = response._retryMetadata) === null || _a === void 0 ? void 0 : _a.retries) || 0;
|
|
168
|
+
const attemptsUsed = ((_b = response._retryMetadata) === null || _b === void 0 ? void 0 : _b.attempts) || 1;
|
|
169
|
+
if (retriesUsed > 0) {
|
|
170
|
+
console.log(`ℹ️ Request completed after ${attemptsUsed} attempts (${retriesUsed} retries)`);
|
|
171
|
+
}
|
|
166
172
|
const cleanJsonFromMarkdown = (content) => {
|
|
167
173
|
if (!content || typeof content !== 'string') {
|
|
168
174
|
return content;
|
|
@@ -230,6 +236,12 @@ class GitHubCopilotOpenAI {
|
|
|
230
236
|
completion_tokens: 0,
|
|
231
237
|
total_tokens: 0,
|
|
232
238
|
},
|
|
239
|
+
...(retriesUsed > 0 && {
|
|
240
|
+
_retry_info: {
|
|
241
|
+
attempts: attemptsUsed,
|
|
242
|
+
retries: retriesUsed,
|
|
243
|
+
}
|
|
244
|
+
}),
|
|
233
245
|
};
|
|
234
246
|
returnData.push({
|
|
235
247
|
json: openAIResponse,
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-github-copilot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.32.1",
|
|
4
4
|
"description": "n8n community node for GitHub Copilot with CLI integration, Chat API access, and AI Chat Model for workflows - access GPT-5, Claude, Gemini and more using your Copilot subscription",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",
|
|
@@ -10,8 +10,9 @@ exports.estimateTokens = estimateTokens;
|
|
|
10
10
|
exports.validateTokenLimit = validateTokenLimit;
|
|
11
11
|
exports.truncateToTokenLimit = truncateToTokenLimit;
|
|
12
12
|
const GitHubCopilotEndpoints_1 = require("./GitHubCopilotEndpoints");
|
|
13
|
+
const OAuthTokenManager_1 = require("./OAuthTokenManager");
|
|
13
14
|
async function makeGitHubCopilotRequest(context, endpoint, body, hasMedia = false, retryConfig) {
|
|
14
|
-
var _a, _b, _c
|
|
15
|
+
var _a, _b, _c;
|
|
15
16
|
const MAX_RETRIES = (_a = retryConfig === null || retryConfig === void 0 ? void 0 : retryConfig.maxRetries) !== null && _a !== void 0 ? _a : 3;
|
|
16
17
|
const BASE_DELAY = (_b = retryConfig === null || retryConfig === void 0 ? void 0 : retryConfig.baseDelay) !== null && _b !== void 0 ? _b : 500;
|
|
17
18
|
const RETRY_ON_403 = (_c = retryConfig === null || retryConfig === void 0 ? void 0 : retryConfig.retryOn403) !== null && _c !== void 0 ? _c : true;
|
|
@@ -24,10 +25,22 @@ async function makeGitHubCopilotRequest(context, endpoint, body, hasMedia = fals
|
|
|
24
25
|
}
|
|
25
26
|
const credentials = await context.getCredentials(credentialType);
|
|
26
27
|
console.log(`🔍 ${credentialType} Credentials Debug:`, Object.keys(credentials));
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const githubToken = credentials.token;
|
|
29
|
+
if (!githubToken) {
|
|
30
|
+
throw new Error("GitHub CLI token (gho_*) not found in credentials");
|
|
31
|
+
}
|
|
32
|
+
if (!githubToken.startsWith("gho_")) {
|
|
33
|
+
throw new Error("Invalid GitHub token format. Must start with gho_");
|
|
34
|
+
}
|
|
35
|
+
console.log(`🔄 Using GitHub token to generate OAuth token...`);
|
|
36
|
+
let token;
|
|
37
|
+
try {
|
|
38
|
+
token = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
|
|
39
|
+
console.log(`✅ OAuth token ready (auto-generated from GitHub token)`);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
throw new Error(`Failed to generate OAuth token: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
|
+
}
|
|
31
44
|
if (!token) {
|
|
32
45
|
console.error(`❌ Available ${credentialType} credential properties:`, Object.keys(credentials));
|
|
33
46
|
console.error(`❌ Full ${credentialType} credential object:`, JSON.stringify(credentials, null, 2));
|
|
@@ -83,7 +96,13 @@ async function makeGitHubCopilotRequest(context, endpoint, body, hasMedia = fals
|
|
|
83
96
|
if (attempt > 1) {
|
|
84
97
|
console.log(`✅ GitHub Copilot API succeeded on attempt ${attempt}/${MAX_RETRIES}`);
|
|
85
98
|
}
|
|
86
|
-
|
|
99
|
+
const responseData = await response.json();
|
|
100
|
+
responseData._retryMetadata = {
|
|
101
|
+
attempts: attempt,
|
|
102
|
+
retries: attempt - 1,
|
|
103
|
+
succeeded: true
|
|
104
|
+
};
|
|
105
|
+
return responseData;
|
|
87
106
|
}
|
|
88
107
|
catch (error) {
|
|
89
108
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface OAuthTokenCache {
|
|
2
|
+
token: string;
|
|
3
|
+
expiresAt: number;
|
|
4
|
+
generatedAt: number;
|
|
5
|
+
refreshIn: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class OAuthTokenManager {
|
|
8
|
+
private static tokenCache;
|
|
9
|
+
private static machineIdCache;
|
|
10
|
+
static getValidOAuthToken(githubToken: string): Promise<string>;
|
|
11
|
+
private static generateOAuthToken;
|
|
12
|
+
private static getMachineId;
|
|
13
|
+
private static generateSessionId;
|
|
14
|
+
private static getCacheKey;
|
|
15
|
+
static clearCache(githubToken: string): void;
|
|
16
|
+
static getCacheInfo(githubToken: string): OAuthTokenCache | null;
|
|
17
|
+
static needsRefresh(githubToken: string, bufferMinutes?: number): boolean;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OAuthTokenManager = void 0;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
const https_1 = __importDefault(require("https"));
|
|
9
|
+
class OAuthTokenManager {
|
|
10
|
+
static async getValidOAuthToken(githubToken) {
|
|
11
|
+
if (!githubToken || !githubToken.startsWith('gho_')) {
|
|
12
|
+
throw new Error('Invalid GitHub token. Must start with gho_');
|
|
13
|
+
}
|
|
14
|
+
const cacheKey = this.getCacheKey(githubToken);
|
|
15
|
+
const cached = this.tokenCache.get(cacheKey);
|
|
16
|
+
if (cached && cached.expiresAt > Date.now() + 120000) {
|
|
17
|
+
const remainingMinutes = Math.round((cached.expiresAt - Date.now()) / 1000 / 60);
|
|
18
|
+
console.log(`✅ Using cached OAuth token (${remainingMinutes} minutes remaining)`);
|
|
19
|
+
return cached.token;
|
|
20
|
+
}
|
|
21
|
+
console.log('🔄 Generating new OAuth token...');
|
|
22
|
+
const newToken = await this.generateOAuthToken(githubToken);
|
|
23
|
+
return newToken;
|
|
24
|
+
}
|
|
25
|
+
static async generateOAuthToken(githubToken) {
|
|
26
|
+
const machineId = this.getMachineId(githubToken);
|
|
27
|
+
const sessionId = this.generateSessionId();
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
const options = {
|
|
30
|
+
hostname: 'api.github.com',
|
|
31
|
+
path: '/copilot_internal/v2/token',
|
|
32
|
+
method: 'GET',
|
|
33
|
+
headers: {
|
|
34
|
+
'Authorization': `token ${githubToken}`,
|
|
35
|
+
'Vscode-Machineid': machineId,
|
|
36
|
+
'Vscode-Sessionid': sessionId,
|
|
37
|
+
'Editor-Version': 'vscode/1.105.1',
|
|
38
|
+
'Editor-Plugin-Version': 'copilot-chat/0.32.3',
|
|
39
|
+
'X-GitHub-Api-Version': '2025-08-20',
|
|
40
|
+
'Accept': 'application/json',
|
|
41
|
+
'User-Agent': 'n8n-nodes-copilot/1.0.0',
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
const req = https_1.default.request(options, (res) => {
|
|
45
|
+
let data = '';
|
|
46
|
+
res.on('data', (chunk) => (data += chunk));
|
|
47
|
+
res.on('end', () => {
|
|
48
|
+
if (res.statusCode === 200) {
|
|
49
|
+
try {
|
|
50
|
+
const response = JSON.parse(data);
|
|
51
|
+
const oauthToken = response.token;
|
|
52
|
+
const expiresAt = response.expires_at * 1000;
|
|
53
|
+
const refreshIn = response.refresh_in;
|
|
54
|
+
const cacheKey = this.getCacheKey(githubToken);
|
|
55
|
+
this.tokenCache.set(cacheKey, {
|
|
56
|
+
token: oauthToken,
|
|
57
|
+
expiresAt: expiresAt,
|
|
58
|
+
generatedAt: Date.now(),
|
|
59
|
+
refreshIn: refreshIn,
|
|
60
|
+
});
|
|
61
|
+
const expiresInMinutes = Math.round((expiresAt - Date.now()) / 1000 / 60);
|
|
62
|
+
console.log(`✅ OAuth token generated successfully (expires in ${expiresInMinutes} minutes)`);
|
|
63
|
+
resolve(oauthToken);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
reject(new Error(`Failed to parse OAuth token response: ${error}`));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
reject(new Error(`Failed to generate OAuth token: ${res.statusCode} ${res.statusMessage}`));
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
req.on('error', (error) => {
|
|
75
|
+
reject(new Error(`Network error generating OAuth token: ${error.message}`));
|
|
76
|
+
});
|
|
77
|
+
req.setTimeout(10000, () => {
|
|
78
|
+
req.destroy();
|
|
79
|
+
reject(new Error('OAuth token generation timeout'));
|
|
80
|
+
});
|
|
81
|
+
req.end();
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
static getMachineId(githubToken) {
|
|
85
|
+
const cacheKey = this.getCacheKey(githubToken);
|
|
86
|
+
if (!this.machineIdCache.has(cacheKey)) {
|
|
87
|
+
const uuid = crypto_1.default.randomUUID();
|
|
88
|
+
const machineId = crypto_1.default.createHash('sha256').update(uuid).digest('hex');
|
|
89
|
+
this.machineIdCache.set(cacheKey, machineId);
|
|
90
|
+
console.log('🆔 Generated new machine ID');
|
|
91
|
+
}
|
|
92
|
+
return this.machineIdCache.get(cacheKey);
|
|
93
|
+
}
|
|
94
|
+
static generateSessionId() {
|
|
95
|
+
return `${crypto_1.default.randomUUID()}${Date.now()}`;
|
|
96
|
+
}
|
|
97
|
+
static getCacheKey(githubToken) {
|
|
98
|
+
return githubToken.substring(0, 20);
|
|
99
|
+
}
|
|
100
|
+
static clearCache(githubToken) {
|
|
101
|
+
const cacheKey = this.getCacheKey(githubToken);
|
|
102
|
+
this.tokenCache.delete(cacheKey);
|
|
103
|
+
this.machineIdCache.delete(cacheKey);
|
|
104
|
+
console.log('🗑️ OAuth token cache cleared');
|
|
105
|
+
}
|
|
106
|
+
static getCacheInfo(githubToken) {
|
|
107
|
+
const cacheKey = this.getCacheKey(githubToken);
|
|
108
|
+
return this.tokenCache.get(cacheKey) || null;
|
|
109
|
+
}
|
|
110
|
+
static needsRefresh(githubToken, bufferMinutes = 2) {
|
|
111
|
+
const cacheKey = this.getCacheKey(githubToken);
|
|
112
|
+
const cached = this.tokenCache.get(cacheKey);
|
|
113
|
+
if (!cached)
|
|
114
|
+
return true;
|
|
115
|
+
const bufferMs = bufferMinutes * 60 * 1000;
|
|
116
|
+
return cached.expiresAt <= Date.now() + bufferMs;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.OAuthTokenManager = OAuthTokenManager;
|
|
120
|
+
OAuthTokenManager.tokenCache = new Map();
|
|
121
|
+
OAuthTokenManager.machineIdCache = new Map();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-github-copilot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.32.1",
|
|
4
4
|
"description": "n8n community node for GitHub Copilot with CLI integration, Chat API access, and AI Chat Model for workflows - access GPT-5, Claude, Gemini and more using your Copilot subscription",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",
|