@openfort/cli 0.1.11 → 0.1.12

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.
Files changed (2) hide show
  1. package/dist/cli.js +67 -18
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -163,6 +163,45 @@ function callbackPage(title, description, variant = "success", extraHtml = "") {
163
163
  </body>
164
164
  </html>`;
165
165
  }
166
+ function fragmentBridgePage(port) {
167
+ return `<!DOCTYPE html>
168
+ <html lang="en">
169
+ <head>
170
+ <meta charset="UTF-8">
171
+ <title>Openfort CLI - Authenticating...</title>
172
+ <style>
173
+ body { font-family: system-ui, sans-serif; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; background: #fafafa; }
174
+ @media (prefers-color-scheme: dark) { body { background: #111; color: #eee; } }
175
+ p { font-size: 0.875rem; color: #888; }
176
+ </style>
177
+ </head>
178
+ <body>
179
+ <p>Completing authentication...</p>
180
+ <script>
181
+ (function() {
182
+ var hash = window.location.hash.substring(1);
183
+ if (!hash) {
184
+ document.querySelector('p').textContent = 'Authentication failed: no credentials received.';
185
+ return;
186
+ }
187
+ // Clear the fragment from the URL immediately to minimize exposure
188
+ history.replaceState(null, '', window.location.pathname);
189
+ fetch('http://localhost:${port}/callback/complete', {
190
+ method: 'POST',
191
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
192
+ body: hash
193
+ }).then(function(r) { return r.text(); }).then(function(html) {
194
+ document.open();
195
+ document.write(html);
196
+ document.close();
197
+ }).catch(function() {
198
+ document.querySelector('p').textContent = 'Failed to complete authentication. Please try again.';
199
+ });
200
+ })();
201
+ </script>
202
+ </body>
203
+ </html>`;
204
+ }
166
205
  function waitForCallback(port, state) {
167
206
  return new Promise((resolve, reject) => {
168
207
  const timeout = setTimeout(() => {
@@ -172,12 +211,7 @@ function waitForCallback(port, state) {
172
211
  }, 5 * 60 * 1e3);
173
212
  const server = createServer((req, res) => {
174
213
  const url = new URL(req.url ?? "/", `http://localhost:${port}`);
175
- if (url.pathname === "/callback") {
176
- const apiKey = url.searchParams.get("api_key");
177
- const publishableKey = url.searchParams.get("publishable_key");
178
- const projectId = url.searchParams.get("project_id");
179
- const project = url.searchParams.get("project");
180
- const returnedState = url.searchParams.get("state");
214
+ if (url.pathname === "/callback" && req.method === "GET") {
181
215
  const error = url.searchParams.get("error");
182
216
  const errorDescription = url.searchParams.get("error_description");
183
217
  if (error) {
@@ -189,14 +223,28 @@ function waitForCallback(port, state) {
189
223
  reject(new Error(errorDescription || error));
190
224
  return;
191
225
  }
192
- if (!apiKey || returnedState !== state) {
193
- res.writeHead(400, { "Content-Type": "text/html" });
194
- res.end(callbackPage("Invalid callback", "Missing API key or state mismatch. Please try logging in again.", "error"));
195
- return;
196
- }
197
226
  res.writeHead(200, { "Content-Type": "text/html" });
198
- const skillCommand = "npx skills add openfort-xyz/agent-skills --skill openfort";
199
- const agentSkillHtml = `
227
+ res.end(fragmentBridgePage(port));
228
+ } else if (url.pathname === "/callback/complete" && req.method === "POST") {
229
+ let body = "";
230
+ req.on("data", (chunk) => {
231
+ body += chunk.toString();
232
+ });
233
+ req.on("end", () => {
234
+ const params = new URLSearchParams(body);
235
+ const apiKey = params.get("api_key");
236
+ const publishableKey = params.get("publishable_key");
237
+ const projectId = params.get("project_id");
238
+ const project = params.get("project");
239
+ const returnedState = params.get("state");
240
+ if (!apiKey || returnedState !== state) {
241
+ res.writeHead(400, { "Content-Type": "text/html" });
242
+ res.end(callbackPage("Invalid callback", "Missing API key or state mismatch. Please try logging in again.", "error"));
243
+ return;
244
+ }
245
+ res.writeHead(200, { "Content-Type": "text/html" });
246
+ const skillCommand = "npx skills add openfort-xyz/agent-skills --skill openfort";
247
+ const agentSkillHtml = `
200
248
  <div class="card-extra">
201
249
  <p class="card-extra-title">Build with AI? Add the Openfort skill:</p>
202
250
  <div class="code-block">
@@ -205,11 +253,12 @@ function waitForCallback(port, state) {
205
253
  </div>
206
254
  <a class="card-extra-link" href="https://www.openfort.io/docs/overview/building-with-cli" target="_blank" rel="noopener noreferrer">Learn more about building with the CLI</a>
207
255
  </div>`;
208
- res.end(callbackPage("Login successful!", "You can close this window and return to your terminal.", "success", agentSkillHtml));
209
- clearTimeout(timeout);
210
- server.close();
211
- server.closeAllConnections();
212
- resolve({ apiKey, publishableKey: publishableKey || void 0, projectId: projectId || void 0, project: project || "unknown" });
256
+ res.end(callbackPage("Login successful!", "You can close this window and return to your terminal.", "success", agentSkillHtml));
257
+ clearTimeout(timeout);
258
+ server.close();
259
+ server.closeAllConnections();
260
+ resolve({ apiKey, publishableKey: publishableKey || void 0, projectId: projectId || void 0, project: project || "unknown" });
261
+ });
213
262
  } else {
214
263
  res.writeHead(404);
215
264
  res.end();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfort/cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Openfort CLI — manage wallets, policies, and transactions from the terminal.",
5
5
  "author": "Openfort (https://www.openfort.io)",
6
6
  "bugs": "https://github.com/openfort-xyz/cli/issues",