n8n-nodes-github-copilot 3.31.31 → 3.32.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.
@@ -1,9 +1,9 @@
1
- import { ICredentialType, INodeProperties, ICredentialTestRequest, IAuthenticateGeneric } from "n8n-workflow";
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: IAuthenticateGeneric;
7
+ authenticate(credentials: ICredentialDataDecryptedObject, requestOptions: IHttpRequestOptions): Promise<IHttpRequestOptions>;
8
8
  test: ICredentialTestRequest;
9
9
  }
@@ -2,41 +2,97 @@
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";
8
9
  this.displayName = "GitHub Copilot API (GitHub CLI Token)";
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 = [
12
+ {
13
+ displayName: "Authentication Method",
14
+ name: "authMethod",
15
+ type: "options",
16
+ options: [
17
+ {
18
+ name: "GitHub CLI Token (Auto OAuth) - RECOMMENDED",
19
+ value: "githubToken",
20
+ description: "Automatically generates and refreshes OAuth tokens every 20 minutes",
21
+ },
22
+ {
23
+ name: "Manual OAuth Token (Advanced)",
24
+ value: "oauthToken",
25
+ description: "Manually provide OAuth token (expires in 20 minutes)",
26
+ },
27
+ ],
28
+ default: "githubToken",
29
+ description: "Choose how to authenticate with GitHub Copilot API",
30
+ },
31
+ {
32
+ displayName: "ℹ️ Auto OAuth Token Generation",
33
+ name: "autoOAuthNotice",
34
+ type: "notice",
35
+ default: "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!",
36
+ displayOptions: {
37
+ show: {
38
+ authMethod: ["githubToken"],
39
+ },
40
+ },
41
+ },
11
42
  {
12
43
  displayName: "⚠️ IMPORTANT: GitHub CLI Token Required",
13
44
  name: "warningNotice",
14
45
  type: "notice",
15
46
  default: "",
47
+ displayOptions: {
48
+ show: {
49
+ authMethod: ["githubToken"],
50
+ },
51
+ },
16
52
  },
17
53
  {
18
54
  displayName: "🚀 Don't have GitHub CLI installed?",
19
55
  name: "helperNotice1",
20
56
  type: "notice",
21
57
  default: "Use the visual 'GitHub Copilot Auth Helper' node to generate your token without touching the terminal!",
58
+ displayOptions: {
59
+ show: {
60
+ authMethod: ["githubToken"],
61
+ },
62
+ },
22
63
  },
23
64
  {
24
65
  displayName: "📝 Step 1: Create Helper Workflow",
25
66
  name: "helperNotice2",
26
67
  type: "notice",
27
68
  default: "Add a new workflow and insert the 'GitHub Copilot Auth Helper' trigger node.",
69
+ displayOptions: {
70
+ show: {
71
+ authMethod: ["githubToken"],
72
+ },
73
+ },
28
74
  },
29
75
  {
30
76
  displayName: "▶️ Step 2: Activate & Access",
31
77
  name: "helperNotice3",
32
78
  type: "notice",
33
79
  default: "Activate the workflow, then click 'Test workflow' to open the visual token generator in your browser.",
80
+ displayOptions: {
81
+ show: {
82
+ authMethod: ["githubToken"],
83
+ },
84
+ },
34
85
  },
35
86
  {
36
87
  displayName: "📋 Step 3: Copy Token",
37
88
  name: "helperNotice4",
38
89
  type: "notice",
39
90
  default: "Follow the on-screen instructions to authenticate with GitHub and copy the generated 'gho_' token back here.",
91
+ displayOptions: {
92
+ show: {
93
+ authMethod: ["githubToken"],
94
+ },
95
+ },
40
96
  },
41
97
  {
42
98
  displayName: "GitHub CLI Token",
@@ -47,20 +103,43 @@ class GitHubCopilotApi {
47
103
  },
48
104
  default: "",
49
105
  required: true,
50
- description: "Token generated by GitHub CLI (starts with 'gho_'). Use the Auth Helper node above for easy generation, or run in terminal: gh auth login && gh auth token",
106
+ description: "Token generated by GitHub CLI (starts with 'gho_'). OAuth tokens will be auto-generated and refreshed from this token.",
51
107
  placeholder: "gho_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
108
+ displayOptions: {
109
+ show: {
110
+ authMethod: ["githubToken"],
111
+ },
112
+ },
52
113
  },
53
- ];
54
- this.authenticate = {
55
- type: "generic",
56
- properties: {
57
- headers: {
58
- Authorization: "=Bearer {{$credentials.token}}",
59
- Accept: "application/json",
60
- "Content-Type": "application/json",
114
+ {
115
+ displayName: "⚠️ Manual OAuth Token (Advanced)",
116
+ name: "manualOAuthNotice",
117
+ type: "notice",
118
+ default: "OAuth tokens expire after ~20 minutes. You will need to manually regenerate and update this token frequently. Consider using GitHub CLI Token mode instead for automatic token management.",
119
+ displayOptions: {
120
+ show: {
121
+ authMethod: ["oauthToken"],
122
+ },
61
123
  },
62
124
  },
63
- };
125
+ {
126
+ displayName: "OAuth Token",
127
+ name: "oauthToken",
128
+ type: "string",
129
+ typeOptions: {
130
+ password: true,
131
+ },
132
+ default: "",
133
+ required: true,
134
+ description: "Manual OAuth token (starts with 'tid='). Expires in ~20 minutes.",
135
+ placeholder: "tid=xxxxx;exp=xxxxx;sku=xxxxx;...",
136
+ displayOptions: {
137
+ show: {
138
+ authMethod: ["oauthToken"],
139
+ },
140
+ },
141
+ },
142
+ ];
64
143
  this.test = {
65
144
  request: {
66
145
  baseURL: GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.BASE_URL,
@@ -69,5 +148,28 @@ class GitHubCopilotApi {
69
148
  },
70
149
  };
71
150
  }
151
+ async authenticate(credentials, requestOptions) {
152
+ const authMethod = credentials.authMethod;
153
+ let authToken;
154
+ if (authMethod === "githubToken") {
155
+ const githubToken = credentials.token;
156
+ try {
157
+ authToken = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
158
+ }
159
+ catch (error) {
160
+ throw new Error(`Failed to generate OAuth token: ${error instanceof Error ? error.message : String(error)}`);
161
+ }
162
+ }
163
+ else {
164
+ authToken = credentials.oauthToken;
165
+ }
166
+ if (!requestOptions.headers) {
167
+ requestOptions.headers = {};
168
+ }
169
+ requestOptions.headers.Authorization = `Bearer ${authToken}`;
170
+ requestOptions.headers.Accept = "application/json";
171
+ requestOptions.headers["Content-Type"] = "application/json";
172
+ return requestOptions;
173
+ }
72
174
  }
73
175
  exports.GitHubCopilotApi = GitHubCopilotApi;
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "3.31.31",
3
+ "version": "3.32.0",
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,6 +10,7 @@ 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
15
  var _a, _b, _c, _d;
15
16
  const MAX_RETRIES = (_a = retryConfig === null || retryConfig === void 0 ? void 0 : retryConfig.maxRetries) !== null && _a !== void 0 ? _a : 3;
@@ -24,10 +25,44 @@ 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 token = (credentials.accessToken ||
28
- credentials.access_token ||
29
- ((_d = credentials.oauthTokenData) === null || _d === void 0 ? void 0 : _d.access_token) ||
30
- credentials.token);
28
+ const authMethod = credentials.authMethod;
29
+ let token;
30
+ if (authMethod === "githubToken" || credentials.token) {
31
+ const githubToken = credentials.token;
32
+ if (!githubToken) {
33
+ throw new Error("GitHub token (gho_*) not found in credentials");
34
+ }
35
+ if (!githubToken.startsWith("gho_")) {
36
+ throw new Error("Invalid GitHub token format. Must start with gho_");
37
+ }
38
+ console.log(`🔄 Using GitHub token to generate OAuth token...`);
39
+ try {
40
+ token = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
41
+ console.log(`✅ OAuth token ready (auto-generated from GitHub token)`);
42
+ }
43
+ catch (error) {
44
+ throw new Error(`Failed to generate OAuth token: ${error instanceof Error ? error.message : String(error)}`);
45
+ }
46
+ }
47
+ else if (authMethod === "oauthToken" || credentials.oauthToken) {
48
+ token = credentials.oauthToken;
49
+ if (!token) {
50
+ throw new Error("OAuth token not found in credentials");
51
+ }
52
+ console.log(`✅ Using manual OAuth token`);
53
+ }
54
+ else {
55
+ token = (credentials.accessToken ||
56
+ credentials.access_token ||
57
+ ((_d = credentials.oauthTokenData) === null || _d === void 0 ? void 0 : _d.access_token) ||
58
+ credentials.token);
59
+ if (!token) {
60
+ console.error(`❌ Available ${credentialType} credential properties:`, Object.keys(credentials));
61
+ throw new Error(`No access token found in ${credentialType} credentials. Available properties: ` +
62
+ Object.keys(credentials).join(", "));
63
+ }
64
+ console.log(`⚠️ Using legacy token format (consider updating credential configuration)`);
65
+ }
31
66
  if (!token) {
32
67
  console.error(`❌ Available ${credentialType} credential properties:`, Object.keys(credentials));
33
68
  console.error(`❌ Full ${credentialType} credential object:`, JSON.stringify(credentials, null, 2));
@@ -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.31.31",
3
+ "version": "3.32.0",
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",