n8n-nodes-github-copilot 3.31.1 → 3.31.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.
@@ -1,5 +1,5 @@
1
- import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
1
+ import { IWebhookFunctions, IWebhookResponseData, INodeType, INodeTypeDescription } from "n8n-workflow";
2
2
  export declare class GitHubCopilotAuthHelper implements INodeType {
3
3
  description: INodeTypeDescription;
4
- execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
4
+ webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
5
5
  }
@@ -7,38 +7,59 @@ class GitHubCopilotAuthHelper {
7
7
  displayName: "GitHub Copilot Auth Helper",
8
8
  name: "githubCopilotAuthHelper",
9
9
  icon: "file:../../shared/icons/copilot.svg",
10
- group: ["transform"],
10
+ group: ["trigger"],
11
11
  version: 1,
12
- description: "Interactive OAuth Device Flow authentication helper - generates HTML page for easy token generation",
12
+ description: "Interactive OAuth Device Flow - serves HTML page with proxy to avoid CORS",
13
13
  defaults: {
14
- name: "GitHub Copilot Auth Helper",
14
+ name: "GitHub Copilot Auth",
15
15
  },
16
- inputs: ["main"],
17
- outputs: ["main"],
16
+ inputs: [],
17
+ outputs: [],
18
+ webhooks: [
19
+ {
20
+ name: "default",
21
+ httpMethod: "GET",
22
+ responseMode: "onReceived",
23
+ path: "github-auth",
24
+ },
25
+ {
26
+ name: "default",
27
+ httpMethod: "POST",
28
+ responseMode: "onReceived",
29
+ path: "github-auth",
30
+ },
31
+ ],
18
32
  properties: [
19
33
  {
20
- displayName: "📋 Como Usar",
34
+ displayName: "🎯 Como Usar",
21
35
  name: "instructions",
22
36
  type: "notice",
23
37
  default: "",
24
38
  description: `
25
- <div style="background: #e3f2fd; padding: 15px; border-left: 4px solid #2196F3; border-radius: 4px;">
26
- <h3 style="margin-top: 0;">🎯 Este node gera uma página HTML interativa!</h3>
27
- <ol>
28
- <li>Execute este node</li>
29
- <li>Copie o HTML do output</li>
30
- <li>Salve como arquivo .html e abra no navegador</li>
31
- <li>OU use um node "Send Email" para enviar para você</li>
32
- <li>Siga as instruções na página para obter seu token</li>
33
- </ol>
34
- <p><strong>A página faz tudo automaticamente:</strong></p>
35
- <ul>
36
- <li>✅ Solicita device code do GitHub</li>
37
- <li>✅ Mostra código para copiar</li>
39
+ <div style="background: #e8f5e8; padding: 20px; border-left: 4px solid #4CAF50; border-radius: 4px;">
40
+ <h3 style="margin-top: 0; color: #2E7D32;">✨ Autenticação Visual - Sem Terminal!</h3>
41
+
42
+ <p><strong>1. Ative este workflow</strong></p>
43
+ <p>Clique em "Active" no canto superior direito</p>
44
+
45
+ <p><strong>2. Copie a URL do Webhook</strong></p>
46
+ <p>Clique em "Copy URL" abaixo e envie para o usuário</p>
47
+
48
+ <p><strong>3. Usuário acessa a URL no navegador</strong></p>
49
+ <p>Uma página bonita vai abrir com instruções claras</p>
50
+
51
+ <p><strong>4. Processo automático!</strong></p>
52
+ <ul style="margin: 10px 0; padding-left: 20px;">
53
+ <li>✅ Página solicita código do GitHub</li>
54
+ <li>✅ Mostra código grande para copiar</li>
38
55
  <li>✅ Abre GitHub automaticamente</li>
39
- <li>✅ Faz polling até você autorizar</li>
56
+ <li>✅ Aguarda autorização (polling automático)</li>
40
57
  <li>✅ Exibe token pronto para copiar</li>
41
58
  </ul>
59
+
60
+ <p style="background: #fff3e0; padding: 10px; border-radius: 4px; margin-top: 15px;">
61
+ <strong>💡 Sem CORS!</strong> O n8n faz as chamadas para o GitHub, não o navegador!
62
+ </p>
42
63
  </div>
43
64
  `,
44
65
  },
@@ -58,90 +79,86 @@ class GitHubCopilotAuthHelper {
58
79
  required: true,
59
80
  description: "OAuth scopes required for GitHub Copilot",
60
81
  },
61
- {
62
- displayName: "Output Format",
63
- name: "outputFormat",
64
- type: "options",
65
- options: [
66
- {
67
- name: "📄 Binary File (Download Ready)",
68
- value: "binary",
69
- description: "HTML as binary data ready to download as .html file",
70
- },
71
- {
72
- name: "📋 HTML Text + Instructions",
73
- value: "htmlWithInstructions",
74
- description: "HTML text with usage instructions (copy & paste)",
75
- },
76
- {
77
- name: "📝 HTML Text Only",
78
- value: "html",
79
- description: "Just the HTML code as text",
80
- },
81
- ],
82
- default: "binary",
83
- description: "How to output the authentication page",
84
- },
85
82
  ],
86
83
  };
87
84
  }
88
- async execute() {
89
- const items = this.getInputData();
90
- const returnData = [];
91
- for (let i = 0; i < items.length; i++) {
92
- const clientId = this.getNodeParameter("clientId", i);
93
- const scopes = this.getNodeParameter("scopes", i);
94
- const outputFormat = this.getNodeParameter("outputFormat", i);
95
- const html = generateAuthPage(clientId, scopes);
96
- let output;
97
- if (outputFormat === "binary") {
98
- const buffer = Buffer.from(html, "utf-8");
99
- output = {
100
- json: {
101
- success: true,
102
- message: "✅ Authentication page generated successfully!",
103
- instructions: "Download the binary file below and open it in your browser",
104
- fileName: "github-copilot-auth.html",
105
- fileSize: `${(buffer.length / 1024).toFixed(2)} KB`,
106
- },
107
- binary: {
108
- authPage: {
109
- data: buffer.toString("base64"),
110
- mimeType: "text/html",
111
- fileName: "github-copilot-auth.html",
85
+ async webhook() {
86
+ const req = this.getRequestObject();
87
+ const clientId = this.getNodeParameter("clientId");
88
+ const scopes = this.getNodeParameter("scopes");
89
+ if (req.method === "POST") {
90
+ const body = this.getBodyData();
91
+ const action = body.action;
92
+ try {
93
+ if (action === "device_code") {
94
+ const response = await fetch("https://github.com/login/device/code", {
95
+ method: "POST",
96
+ headers: {
97
+ "Accept": "application/json",
98
+ "Content-Type": "application/x-www-form-urlencoded",
112
99
  },
113
- },
114
- pairedItem: i,
115
- };
116
- }
117
- else {
118
- const jsonOutput = {
119
- html,
120
- clientId,
121
- scopes,
122
- };
123
- if (outputFormat === "htmlWithInstructions") {
124
- jsonOutput.instructions = [
125
- "1. Copy the HTML content from the 'html' field",
126
- "2. Save as 'github-copilot-auth.html'",
127
- "3. Open the file in your browser",
128
- "4. Follow the on-screen instructions",
129
- "5. Copy the token when it appears",
130
- "6. Use the token in your GitHub Copilot API credential in n8n",
131
- ].join("\n");
100
+ body: new URLSearchParams({
101
+ client_id: clientId,
102
+ scope: scopes,
103
+ }),
104
+ });
105
+ const data = await response.json();
106
+ return {
107
+ webhookResponse: {
108
+ status: 200,
109
+ headers: { "Content-Type": "application/json" },
110
+ body: JSON.stringify(data),
111
+ },
112
+ };
132
113
  }
133
- output = {
134
- json: jsonOutput,
135
- pairedItem: i,
114
+ if (action === "poll_token") {
115
+ const deviceCode = body.device_code;
116
+ const response = await fetch("https://github.com/login/oauth/access_token", {
117
+ method: "POST",
118
+ headers: {
119
+ "Accept": "application/json",
120
+ "Content-Type": "application/x-www-form-urlencoded",
121
+ },
122
+ body: new URLSearchParams({
123
+ client_id: clientId,
124
+ device_code: deviceCode,
125
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
126
+ }),
127
+ });
128
+ const data = await response.json();
129
+ return {
130
+ webhookResponse: {
131
+ status: 200,
132
+ headers: { "Content-Type": "application/json" },
133
+ body: JSON.stringify(data),
134
+ },
135
+ };
136
+ }
137
+ throw new Error(`Unknown action: ${action}`);
138
+ }
139
+ catch (error) {
140
+ return {
141
+ webhookResponse: {
142
+ status: 500,
143
+ headers: { "Content-Type": "application/json" },
144
+ body: JSON.stringify({ error: error.message }),
145
+ },
136
146
  };
137
147
  }
138
- returnData.push(output);
139
148
  }
140
- return [returnData];
149
+ const webhookUrl = this.getNodeWebhookUrl("default");
150
+ const html = generateAuthPage(webhookUrl);
151
+ return {
152
+ webhookResponse: {
153
+ status: 200,
154
+ headers: { "Content-Type": "text/html; charset=utf-8" },
155
+ body: html,
156
+ },
157
+ };
141
158
  }
142
159
  }
143
160
  exports.GitHubCopilotAuthHelper = GitHubCopilotAuthHelper;
144
- function generateAuthPage(clientId, scopes) {
161
+ function generateAuthPage(proxyUrl) {
145
162
  return `<!DOCTYPE html>
146
163
  <html lang="pt-BR">
147
164
  <head>
@@ -399,7 +416,7 @@ function generateAuthPage(clientId, scopes) {
399
416
  <span>Copiar Token</span>
400
417
  </button>
401
418
  <p class="info-text" style="color: #155724; margin-top: 15px;">
402
- ✨ Cole este token na credencial "GitHub Copilot OAuth2 (with Helper)" no n8n
419
+ ✨ Cole este token na credencial "GitHub Copilot API" no n8n
403
420
  </p>
404
421
  </div>
405
422
 
@@ -410,10 +427,7 @@ function generateAuthPage(clientId, scopes) {
410
427
  </div>
411
428
 
412
429
  <script>
413
- const CLIENT_ID = "${clientId}";
414
- const SCOPES = "${scopes}";
415
- const DEVICE_CODE_URL = "https://github.com/login/device/code";
416
- const ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
430
+ const PROXY_URL = "${proxyUrl}";
417
431
 
418
432
  let deviceCode = "";
419
433
  let userCode = "";
@@ -425,16 +439,14 @@ function generateAuthPage(clientId, scopes) {
425
439
  document.getElementById("step1").querySelector(".btn").disabled = true;
426
440
  document.getElementById("step1").querySelector(".btn").innerHTML = '<span>⏳</span><span>Solicitando...</span>';
427
441
 
428
- // Request device code
429
- const response = await fetch(DEVICE_CODE_URL, {
442
+ // Request device code via n8n proxy
443
+ const response = await fetch(PROXY_URL, {
430
444
  method: "POST",
431
445
  headers: {
432
- "Accept": "application/json",
433
- "Content-Type": "application/x-www-form-urlencoded",
446
+ "Content-Type": "application/json",
434
447
  },
435
- body: new URLSearchParams({
436
- client_id: CLIENT_ID,
437
- scope: SCOPES
448
+ body: JSON.stringify({
449
+ action: "device_code"
438
450
  })
439
451
  });
440
452
 
@@ -490,16 +502,14 @@ function generateAuthPage(clientId, scopes) {
490
502
  document.getElementById("statusText").textContent = \`Verificando... (tentativa \${attempt}/\${maxAttempts})\`;
491
503
 
492
504
  try {
493
- const response = await fetch(ACCESS_TOKEN_URL, {
505
+ const response = await fetch(PROXY_URL, {
494
506
  method: "POST",
495
507
  headers: {
496
- "Accept": "application/json",
497
- "Content-Type": "application/x-www-form-urlencoded",
508
+ "Content-Type": "application/json",
498
509
  },
499
- body: new URLSearchParams({
500
- client_id: CLIENT_ID,
501
- device_code: deviceCode,
502
- grant_type: "urn:ietf:params:oauth:grant-type:device_code"
510
+ body: JSON.stringify({
511
+ action: "poll_token",
512
+ device_code: deviceCode
503
513
  })
504
514
  });
505
515
 
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "3.31.1",
3
+ "version": "3.31.3",
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "3.31.1",
3
+ "version": "3.31.3",
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",