n8n-nodes-github-copilot 3.31.1 → 3.31.2

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,53 @@ 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: "=",
22
+ responseMode: "onReceived",
23
+ path: "github-auth",
24
+ },
25
+ ],
18
26
  properties: [
19
27
  {
20
- displayName: "📋 Como Usar",
28
+ displayName: "🎯 Como Usar",
21
29
  name: "instructions",
22
30
  type: "notice",
23
31
  default: "",
24
32
  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>
33
+ <div style="background: #e8f5e8; padding: 20px; border-left: 4px solid #4CAF50; border-radius: 4px;">
34
+ <h3 style="margin-top: 0; color: #2E7D32;">✨ Autenticação Visual - Sem Terminal!</h3>
35
+
36
+ <p><strong>1. Ative este workflow</strong></p>
37
+ <p>Clique em "Active" no canto superior direito</p>
38
+
39
+ <p><strong>2. Copie a URL do Webhook</strong></p>
40
+ <p>Clique em "Copy URL" abaixo e envie para o usuário</p>
41
+
42
+ <p><strong>3. Usuário acessa a URL no navegador</strong></p>
43
+ <p>Uma página bonita vai abrir com instruções claras</p>
44
+
45
+ <p><strong>4. Processo automático!</strong></p>
46
+ <ul style="margin: 10px 0; padding-left: 20px;">
47
+ <li>✅ Página solicita código do GitHub</li>
48
+ <li>✅ Mostra código grande para copiar</li>
38
49
  <li>✅ Abre GitHub automaticamente</li>
39
- <li>✅ Faz polling até você autorizar</li>
50
+ <li>✅ Aguarda autorização (polling automático)</li>
40
51
  <li>✅ Exibe token pronto para copiar</li>
41
52
  </ul>
53
+
54
+ <p style="background: #fff3e0; padding: 10px; border-radius: 4px; margin-top: 15px;">
55
+ <strong>💡 Sem CORS!</strong> O n8n faz as chamadas para o GitHub, não o navegador!
56
+ </p>
42
57
  </div>
43
58
  `,
44
59
  },
@@ -58,90 +73,86 @@ class GitHubCopilotAuthHelper {
58
73
  required: true,
59
74
  description: "OAuth scopes required for GitHub Copilot",
60
75
  },
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
76
  ],
86
77
  };
87
78
  }
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",
79
+ async webhook() {
80
+ const req = this.getRequestObject();
81
+ const clientId = this.getNodeParameter("clientId");
82
+ const scopes = this.getNodeParameter("scopes");
83
+ if (req.method === "POST") {
84
+ const body = this.getBodyData();
85
+ const action = body.action;
86
+ try {
87
+ if (action === "device_code") {
88
+ const response = await fetch("https://github.com/login/device/code", {
89
+ method: "POST",
90
+ headers: {
91
+ "Accept": "application/json",
92
+ "Content-Type": "application/x-www-form-urlencoded",
112
93
  },
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");
94
+ body: new URLSearchParams({
95
+ client_id: clientId,
96
+ scope: scopes,
97
+ }),
98
+ });
99
+ const data = await response.json();
100
+ return {
101
+ webhookResponse: {
102
+ status: 200,
103
+ headers: { "Content-Type": "application/json" },
104
+ body: JSON.stringify(data),
105
+ },
106
+ };
107
+ }
108
+ if (action === "poll_token") {
109
+ const deviceCode = body.device_code;
110
+ const response = await fetch("https://github.com/login/oauth/access_token", {
111
+ method: "POST",
112
+ headers: {
113
+ "Accept": "application/json",
114
+ "Content-Type": "application/x-www-form-urlencoded",
115
+ },
116
+ body: new URLSearchParams({
117
+ client_id: clientId,
118
+ device_code: deviceCode,
119
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
120
+ }),
121
+ });
122
+ const data = await response.json();
123
+ return {
124
+ webhookResponse: {
125
+ status: 200,
126
+ headers: { "Content-Type": "application/json" },
127
+ body: JSON.stringify(data),
128
+ },
129
+ };
132
130
  }
133
- output = {
134
- json: jsonOutput,
135
- pairedItem: i,
131
+ throw new Error(`Unknown action: ${action}`);
132
+ }
133
+ catch (error) {
134
+ return {
135
+ webhookResponse: {
136
+ status: 500,
137
+ headers: { "Content-Type": "application/json" },
138
+ body: JSON.stringify({ error: error.message }),
139
+ },
136
140
  };
137
141
  }
138
- returnData.push(output);
139
142
  }
140
- return [returnData];
143
+ const webhookUrl = this.getNodeWebhookUrl("default");
144
+ const html = generateAuthPage(webhookUrl);
145
+ return {
146
+ webhookResponse: {
147
+ status: 200,
148
+ headers: { "Content-Type": "text/html; charset=utf-8" },
149
+ body: html,
150
+ },
151
+ };
141
152
  }
142
153
  }
143
154
  exports.GitHubCopilotAuthHelper = GitHubCopilotAuthHelper;
144
- function generateAuthPage(clientId, scopes) {
155
+ function generateAuthPage(proxyUrl) {
145
156
  return `<!DOCTYPE html>
146
157
  <html lang="pt-BR">
147
158
  <head>
@@ -399,7 +410,7 @@ function generateAuthPage(clientId, scopes) {
399
410
  <span>Copiar Token</span>
400
411
  </button>
401
412
  <p class="info-text" style="color: #155724; margin-top: 15px;">
402
- ✨ Cole este token na credencial "GitHub Copilot OAuth2 (with Helper)" no n8n
413
+ ✨ Cole este token na credencial "GitHub Copilot API" no n8n
403
414
  </p>
404
415
  </div>
405
416
 
@@ -410,10 +421,7 @@ function generateAuthPage(clientId, scopes) {
410
421
  </div>
411
422
 
412
423
  <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";
424
+ const PROXY_URL = "${proxyUrl}";
417
425
 
418
426
  let deviceCode = "";
419
427
  let userCode = "";
@@ -425,16 +433,14 @@ function generateAuthPage(clientId, scopes) {
425
433
  document.getElementById("step1").querySelector(".btn").disabled = true;
426
434
  document.getElementById("step1").querySelector(".btn").innerHTML = '<span>⏳</span><span>Solicitando...</span>';
427
435
 
428
- // Request device code
429
- const response = await fetch(DEVICE_CODE_URL, {
436
+ // Request device code via n8n proxy
437
+ const response = await fetch(PROXY_URL, {
430
438
  method: "POST",
431
439
  headers: {
432
- "Accept": "application/json",
433
- "Content-Type": "application/x-www-form-urlencoded",
440
+ "Content-Type": "application/json",
434
441
  },
435
- body: new URLSearchParams({
436
- client_id: CLIENT_ID,
437
- scope: SCOPES
442
+ body: JSON.stringify({
443
+ action: "device_code"
438
444
  })
439
445
  });
440
446
 
@@ -490,16 +496,14 @@ function generateAuthPage(clientId, scopes) {
490
496
  document.getElementById("statusText").textContent = \`Verificando... (tentativa \${attempt}/\${maxAttempts})\`;
491
497
 
492
498
  try {
493
- const response = await fetch(ACCESS_TOKEN_URL, {
499
+ const response = await fetch(PROXY_URL, {
494
500
  method: "POST",
495
501
  headers: {
496
- "Accept": "application/json",
497
- "Content-Type": "application/x-www-form-urlencoded",
502
+ "Content-Type": "application/json",
498
503
  },
499
- body: new URLSearchParams({
500
- client_id: CLIENT_ID,
501
- device_code: deviceCode,
502
- grant_type: "urn:ietf:params:oauth:grant-type:device_code"
504
+ body: JSON.stringify({
505
+ action: "poll_token",
506
+ device_code: deviceCode
503
507
  })
504
508
  });
505
509
 
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.2",
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.2",
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",