@floomhq/floom 1.0.42 → 1.0.44

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/login.js CHANGED
@@ -107,6 +107,31 @@ function waitForCallback(port) {
107
107
  res.end();
108
108
  return;
109
109
  }
110
+ if (req.method === "GET" && req.url?.startsWith("/cli-callback?")) {
111
+ try {
112
+ const data = parseCallbackQuery(req.url);
113
+ if (!data.access_token || !data.refresh_token) {
114
+ res.writeHead(400, {
115
+ "content-type": "text/html; charset=utf-8",
116
+ });
117
+ res.end(localCallbackPage("Missing tokens from OAuth response."));
118
+ return;
119
+ }
120
+ res.writeHead(200, {
121
+ "content-type": "text/html; charset=utf-8",
122
+ "referrer-policy": "no-referrer",
123
+ });
124
+ res.end(localCallbackPage("Signed in. You can close this tab."));
125
+ settled = true;
126
+ cleanup();
127
+ resolve(data);
128
+ }
129
+ catch {
130
+ res.writeHead(400, { "content-type": "text/html; charset=utf-8" });
131
+ res.end(localCallbackPage("Invalid OAuth response."));
132
+ }
133
+ return;
134
+ }
110
135
  if (req.method === "POST" && req.url === "/cli-callback") {
111
136
  let body = "";
112
137
  req.on("data", (chunk) => { body += chunk.toString("utf8"); });
@@ -170,6 +195,16 @@ function waitForCallback(port) {
170
195
  });
171
196
  });
172
197
  }
198
+ function parseCallbackQuery(url) {
199
+ const parsed = new URL(url, "http://127.0.0.1");
200
+ const result = {};
201
+ for (const key of ["access_token", "refresh_token", "expires_in", "token_type"]) {
202
+ const value = parsed.searchParams.get(key);
203
+ if (value)
204
+ result[key] = value;
205
+ }
206
+ return result;
207
+ }
173
208
  function parseCallbackBody(body, contentType) {
174
209
  const type = Array.isArray(contentType) ? contentType.join(";") : contentType ?? "";
175
210
  if (type.includes("application/x-www-form-urlencoded")) {
@@ -1,4 +1,4 @@
1
- import { constants } from "node:fs";
1
+ import { constants, rmSync } from "node:fs";
2
2
  import { lstat, mkdir, open, rename, rm, stat } from "node:fs/promises";
3
3
  import { homedir } from "node:os";
4
4
  import { basename, dirname, join, relative, resolve, sep } from "node:path";
@@ -260,10 +260,30 @@ export async function withSyncLock(fn) {
260
260
  await new Promise((resolveDelay) => setTimeout(resolveDelay, 50));
261
261
  }
262
262
  }
263
+ const signalHandlers = new Map();
264
+ const cleanupSync = () => {
265
+ try {
266
+ rmSync(lockPath, { recursive: true, force: true });
267
+ }
268
+ catch {
269
+ // Best-effort signal cleanup. The normal finally path reports real errors.
270
+ }
271
+ };
272
+ for (const signal of ["SIGINT", "SIGTERM"]) {
273
+ const handler = () => {
274
+ cleanupSync();
275
+ process.exit(signal === "SIGINT" ? 130 : 143);
276
+ };
277
+ signalHandlers.set(signal, handler);
278
+ process.once(signal, handler);
279
+ }
263
280
  try {
264
281
  return await fn();
265
282
  }
266
283
  finally {
284
+ for (const [signal, handler] of signalHandlers) {
285
+ process.off(signal, handler);
286
+ }
267
287
  await rm(lockPath, { recursive: true, force: true }).catch(() => { });
268
288
  }
269
289
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/floom",
3
- "version": "1.0.42",
3
+ "version": "1.0.44",
4
4
  "description": "Sync AI skills across agents and machines.",
5
5
  "license": "MIT",
6
6
  "type": "module",