@flow-industries/id 0.24.2 → 0.24.4

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,6 +1,7 @@
1
1
  export declare function safeReturnTo(value: string, audience: string, sessionPath?: string): string | null;
2
2
  export declare function startBrowserSession(request: Request, audience: string, issuerUrl: string, body: {
3
3
  action: "login" | "account";
4
+ redirect?: boolean;
4
5
  returnTo?: string;
5
6
  signUp?: boolean;
6
7
  accessKeyHash?: string;
@@ -81,7 +81,17 @@ export async function startBrowserSession(request, audience, issuerUrl, body, ap
81
81
  const { handoff } = z
82
82
  .object({ handoff: z.string().regex(opaquePattern) })
83
83
  .parse(await response.json());
84
- return reply({ accountUrl: `${issuerUrl}/account#handoff=${handoff}` });
84
+ const accountUrl = `${issuerUrl}/account#handoff=${handoff}`;
85
+ if (body.redirect)
86
+ return new Response(null, {
87
+ status: 303,
88
+ headers: {
89
+ Location: accountUrl,
90
+ "Cache-Control": "no-store",
91
+ "Referrer-Policy": "no-referrer",
92
+ },
93
+ });
94
+ return reply({ accountUrl });
85
95
  }
86
96
  const returnTo = safeReturnTo(body.returnTo ?? "/", audience, new URL(request.url).pathname);
87
97
  if (!returnTo)
@@ -394,34 +394,12 @@ export function createFlow(options = {}) {
394
394
  });
395
395
  }
396
396
  function openAccount() {
397
- const tab = window.open("about:blank", "_blank");
397
+ const url = new URL(sessionPath, window.location.origin);
398
+ url.searchParams.set("action", "account");
399
+ const tab = window.open(url.href, "_blank");
398
400
  if (!tab)
399
401
  return false;
400
402
  tab.opener = null;
401
- tab.document.title = "Opening Flow ID";
402
- tab.document.body.textContent = "Opening your Flow ID account…";
403
- void fetch(sessionPath, {
404
- method: "POST",
405
- headers: { "Content-Type": "application/json" },
406
- body: JSON.stringify({ action: "account" }),
407
- })
408
- .then(async (response) => {
409
- if (!response.ok)
410
- throw new Error("Account unavailable");
411
- // SAFETY: the app session handler returns the SDK protocol response.
412
- const result = (await response.json());
413
- tab.location.replace(result.accountUrl);
414
- })
415
- .catch(() => {
416
- tab.document.title = "Open Flow ID";
417
- tab.document.body.textContent =
418
- "Your app account could not be opened securely. Return to the app and try again, or open Flow ID and check the signed-in account before making changes. ";
419
- const link = tab.document.createElement("a");
420
- link.href = `${host}/account`;
421
- link.textContent = "Open Flow ID";
422
- link.rel = "noreferrer";
423
- tab.document.body.appendChild(link);
424
- });
425
403
  return true;
426
404
  }
427
405
  async function logout() {
@@ -1,3 +1,3 @@
1
1
  import type { MountProfileOptions, ProfileButtonHandle } from "../types";
2
- /** Mount a native account button that opens Flow ID in a normal browser tab. */
2
+ /** Mount an account button that signs guests in or opens full-account settings. */
3
3
  export declare function createProfileButton(options: MountProfileOptions): ProfileButtonHandle;
@@ -6,7 +6,7 @@ const POSITION_STYLE = {
6
6
  "bottom-right": { bottom: "0", right: "0" },
7
7
  "bottom-left": { bottom: "0", left: "0" },
8
8
  };
9
- /** Mount a native account button that opens Flow ID in a normal browser tab. */
9
+ /** Mount an account button that signs guests in or opens full-account settings. */
10
10
  export function createProfileButton(options) {
11
11
  if (!("document" in globalThis))
12
12
  return { setTheme() { }, destroy() { } };
@@ -81,7 +81,9 @@ export function createProfileButton(options) {
81
81
  function update(refresh = false) {
82
82
  const user = flow.getState().user;
83
83
  name.textContent = user?.username ?? "Flow ID";
84
- button.setAttribute("aria-label", `Open ${user?.username ?? "your"} Flow ID account in a new tab`);
84
+ button.setAttribute("aria-label", !user || user.isGuest
85
+ ? "Sign in to Flow ID"
86
+ : `Open ${user.username} Flow ID account in a new tab`);
85
87
  const identityChanged = user?.id !== lastUser?.id ||
86
88
  user?.username !== lastUser?.username ||
87
89
  user?.isGuest !== lastUser?.isGuest;
@@ -140,6 +142,19 @@ export function createProfileButton(options) {
140
142
  });
141
143
  }
142
144
  button.addEventListener("click", () => {
145
+ const user = flow.getState().user;
146
+ if (!user || user.isGuest) {
147
+ if (button.disabled)
148
+ return;
149
+ button.disabled = true;
150
+ notice.textContent = "";
151
+ fallback.hidden = true;
152
+ void flow.login().catch(() => {
153
+ button.disabled = false;
154
+ notice.textContent = "Could not start sign-in. Try again.";
155
+ });
156
+ return;
157
+ }
143
158
  const opened = flow.openAccount();
144
159
  notice.textContent = opened
145
160
  ? ""
@@ -93,6 +93,14 @@ export async function handleSessionRequest(request, opts = {}) {
93
93
  }
94
94
  switch (request.method) {
95
95
  case "GET": {
96
+ if (callback.searchParams.get("action") === "account") {
97
+ try {
98
+ return await startBrowserSession(request, audience, issuerUrl, { action: "account", redirect: true }, apiUrl);
99
+ }
100
+ catch {
101
+ return json({ state: null }, 502);
102
+ }
103
+ }
96
104
  if (new URL(request.url).searchParams.get("refresh") === "1") {
97
105
  const token = parseCookieHeader(request.headers.get("Cookie"))[cookieNamesFor(audience).refresh];
98
106
  if (!token)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flow-industries/id",
3
- "version": "0.24.2",
3
+ "version": "0.24.4",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",