@flow-industries/id 0.24.2 → 0.24.5
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/sdk/browser-session-route.d.ts +1 -0
- package/dist/sdk/browser-session-route.js +11 -1
- package/dist/sdk/client/create-flow.js +3 -25
- package/dist/sdk/client/profile-button.d.ts +1 -1
- package/dist/sdk/client/profile-button.js +35 -8
- package/dist/sdk/session-route.js +8 -0
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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
|
|
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() { } };
|
|
@@ -32,14 +32,19 @@ export function createProfileButton(options) {
|
|
|
32
32
|
button.dataset.flowProfile = "";
|
|
33
33
|
Object.assign(button.style, {
|
|
34
34
|
display: "flex",
|
|
35
|
+
boxSizing: "border-box",
|
|
36
|
+
height: "var(--flow-profile-height, 2.25rem)",
|
|
37
|
+
flexShrink: "0",
|
|
35
38
|
alignItems: "center",
|
|
36
39
|
gap: "8px",
|
|
37
40
|
border: "0",
|
|
38
|
-
borderRadius: "
|
|
39
|
-
padding: "
|
|
40
|
-
background: "
|
|
41
|
+
borderRadius: "0",
|
|
42
|
+
padding: "0.25rem 0.75rem",
|
|
43
|
+
background: "transparent",
|
|
41
44
|
color: "CanvasText",
|
|
42
45
|
font: "inherit",
|
|
46
|
+
fontSize: "0.875rem",
|
|
47
|
+
lineHeight: "1.25rem",
|
|
43
48
|
cursor: "pointer",
|
|
44
49
|
pointerEvents: "auto",
|
|
45
50
|
maxWidth: "240px",
|
|
@@ -59,14 +64,21 @@ export function createProfileButton(options) {
|
|
|
59
64
|
display: "flex",
|
|
60
65
|
alignItems: "center",
|
|
61
66
|
justifyContent: "center",
|
|
62
|
-
width: "
|
|
63
|
-
height: "
|
|
64
|
-
borderRadius: "
|
|
67
|
+
width: "calc(var(--flow-profile-height, 2.25rem) - 0.5rem)",
|
|
68
|
+
height: "calc(var(--flow-profile-height, 2.25rem) - 0.5rem)",
|
|
69
|
+
borderRadius: "var(--squircle-radius, 35%)",
|
|
70
|
+
// biome-ignore lint/plugin: CSSStyleDeclaration requires the browser's property name.
|
|
71
|
+
cornerShape: "superellipse(1.6)",
|
|
65
72
|
overflow: "hidden",
|
|
66
73
|
background: "color-mix(in srgb, currentColor 10%, transparent)",
|
|
67
74
|
flexShrink: "0",
|
|
68
75
|
});
|
|
69
76
|
const name = document.createElement("span");
|
|
77
|
+
Object.assign(name.style, {
|
|
78
|
+
minWidth: "0",
|
|
79
|
+
overflow: "hidden",
|
|
80
|
+
textOverflow: "ellipsis",
|
|
81
|
+
});
|
|
70
82
|
button.append(avatar, name);
|
|
71
83
|
const fallback = document.createElement("a");
|
|
72
84
|
fallback.href = `${host}/account`;
|
|
@@ -81,7 +93,9 @@ export function createProfileButton(options) {
|
|
|
81
93
|
function update(refresh = false) {
|
|
82
94
|
const user = flow.getState().user;
|
|
83
95
|
name.textContent = user?.username ?? "Flow ID";
|
|
84
|
-
button.setAttribute("aria-label",
|
|
96
|
+
button.setAttribute("aria-label", !user || user.isGuest
|
|
97
|
+
? "Sign in to Flow ID"
|
|
98
|
+
: `Open ${user.username} Flow ID account in a new tab`);
|
|
85
99
|
const identityChanged = user?.id !== lastUser?.id ||
|
|
86
100
|
user?.username !== lastUser?.username ||
|
|
87
101
|
user?.isGuest !== lastUser?.isGuest;
|
|
@@ -140,6 +154,19 @@ export function createProfileButton(options) {
|
|
|
140
154
|
});
|
|
141
155
|
}
|
|
142
156
|
button.addEventListener("click", () => {
|
|
157
|
+
const user = flow.getState().user;
|
|
158
|
+
if (!user || user.isGuest) {
|
|
159
|
+
if (button.disabled)
|
|
160
|
+
return;
|
|
161
|
+
button.disabled = true;
|
|
162
|
+
notice.textContent = "";
|
|
163
|
+
fallback.hidden = true;
|
|
164
|
+
void flow.login().catch(() => {
|
|
165
|
+
button.disabled = false;
|
|
166
|
+
notice.textContent = "Could not start sign-in. Try again.";
|
|
167
|
+
});
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
143
170
|
const opened = flow.openAccount();
|
|
144
171
|
notice.textContent = opened
|
|
145
172
|
? ""
|
|
@@ -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)
|