@flow-industries/id 0.15.0 → 0.17.0
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/client/flow-widget.d.ts +20 -0
- package/dist/sdk/client/flow-widget.js +78 -0
- package/dist/sdk/client/iframe-host.d.ts +12 -0
- package/dist/sdk/client/iframe-host.js +14 -0
- package/dist/sdk/client/index.d.ts +2 -1
- package/dist/sdk/client/index.js +1 -0
- package/dist/sdk/client/profile-button.js +8 -1
- package/dist/sdk/react/flow-widget.d.ts +12 -0
- package/dist/sdk/react/flow-widget.js +37 -0
- package/dist/sdk/react/index.d.ts +2 -1
- package/dist/sdk/react/index.js +1 -0
- package/dist/sdk/types/auth.d.ts +62 -0
- package/dist/sdk/types/dialog.d.ts +13 -0
- package/dist/sdk/types/events.d.ts +15 -2
- package/dist/sdk/types/index.d.ts +5 -4
- package/dist/sdk/types/messenger.d.ts +7 -0
- package/dist/sdk/types/room-events.d.ts +133 -0
- package/dist/sdk/types/room-events.js +14 -0
- package/dist/sdk/types/rooms.d.ts +36 -0
- package/dist/sdk/types/sdk.d.ts +48 -0
- package/package.json +4 -2
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FlowWidgetHandle, MountFlowWidgetOptions } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Mounts one of the inline Flow ID widgets — the XP strip, the action timer —
|
|
4
|
+
* as a transparent iframe the embedder positions and sizes itself.
|
|
5
|
+
*
|
|
6
|
+
* The reason this exists rather than embedders hand-rolling an `<iframe>`: the
|
|
7
|
+
* widget reads the Flow ID API from a cross-site frame, where its own origin's
|
|
8
|
+
* cookie is unavailable or bound to a different audience, so it needs the
|
|
9
|
+
* host's access token. It gets one by asking over the postMessage bridge, and
|
|
10
|
+
* only a frame that received the `init` handshake knows which origin to ask.
|
|
11
|
+
* A hand-rolled iframe never sends `init` and never gets an answer, so it is
|
|
12
|
+
* silently limited to whatever the cookie happens to allow (AUTH-171).
|
|
13
|
+
*
|
|
14
|
+
* The handle exposes the frame instead of styling it, because each embedder
|
|
15
|
+
* wants different geometry (the in-game overlay is fixed and click-through,
|
|
16
|
+
* the menu's is a laid-out block) and none of that belongs in the SDK.
|
|
17
|
+
*
|
|
18
|
+
* No-op under SSR.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createFlowWidget(options: MountFlowWidgetOptions): FlowWidgetHandle;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { resolveIdHost } from "../id-host";
|
|
2
|
+
import { getFlow, requireFlow } from "./create-flow";
|
|
3
|
+
import { answerTokenRequest, bridgeToWindow, makeIframe } from "./iframe-host";
|
|
4
|
+
/**
|
|
5
|
+
* The inline widgets an embedder may mount, mapped to the dialog routes that
|
|
6
|
+
* serve them. Callers name a widget rather than passing a route so the dialog's
|
|
7
|
+
* URL space stays an internal detail and an embedder can't point this at an
|
|
8
|
+
* auth route, which would render a sign-in ceremony inside a decorative frame.
|
|
9
|
+
*/
|
|
10
|
+
const WIDGET_ROUTE = {
|
|
11
|
+
xp: "/dialog/xp-widget",
|
|
12
|
+
"action-timer": "/dialog/action-timer",
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Mounts one of the inline Flow ID widgets — the XP strip, the action timer —
|
|
16
|
+
* as a transparent iframe the embedder positions and sizes itself.
|
|
17
|
+
*
|
|
18
|
+
* The reason this exists rather than embedders hand-rolling an `<iframe>`: the
|
|
19
|
+
* widget reads the Flow ID API from a cross-site frame, where its own origin's
|
|
20
|
+
* cookie is unavailable or bound to a different audience, so it needs the
|
|
21
|
+
* host's access token. It gets one by asking over the postMessage bridge, and
|
|
22
|
+
* only a frame that received the `init` handshake knows which origin to ask.
|
|
23
|
+
* A hand-rolled iframe never sends `init` and never gets an answer, so it is
|
|
24
|
+
* silently limited to whatever the cookie happens to allow (AUTH-171).
|
|
25
|
+
*
|
|
26
|
+
* The handle exposes the frame instead of styling it, because each embedder
|
|
27
|
+
* wants different geometry (the in-game overlay is fixed and click-through,
|
|
28
|
+
* the menu's is a laid-out block) and none of that belongs in the SDK.
|
|
29
|
+
*
|
|
30
|
+
* No-op under SSR.
|
|
31
|
+
*/
|
|
32
|
+
export function createFlowWidget(options) {
|
|
33
|
+
if (typeof document === "undefined")
|
|
34
|
+
return {
|
|
35
|
+
frame: null,
|
|
36
|
+
post() { },
|
|
37
|
+
destroy() { },
|
|
38
|
+
};
|
|
39
|
+
const flow = options.flow ?? getFlow() ?? requireFlow();
|
|
40
|
+
const host = resolveIdHost(options.host ?? flow.host);
|
|
41
|
+
const hostOrigin = new URL(host).origin;
|
|
42
|
+
const theme = options.theme ?? "light dark";
|
|
43
|
+
const route = WIDGET_ROUTE[options.widget];
|
|
44
|
+
const frame = makeIframe(`${host}${route}`);
|
|
45
|
+
frame.style.background = "transparent";
|
|
46
|
+
const container = options.container ?? document.body;
|
|
47
|
+
// Appended before bridging: `contentWindow` is null until the frame is in the
|
|
48
|
+
// document, and the bridge is bound to that window.
|
|
49
|
+
container.appendChild(frame);
|
|
50
|
+
const bridge = bridgeToWindow(frame.contentWindow, {
|
|
51
|
+
targetOrigin: hostOrigin,
|
|
52
|
+
});
|
|
53
|
+
bridge.on("__internal", (payload) => {
|
|
54
|
+
if (payload.type === "profile-token-request")
|
|
55
|
+
void answerTokenRequest(bridge, flow, payload.id);
|
|
56
|
+
});
|
|
57
|
+
// The widget already loads its own route directly, so `route` here only
|
|
58
|
+
// confirms where the frame is; what the handshake is really for is telling
|
|
59
|
+
// the dialog which origin it is embedded by, which is what it later asks for
|
|
60
|
+
// a token.
|
|
61
|
+
void bridge.send("__internal", {
|
|
62
|
+
type: "init",
|
|
63
|
+
mode: "iframe",
|
|
64
|
+
referrer: { title: document.title },
|
|
65
|
+
theme: { colorScheme: theme },
|
|
66
|
+
route,
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
frame,
|
|
70
|
+
post(message) {
|
|
71
|
+
frame.contentWindow?.postMessage(message, hostOrigin);
|
|
72
|
+
},
|
|
73
|
+
destroy() {
|
|
74
|
+
bridge.destroy();
|
|
75
|
+
frame.remove();
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as Messenger from "../dialog/remote/Messenger";
|
|
2
|
+
import type { Flow } from "../types";
|
|
2
3
|
/**
|
|
3
4
|
* Permissions the dialog iframe needs to run WebAuthn passkey ceremonies and
|
|
4
5
|
* copy recovery values. Shared by every Flow iframe host (the dialog host and
|
|
@@ -21,3 +22,14 @@ export declare function makeIframe(src: string): HTMLIFrameElement;
|
|
|
21
22
|
export declare function bridgeToWindow(target: Window, options?: {
|
|
22
23
|
targetOrigin?: string;
|
|
23
24
|
}): Messenger.Bridge;
|
|
25
|
+
/**
|
|
26
|
+
* Answers a widget's request for the host's credential. Every Flow iframe that
|
|
27
|
+
* reads the Flow ID API from a cross-site frame asks for this, because its own
|
|
28
|
+
* origin's cookie is unavailable or bound to another audience there.
|
|
29
|
+
*
|
|
30
|
+
* `getToken` refreshes a token that is missing or near expiry, so a widget left
|
|
31
|
+
* open past the 1h access-token lifetime still gets a live one rather than a
|
|
32
|
+
* 401. A failure answers `null` — "no session", which widgets render as signed
|
|
33
|
+
* out — instead of leaving the request to time out.
|
|
34
|
+
*/
|
|
35
|
+
export declare function answerTokenRequest(bridge: Messenger.Bridge, flow: Flow, id: string): Promise<void>;
|
|
@@ -32,3 +32,17 @@ export function bridgeToWindow(target, options = {}) {
|
|
|
32
32
|
waitForReady: true,
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Answers a widget's request for the host's credential. Every Flow iframe that
|
|
37
|
+
* reads the Flow ID API from a cross-site frame asks for this, because its own
|
|
38
|
+
* origin's cookie is unavailable or bound to another audience there.
|
|
39
|
+
*
|
|
40
|
+
* `getToken` refreshes a token that is missing or near expiry, so a widget left
|
|
41
|
+
* open past the 1h access-token lifetime still gets a live one rather than a
|
|
42
|
+
* 401. A failure answers `null` — "no session", which widgets render as signed
|
|
43
|
+
* out — instead of leaving the request to time out.
|
|
44
|
+
*/
|
|
45
|
+
export async function answerTokenRequest(bridge, flow, id) {
|
|
46
|
+
const token = await flow.getToken().catch(() => null);
|
|
47
|
+
void bridge.send("__internal", { type: "profile-token", id, token });
|
|
48
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { defaultIdHost, isLocalHostname } from "../id-host";
|
|
2
|
-
export type { AccessKeyOptions, AdditionalSession, Address, ConnectCapabilities, ConnectResponse, CreateFlowOptions, DialogHost, Flow, FlowCredential, FlowSessionState, FlowState, FlowUser, LoginOptions, MethodName, MountProfileOptions, ProfileButtonHandle, ProfilePosition, Session, } from "../types";
|
|
2
|
+
export type { AccessKeyOptions, AdditionalSession, Address, ConnectCapabilities, ConnectResponse, CreateFlowOptions, DialogHost, Flow, FlowCredential, FlowSessionState, FlowState, FlowUser, FlowWidgetHandle, FlowWidgetName, LoginOptions, MethodName, MountFlowWidgetOptions, MountProfileOptions, ProfileButtonHandle, ProfilePosition, Session, } from "../types";
|
|
3
3
|
export { createFlow, getFlow, requireFlow, resetFlow } from "./create-flow";
|
|
4
4
|
export { createDialogHost } from "./dialog-host";
|
|
5
|
+
export { createFlowWidget } from "./flow-widget";
|
|
5
6
|
export { METHODS } from "./methods";
|
|
6
7
|
export { createProfileButton } from "./profile-button";
|
|
7
8
|
export { createRoomsApi, RoomsRequestError } from "./rooms";
|
package/dist/sdk/client/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { defaultIdHost, isLocalHostname } from "../id-host";
|
|
2
2
|
export { createFlow, getFlow, requireFlow, resetFlow } from "./create-flow";
|
|
3
3
|
export { createDialogHost } from "./dialog-host";
|
|
4
|
+
export { createFlowWidget } from "./flow-widget";
|
|
4
5
|
export { METHODS } from "./methods";
|
|
5
6
|
export { createProfileButton } from "./profile-button";
|
|
6
7
|
export { createRoomsApi, RoomsRequestError } from "./rooms";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveIdHost } from "../id-host";
|
|
2
2
|
import { getFlow, requireFlow } from "./create-flow";
|
|
3
|
-
import { bridgeToWindow, makeIframe } from "./iframe-host";
|
|
3
|
+
import { answerTokenRequest, bridgeToWindow, makeIframe } from "./iframe-host";
|
|
4
4
|
const POSITION_STYLE = {
|
|
5
5
|
"top-right": { top: "0", right: "0" },
|
|
6
6
|
"top-left": { top: "0", left: "0" },
|
|
@@ -105,6 +105,9 @@ export function createProfileButton(options) {
|
|
|
105
105
|
else if (payload.type === "profile-expand") {
|
|
106
106
|
showDialog();
|
|
107
107
|
}
|
|
108
|
+
else if (payload.type === "profile-token-request") {
|
|
109
|
+
void answerTokenRequest(pillBridge, flow, payload.id);
|
|
110
|
+
}
|
|
108
111
|
});
|
|
109
112
|
// ----- the dialog overlay (lazy; a separate fullscreen iframe layered ABOVE
|
|
110
113
|
// the pill, so the pill shows through its dimmed backdrop) -----
|
|
@@ -131,6 +134,10 @@ export function createProfileButton(options) {
|
|
|
131
134
|
hideDialog();
|
|
132
135
|
void flow.logout().catch(() => { });
|
|
133
136
|
}
|
|
137
|
+
else if (payload.type === "profile-token-request") {
|
|
138
|
+
if (dialogBridge)
|
|
139
|
+
void answerTokenRequest(dialogBridge, flow, payload.id);
|
|
140
|
+
}
|
|
134
141
|
});
|
|
135
142
|
void dialogBridge.send("__internal", {
|
|
136
143
|
type: "profile-identity",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FlowWidgetProps } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Drops an inline Flow ID widget — the XP strip, the action timer — into a
|
|
4
|
+
* React tree. Renders a host element (style it via `className` for placement
|
|
5
|
+
* and size) that the widget iframe fills. Resolves the Flow instance from a
|
|
6
|
+
* `<FlowIdProvider>` or the createFlow() singleton.
|
|
7
|
+
*
|
|
8
|
+
* Prefer this over embedding the widget's URL in your own `<iframe>`: only a
|
|
9
|
+
* frame mounted this way completes the handshake that lets it authenticate as
|
|
10
|
+
* the signed-in user from a cross-site page (AUTH-171).
|
|
11
|
+
*/
|
|
12
|
+
export declare function FlowWidget({ widget, className, host, theme, }: FlowWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { createFlowWidget } from "../client/flow-widget";
|
|
4
|
+
import { useFlow } from "./hooks";
|
|
5
|
+
/**
|
|
6
|
+
* Drops an inline Flow ID widget — the XP strip, the action timer — into a
|
|
7
|
+
* React tree. Renders a host element (style it via `className` for placement
|
|
8
|
+
* and size) that the widget iframe fills. Resolves the Flow instance from a
|
|
9
|
+
* `<FlowIdProvider>` or the createFlow() singleton.
|
|
10
|
+
*
|
|
11
|
+
* Prefer this over embedding the widget's URL in your own `<iframe>`: only a
|
|
12
|
+
* frame mounted this way completes the handshake that lets it authenticate as
|
|
13
|
+
* the signed-in user from a cross-site page (AUTH-171).
|
|
14
|
+
*/
|
|
15
|
+
export function FlowWidget({ widget, className, host, theme, }) {
|
|
16
|
+
const flow = useFlow();
|
|
17
|
+
const ref = useRef(null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const container = ref.current;
|
|
20
|
+
if (!container)
|
|
21
|
+
return;
|
|
22
|
+
const handle = createFlowWidget({
|
|
23
|
+
widget,
|
|
24
|
+
container,
|
|
25
|
+
flow,
|
|
26
|
+
...(host ? { host } : {}),
|
|
27
|
+
...(theme ? { theme } : {}),
|
|
28
|
+
});
|
|
29
|
+
if (handle.frame) {
|
|
30
|
+
handle.frame.style.width = "100%";
|
|
31
|
+
handle.frame.style.height = "100%";
|
|
32
|
+
handle.frame.style.display = "block";
|
|
33
|
+
}
|
|
34
|
+
return () => handle.destroy();
|
|
35
|
+
}, [widget, flow, host, theme]);
|
|
36
|
+
return _jsx("div", { ref: ref, className: className });
|
|
37
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export type { FlowIdProviderProps, ProfileButtonProps } from "../types";
|
|
1
|
+
export type { FlowIdProviderProps, FlowWidgetProps, ProfileButtonProps, } from "../types";
|
|
2
|
+
export { FlowWidget } from "./flow-widget";
|
|
2
3
|
export { useFlow, useFlowId, useFlowState, useRoom, useRooms } from "./hooks";
|
|
3
4
|
export { ProfileButton } from "./profile-button";
|
|
4
5
|
export { FlowIdProvider } from "./provider";
|
package/dist/sdk/react/index.js
CHANGED
package/dist/sdk/types/auth.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { JWTPayload } from "jose";
|
|
2
|
+
import type { AuthEventName } from "./events";
|
|
2
3
|
export type FlowUser = {
|
|
3
4
|
id: string;
|
|
4
5
|
username: string;
|
|
@@ -14,6 +15,17 @@ export type FlowCredential = {
|
|
|
14
15
|
id: string;
|
|
15
16
|
publicKey: string;
|
|
16
17
|
};
|
|
18
|
+
/** The better-auth session user with Flow's additional fields — the one
|
|
19
|
+
* shape routes cast `session.user` to instead of ad-hoc inline casts. */
|
|
20
|
+
export interface SessionUser {
|
|
21
|
+
id: string;
|
|
22
|
+
email?: string | null;
|
|
23
|
+
emailVerified?: boolean;
|
|
24
|
+
username?: string | null;
|
|
25
|
+
isGuest?: boolean;
|
|
26
|
+
role?: string | null;
|
|
27
|
+
image?: string | null;
|
|
28
|
+
}
|
|
17
29
|
/**
|
|
18
30
|
* A session minted for one of the ADDITIONAL audiences a login requested
|
|
19
31
|
* (AUTH-39): its own refresh-token lineage and access JWT, both bound to
|
|
@@ -61,6 +73,56 @@ export type VerifyOptions = {
|
|
|
61
73
|
audience: string;
|
|
62
74
|
issuerUrl?: string;
|
|
63
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* One entry in the signed-in user's session list (`GET /api/account/sessions`).
|
|
78
|
+
* An entry is either a cookie session (with the activity of its linked app
|
|
79
|
+
* refresh lineages folded in) or an app-only refresh lineage whose cookie
|
|
80
|
+
* session no longer exists. `id` is an opaque revocation handle — never a
|
|
81
|
+
* token, and never another user's row.
|
|
82
|
+
*/
|
|
83
|
+
export type AccountSession = {
|
|
84
|
+
id: string;
|
|
85
|
+
/** The app origin the session was opened for; null on a pre-audience row. */
|
|
86
|
+
audience: string | null;
|
|
87
|
+
/** Coarse "Browser · OS" from the sign-in user agent; null when unknown. */
|
|
88
|
+
device: string | null;
|
|
89
|
+
createdAt: string;
|
|
90
|
+
/** Latest activity across the cookie session and its app refresh lineages. */
|
|
91
|
+
lastSeenAt: string;
|
|
92
|
+
expiresAt: string;
|
|
93
|
+
/** True for the session serving this request. */
|
|
94
|
+
isCurrent: boolean;
|
|
95
|
+
};
|
|
96
|
+
export type AccountSessionsResponse = {
|
|
97
|
+
sessions: AccountSession[];
|
|
98
|
+
};
|
|
99
|
+
/** Result of `DELETE /api/account/sessions/:id`. */
|
|
100
|
+
export type RevokeSessionResponse = {
|
|
101
|
+
revoked: true;
|
|
102
|
+
/** True when the caller revoked the session serving the request itself. */
|
|
103
|
+
wasCurrent: boolean;
|
|
104
|
+
};
|
|
105
|
+
/** Result of `POST /api/account/sessions/revoke-all`. */
|
|
106
|
+
export type RevokeAllSessionsResponse = {
|
|
107
|
+
revokedSessions: number;
|
|
108
|
+
revokedLineages: number;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* One entry of the user-facing security feed
|
|
112
|
+
* (`GET /api/account/security-events`). Country and coarse device only —
|
|
113
|
+
* the stored ip and raw user agent never leave the server.
|
|
114
|
+
*/
|
|
115
|
+
export type SecurityActivityEntry = {
|
|
116
|
+
id: string;
|
|
117
|
+
event: AuthEventName;
|
|
118
|
+
audience: string | null;
|
|
119
|
+
country: string | null;
|
|
120
|
+
device: string | null;
|
|
121
|
+
createdAt: string;
|
|
122
|
+
};
|
|
123
|
+
export type SecurityActivityResponse = {
|
|
124
|
+
events: SecurityActivityEntry[];
|
|
125
|
+
};
|
|
64
126
|
export type VerifiedFlowJWT = JWTPayload & {
|
|
65
127
|
sub: string;
|
|
66
128
|
username?: string;
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async view state for a dialog panel — the three states every fetched
|
|
3
|
+
* section renders (spinner / retry row / content), so "empty" stays
|
|
4
|
+
* distinguishable from "not loaded yet".
|
|
5
|
+
*/
|
|
6
|
+
export type Loadable<T> = {
|
|
7
|
+
status: "loading";
|
|
8
|
+
} | {
|
|
9
|
+
status: "error";
|
|
10
|
+
} | {
|
|
11
|
+
status: "ready";
|
|
12
|
+
data: T;
|
|
13
|
+
};
|
|
1
14
|
export type DialogReferrer = {
|
|
2
15
|
icon?: string | {
|
|
3
16
|
light: string;
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* here are the contract every dashboard/alert query depends on — changing one
|
|
5
5
|
* is a breaking change to the dashboard.
|
|
6
6
|
*/
|
|
7
|
+
import type { GlobalRole } from "./rooms";
|
|
7
8
|
export type AuthOutcome = "success" | "failure" | "info";
|
|
8
9
|
export type AuthMode = "sign-up" | "sign-in";
|
|
9
10
|
/** Client-only funnel steps reported via the `/api/events` beacon. */
|
|
10
11
|
export type FunnelStep = "mode_selected" | "email_entered" | "ceremony_started" | "ceremony_failed" | "done_shown";
|
|
11
|
-
export type AuthEventName = "auth.username.checked" | "auth.signup.succeeded" | "auth.signup.failed" | "auth.otp.sent" | "auth.otp.verified" | "auth.otp.failed" | "auth.email.verify.sent" | "auth.email.verify.succeeded" | "auth.email.verify.failed" | "auth.email.changed" | "auth.avatar.upload.succeeded" | "auth.avatar.upload.failed" | "auth.challenge.issued" | "auth.signin.succeeded" | "auth.signin.failed" | "auth.passkey.added" | "auth.passkey.add_failed" | "auth.restore.succeeded" | "auth.restore.failed" | "auth.restore.no_session" | "auth.refresh.succeeded" | "auth.refresh.failed" | "auth.refresh.reuse" | "auth.refresh.grace" | "auth.jwt.verified" | "auth.jwt.rejected" | "auth.signout" | "auth.audience.rejected" | "auth.audience.minted" | "auth.guest.created" | "auth.guest.restored" | "auth.guest.upgraded" | "auth.guest.failed" | "auth.funnel.mode_selected" | "auth.funnel.email_entered" | "auth.funnel.ceremony_started" | "auth.funnel.ceremony_failed" | "auth.funnel.done_shown";
|
|
12
|
-
export type AuthErrorCode = "username_taken" | "credential_taken" | "email_taken" | "email_not_verified" | "no_email" | "image_upload_forbidden" | "image_upload_rate_limited" | "invalid_image_type" | "image_too_large" | "image_upload_failed" | "otp_invalid" | "otp_expired" | "otp_attempts_exceeded" | "otp_resend_cooldown" | "otp_resend_limit" | "otp_global_limit" | "otp_send_failed" | "challenge_expired" | "unknown_credential" | "invalid_assertion_type" | "invalid_assertion_origin" | "user_verification_required" | "invalid_signature" | "user_not_found" | "missing_audience" | "audience_not_allowed" | "audience_mismatch" | "no_session" | "no_passkey" | "refresh_token_invalid" | "refresh_token_expired" | "refresh_epoch_stale" | "refresh_reuse_detected" | "guest_rate_limited" | "guest_global_limit" | "guest_username_exhausted" | "guest_session" | "passkey_exists" | "already_upgraded" | "malformed_token" | "unknown_key" | "verification_failed" | "webauthn_not_allowed" | "webauthn_security" | "webauthn_invalid_state" | "webauthn_not_supported" | "webauthn_constraint" | "webauthn_aborted" | "webauthn_unknown" | "internal_error";
|
|
12
|
+
export type AuthEventName = "auth.username.checked" | "auth.signup.succeeded" | "auth.signup.failed" | "auth.otp.sent" | "auth.otp.verified" | "auth.otp.failed" | "auth.email.verify.sent" | "auth.email.verify.succeeded" | "auth.email.verify.failed" | "auth.email.changed" | "auth.avatar.upload.succeeded" | "auth.avatar.upload.failed" | "auth.challenge.issued" | "auth.signin.succeeded" | "auth.signin.failed" | "auth.passkey.added" | "auth.passkey.add_failed" | "auth.restore.succeeded" | "auth.restore.failed" | "auth.restore.no_session" | "auth.refresh.succeeded" | "auth.refresh.failed" | "auth.refresh.reuse" | "auth.refresh.grace" | "auth.jwt.verified" | "auth.jwt.rejected" | "auth.signout" | "auth.session.revoked" | "auth.session.revoked_all" | "auth.audience.rejected" | "auth.audience.minted" | "auth.guest.created" | "auth.guest.restored" | "auth.guest.upgraded" | "auth.guest.failed" | "auth.role.granted" | "auth.role.revoked" | "auth.funnel.mode_selected" | "auth.funnel.email_entered" | "auth.funnel.ceremony_started" | "auth.funnel.ceremony_failed" | "auth.funnel.done_shown" | "room_event.activated" | "room_event.completed" | "room_event.reminder_dispatched" | "room_event.reminder_failed";
|
|
13
|
+
export type AuthErrorCode = "username_taken" | "credential_taken" | "email_taken" | "email_not_verified" | "no_email" | "image_upload_forbidden" | "image_upload_rate_limited" | "invalid_image_type" | "image_too_large" | "image_upload_failed" | "otp_invalid" | "otp_expired" | "otp_attempts_exceeded" | "otp_resend_cooldown" | "otp_resend_limit" | "otp_global_limit" | "otp_send_failed" | "challenge_expired" | "unknown_credential" | "invalid_assertion_type" | "invalid_assertion_origin" | "user_verification_required" | "invalid_signature" | "user_not_found" | "missing_audience" | "audience_not_allowed" | "audience_mismatch" | "no_session" | "no_passkey" | "refresh_token_invalid" | "refresh_token_expired" | "refresh_epoch_stale" | "refresh_user_epoch_stale" | "refresh_reuse_detected" | "guest_rate_limited" | "guest_global_limit" | "guest_username_exhausted" | "guest_session" | "passkey_exists" | "already_upgraded" | "malformed_token" | "unknown_key" | "verification_failed" | "webauthn_not_allowed" | "webauthn_security" | "webauthn_invalid_state" | "webauthn_not_supported" | "webauthn_constraint" | "webauthn_aborted" | "webauthn_unknown" | "internal_error";
|
|
13
14
|
/** One flat record per event = one row in the `auth_events` stream. */
|
|
14
15
|
export interface AuthEventRecord {
|
|
15
16
|
service: "auth";
|
|
@@ -26,11 +27,23 @@ export interface AuthEventRecord {
|
|
|
26
27
|
mode: AuthMode | null;
|
|
27
28
|
step: FunnelStep | null;
|
|
28
29
|
errorCode: AuthErrorCode | null;
|
|
30
|
+
/** Role-audit fields: who changed whose global role, from what, to what.
|
|
31
|
+
* `userId`/`username` carry the target. */
|
|
32
|
+
actorId: string | null;
|
|
33
|
+
roleFrom: GlobalRole | null;
|
|
34
|
+
roleTo: GlobalRole | null;
|
|
29
35
|
ip: string | null;
|
|
30
36
|
country: string | null;
|
|
31
37
|
userAgent: string | null;
|
|
32
38
|
durationMs: number | null;
|
|
33
39
|
traceId: string | null;
|
|
40
|
+
/** Room-event scheduler fields: which series and dated instance a transition
|
|
41
|
+
* or dispatch was about, and for a dispatch, which reminder and how many
|
|
42
|
+
* subscribers it reached. */
|
|
43
|
+
roomEventId: string | null;
|
|
44
|
+
occurrenceId: string | null;
|
|
45
|
+
dispatchKind: string | null;
|
|
46
|
+
recipients: number | null;
|
|
34
47
|
}
|
|
35
48
|
/** Body accepted by `POST /api/events` from the dialog. */
|
|
36
49
|
export interface BeaconBody {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
export type { AdditionalSession, AuthConfig, AuthResponse, AuthResponseWithWebAuthn, FlowCredential, FlowUser, PasskeyPluginOptions, VerifiedFlowJWT, VerifyOptions, WebAuthnSignature, } from "./auth";
|
|
2
|
-
export type { BoundaryError, DialogCustomFeatures, DialogCustomLabels, DialogError, DialogReferrer, DialogState, ProfileData, ProfileIdentity, } from "./dialog";
|
|
1
|
+
export type { AccountSession, AccountSessionsResponse, AdditionalSession, AuthConfig, AuthResponse, AuthResponseWithWebAuthn, FlowCredential, FlowUser, PasskeyPluginOptions, RevokeAllSessionsResponse, RevokeSessionResponse, SecurityActivityEntry, SecurityActivityResponse, SessionUser, VerifiedFlowJWT, VerifyOptions, WebAuthnSignature, } from "./auth";
|
|
2
|
+
export type { BoundaryError, DialogCustomFeatures, DialogCustomLabels, DialogError, DialogReferrer, DialogState, Loadable, ProfileData, ProfileIdentity, } from "./dialog";
|
|
3
3
|
export type { AuthErrorCode, AuthEventName, AuthEventRecord, AuthMode, AuthOutcome, BeaconBody, FunnelStep, } from "./events";
|
|
4
4
|
export type { Bridge, BridgeParameters, FlowAccount, FlowRemote, FlowRemoteConfig, FromWindowOptions, MessageResponse, Messenger, OneOf, Payload, QueuedRequest, ReadyOptions, RemoteFlowState, RemoteState, Schema, Storage, Topic, WithReady, } from "./messenger";
|
|
5
5
|
export type { Call, ConnectCapabilities, ConnectRequest, ConnectResponse, GuestRequest, GuestResponse, MethodName, MethodParams, MethodResult, RestoreResponse, RpcRequest, SendCallsParams, SendCallsRequest, SendCallsResponse, SendTransactionParams, SendTransactionRequest, SendTransactionResponse, SignMessageRequest, SignMessageResponse, SignOutRequest, SignOutResponse, SignTypedDataRequest, SignTypedDataResponse, TransactionArgs, TypedData, TypedDataDomain, TypedDataField, } from "./protocol";
|
|
6
6
|
export { getConnectCapabilities, isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
|
|
7
|
-
export type {
|
|
8
|
-
export type {
|
|
7
|
+
export type { CreateRoomEventInput, RoomEventAttendance, RoomEventFrequency, RoomEventInstance, RoomEventInterest, RoomEventInterestState, RoomEventList, RoomEventOccurrence, RoomEventRecurrence, RoomEventRoomRef, RoomEventSeries, RoomEventStatus, SetInterestInput, UpdateRoomEventInput, } from "./room-events";
|
|
8
|
+
export type { CreateRoomInput, GlobalRole, ModerationSubject, MyRooms, RoleChangeVerdict, RoomChannel, RoomDetail, RoomList, RoomMemberEntry, RoomMembers, RoomOccupancy, RoomOwner, RoomPresenceEntry, RoomPresenceSnapshot, RoomRestrictionKind, RoomRole, RoomSummary, RoomSurfaceSettings, RoomsApi, RoomVisibility, StaffEntry, UpdateRoomInput, VerifyRoomContext, Viewer, } from "./rooms";
|
|
9
|
+
export type { AccessKeyOptions, AccessKeyPreparation, Address, CreateDialogHostOptions, CreateFlowOptions, DialogHost, DialogOpenOptions, FinalizeAccessKeyParams, Flow, FlowConnectorParameters, FlowCookieNames, FlowIdProviderProps, FlowSessionState, FlowState, FlowWidgetHandle, FlowWidgetName, FlowWidgetProps, Listener, LoginOptions, MountFlowWidgetOptions, MountProfileOptions, PrepareArgsWithAuth, PrepareTransactionRequestPhase, ProfileButtonHandle, ProfileButtonProps, ProfilePosition, ResolveAccountParams, ResolvedAccessKeyOptions, RootCredential, RunLoginParams, RunLoginResult, SendCallsArgs, SendTransactionArgs, Session, SigningContext, SignMessageArgs, SignTypedDataArgs, Store, StoredAccessKey, WagmiConnectCapabilities, WagmiConnectParams, } from "./sdk";
|
|
9
10
|
export type { ResolvedFlowSession, ResolveSessionOptions, SessionRouteOptions, SessionRouteResponse, SessionRouteSession, } from "./server";
|
|
10
11
|
export type { CoinAsset, IdentifiedTx, TxApprove, TxConvert, TxSend, TxSwap, } from "./tx";
|
|
11
12
|
export type { ActionDayContext, ActionEventKind, ActionSessionState, ActiveActionResponse, LevelProgress, PublicProfile, XpGrantResult, XpRecentGrant, XpSummary, } from "./xp";
|
|
@@ -90,6 +90,13 @@ export type Schema = [
|
|
|
90
90
|
username: string;
|
|
91
91
|
isGuest: boolean;
|
|
92
92
|
} | null;
|
|
93
|
+
} | {
|
|
94
|
+
type: "profile-token-request";
|
|
95
|
+
id: string;
|
|
96
|
+
} | {
|
|
97
|
+
type: "profile-token";
|
|
98
|
+
id: string;
|
|
99
|
+
token: string | null;
|
|
93
100
|
} | {
|
|
94
101
|
type: "profile-login";
|
|
95
102
|
mode: "signin" | "signup";
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Room events — scheduled happenings inside a room, shared by the server
|
|
3
|
+
* routes and the client SDK.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately named `room-events` throughout: `types/events.ts` and
|
|
6
|
+
* `routes/events.ts` already mean structured product/telemetry events, and the
|
|
7
|
+
* two must never blur.
|
|
8
|
+
*
|
|
9
|
+
* Two shapes, and which one an endpoint speaks is load-bearing. A
|
|
10
|
+
* {@link RoomEventSeries} is what an owner authors and edits; an instance is
|
|
11
|
+
* one dated occurrence of it. Players only ever address occurrences — interest,
|
|
12
|
+
* reminders and attendance all attach to an instance, so a weekly race's third
|
|
13
|
+
* week is a thing in its own right.
|
|
14
|
+
*/
|
|
15
|
+
/** Discord's Guild Scheduled Event lifecycle, mirrored exactly. */
|
|
16
|
+
export type RoomEventStatus = "scheduled" | "active" | "completed" | "cancelled";
|
|
17
|
+
export type RoomEventFrequency = "daily" | "weekly" | "monthly";
|
|
18
|
+
/**
|
|
19
|
+
* The RRULE subset a series may repeat on. Expanded in the event's IANA
|
|
20
|
+
* timezone by the (db-free) expander, never in UTC. `until` is an ISO instant;
|
|
21
|
+
* `until` and `count` are mutually exclusive and both may be absent for an
|
|
22
|
+
* open-ended series.
|
|
23
|
+
*/
|
|
24
|
+
export interface RoomEventRecurrence {
|
|
25
|
+
freq: RoomEventFrequency;
|
|
26
|
+
interval?: number;
|
|
27
|
+
/** 0 = Sunday … 6 = Saturday, matching `Date.prototype.getDay`. */
|
|
28
|
+
byweekday?: number[];
|
|
29
|
+
bymonthday?: number[];
|
|
30
|
+
until?: string;
|
|
31
|
+
count?: number;
|
|
32
|
+
}
|
|
33
|
+
/** The room an event belongs to, denormalized so a listing needs no second read. */
|
|
34
|
+
export interface RoomEventRoomRef {
|
|
35
|
+
id: string;
|
|
36
|
+
slug: string;
|
|
37
|
+
displayName: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Interest in one dated instance. `interestedCount` is public; the two viewer
|
|
41
|
+
* flags are meaningful only when the request carried a bearer and read false
|
|
42
|
+
* otherwise — the same shape the room payload uses for the caller's role.
|
|
43
|
+
*
|
|
44
|
+
* A player counts as interested in an instance either by marking that instance
|
|
45
|
+
* or by following its whole series, so `viewerInterested` can be true while
|
|
46
|
+
* `viewerFollowing` is what actually produced it.
|
|
47
|
+
*/
|
|
48
|
+
export interface RoomEventInterest {
|
|
49
|
+
interestedCount: number;
|
|
50
|
+
viewerInterested: boolean;
|
|
51
|
+
viewerFollowing: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* One dated instance, as it appears under the series that owns it: only what
|
|
55
|
+
* differs per instance, since the series already carries the title, room and
|
|
56
|
+
* timezone. `startsAt`/`endsAt` are ISO instants in UTC — render them in the
|
|
57
|
+
* series' `timezone` to show the local time the owner scheduled.
|
|
58
|
+
*/
|
|
59
|
+
export interface RoomEventInstance extends RoomEventInterest {
|
|
60
|
+
id: string;
|
|
61
|
+
startsAt: string;
|
|
62
|
+
endsAt: string | null;
|
|
63
|
+
status: RoomEventStatus;
|
|
64
|
+
/** Moved or cancelled on its own, so a series-wide edit leaves it alone. */
|
|
65
|
+
overridden: boolean;
|
|
66
|
+
/** Written once the instance completes — the history view reads these rather
|
|
67
|
+
* than scanning presence. Null while it has not finished. */
|
|
68
|
+
attendance: RoomEventAttendance | null;
|
|
69
|
+
}
|
|
70
|
+
/** What actually happened, as observed from room presence while it ran. */
|
|
71
|
+
export interface RoomEventAttendance {
|
|
72
|
+
attendeeCount: number;
|
|
73
|
+
peakConcurrent: number;
|
|
74
|
+
startedAt: string | null;
|
|
75
|
+
endedAt: string | null;
|
|
76
|
+
}
|
|
77
|
+
/** An instance standing on its own in a listing, carrying enough of its series
|
|
78
|
+
* and room to render a card. */
|
|
79
|
+
export interface RoomEventOccurrence extends RoomEventInstance {
|
|
80
|
+
eventId: string;
|
|
81
|
+
room: RoomEventRoomRef;
|
|
82
|
+
title: string;
|
|
83
|
+
description: string | null;
|
|
84
|
+
coverUrl: string | null;
|
|
85
|
+
timezone: string;
|
|
86
|
+
/** True when the parent series repeats, so a card can badge it as recurring. */
|
|
87
|
+
recurring: boolean;
|
|
88
|
+
createdBy: string | null;
|
|
89
|
+
}
|
|
90
|
+
/** The authored series, with the instances it has materialized so far. */
|
|
91
|
+
export interface RoomEventSeries {
|
|
92
|
+
id: string;
|
|
93
|
+
room: RoomEventRoomRef;
|
|
94
|
+
title: string;
|
|
95
|
+
description: string | null;
|
|
96
|
+
coverUrl: string | null;
|
|
97
|
+
startsAt: string;
|
|
98
|
+
endsAt: string | null;
|
|
99
|
+
timezone: string;
|
|
100
|
+
recurrence: RoomEventRecurrence | null;
|
|
101
|
+
/** Minutes before the start at which subscribers are reminded; null is the
|
|
102
|
+
* default schedule, an empty list is silence. */
|
|
103
|
+
reminderOffsets: number[] | null;
|
|
104
|
+
status: RoomEventStatus;
|
|
105
|
+
createdBy: string | null;
|
|
106
|
+
createdAt: string;
|
|
107
|
+
updatedAt: string;
|
|
108
|
+
occurrences: RoomEventInstance[];
|
|
109
|
+
}
|
|
110
|
+
export interface RoomEventList {
|
|
111
|
+
events: RoomEventOccurrence[];
|
|
112
|
+
}
|
|
113
|
+
export interface CreateRoomEventInput {
|
|
114
|
+
title: string;
|
|
115
|
+
description?: string | null;
|
|
116
|
+
coverUrl?: string | null;
|
|
117
|
+
startsAt: string;
|
|
118
|
+
endsAt?: string | null;
|
|
119
|
+
timezone?: string;
|
|
120
|
+
recurrence?: RoomEventRecurrence | null;
|
|
121
|
+
reminderOffsets?: number[] | null;
|
|
122
|
+
}
|
|
123
|
+
/** Every create field, all optional — a patch is merged over the stored row and
|
|
124
|
+
* validated by the same rules, so the two shapes can never drift. */
|
|
125
|
+
export type UpdateRoomEventInput = Partial<CreateRoomEventInput>;
|
|
126
|
+
export interface SetInterestInput {
|
|
127
|
+
/** Also follow (or unfollow) the whole series, not just this instance. */
|
|
128
|
+
series?: boolean;
|
|
129
|
+
}
|
|
130
|
+
/** What the interest endpoints answer with, so a card can update in place. */
|
|
131
|
+
export interface RoomEventInterestState extends RoomEventInterest {
|
|
132
|
+
occurrenceId: string;
|
|
133
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Room events — scheduled happenings inside a room, shared by the server
|
|
3
|
+
* routes and the client SDK.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately named `room-events` throughout: `types/events.ts` and
|
|
6
|
+
* `routes/events.ts` already mean structured product/telemetry events, and the
|
|
7
|
+
* two must never blur.
|
|
8
|
+
*
|
|
9
|
+
* Two shapes, and which one an endpoint speaks is load-bearing. A
|
|
10
|
+
* {@link RoomEventSeries} is what an owner authors and edits; an instance is
|
|
11
|
+
* one dated occurrence of it. Players only ever address occurrences — interest,
|
|
12
|
+
* reminders and attendance all attach to an instance, so a weekly race's third
|
|
13
|
+
* week is a thing in its own right.
|
|
14
|
+
*/
|
|
@@ -5,6 +5,42 @@ export type RoomVisibility = "public" | "unlisted" | "private";
|
|
|
5
5
|
* Member rows carry moderator|member.
|
|
6
6
|
*/
|
|
7
7
|
export type RoomRole = "owner" | "moderator" | "member";
|
|
8
|
+
/**
|
|
9
|
+
* Global permission tier held on the user row, composing over room roles: an
|
|
10
|
+
* admin holds owner-power in any room, a platform moderator holds mod-power
|
|
11
|
+
* anywhere. Read from the DB at enforcement time — never a JWT claim — so a
|
|
12
|
+
* demotion is instant.
|
|
13
|
+
*/
|
|
14
|
+
export type GlobalRole = "user" | "moderator" | "admin";
|
|
15
|
+
/** What the moderation lattice ranks: a subject's global tier plus their
|
|
16
|
+
* room-axis role (`owner` from `room.ownerId`, else the member row). */
|
|
17
|
+
export interface ModerationSubject {
|
|
18
|
+
globalRole: GlobalRole;
|
|
19
|
+
roomRole: RoomRole | null;
|
|
20
|
+
}
|
|
21
|
+
/** A verified caller resolved against one room: the raw composite the rank
|
|
22
|
+
* lattice needs, plus the wire projection every route-side gate compares. */
|
|
23
|
+
export interface Viewer {
|
|
24
|
+
sub: string;
|
|
25
|
+
guest: boolean;
|
|
26
|
+
subject: ModerationSubject;
|
|
27
|
+
role: RoomRole | null;
|
|
28
|
+
}
|
|
29
|
+
/** One row of `GET /api/admin/staff` — a user holding a non-`user` tier. */
|
|
30
|
+
export interface StaffEntry {
|
|
31
|
+
userId: string;
|
|
32
|
+
username: string;
|
|
33
|
+
role: GlobalRole;
|
|
34
|
+
}
|
|
35
|
+
/** Outcome of a global-role change request: refused with a reason, or
|
|
36
|
+
* allowed with the audit event it is (`null` for a no-op). */
|
|
37
|
+
export type RoleChangeVerdict = {
|
|
38
|
+
allowed: true;
|
|
39
|
+
event: "auth.role.granted" | "auth.role.revoked" | null;
|
|
40
|
+
} | {
|
|
41
|
+
allowed: false;
|
|
42
|
+
reason: "self_target" | "guest_target";
|
|
43
|
+
};
|
|
8
44
|
export type RoomChannel = "game" | "voice" | "text";
|
|
9
45
|
export type RoomRestrictionKind = "ban" | "mute";
|
|
10
46
|
export interface RoomOwner {
|
package/dist/sdk/types/sdk.d.ts
CHANGED
|
@@ -217,6 +217,54 @@ export type ProfileButtonHandle = {
|
|
|
217
217
|
/** Tears down the iframe, listeners, and any auto-created container. */
|
|
218
218
|
destroy: () => void;
|
|
219
219
|
};
|
|
220
|
+
/** The inline Flow ID widgets an embedder can mount alongside its own UI. */
|
|
221
|
+
export type FlowWidgetName = "xp" | "action-timer";
|
|
222
|
+
export type MountFlowWidgetOptions = {
|
|
223
|
+
/** Which inline widget to mount. */
|
|
224
|
+
widget: FlowWidgetName;
|
|
225
|
+
/**
|
|
226
|
+
* Element to append the widget iframe to. Defaults to `document.body`, which
|
|
227
|
+
* is what a fixed-position overlay wants; pass a container to lay the widget
|
|
228
|
+
* out inline instead.
|
|
229
|
+
*/
|
|
230
|
+
container?: HTMLElement;
|
|
231
|
+
/**
|
|
232
|
+
* The Flow ID origin serving the widget (e.g. https://id.flow.industries).
|
|
233
|
+
* Defaults to the resolved Flow instance's `host`, then the SDK default.
|
|
234
|
+
*/
|
|
235
|
+
host?: string;
|
|
236
|
+
/**
|
|
237
|
+
* Color scheme for the widget chrome. Set this to match the host (the dark
|
|
238
|
+
* game UI passes "dark"). Defaults to "light dark" (follows the OS).
|
|
239
|
+
*/
|
|
240
|
+
theme?: "light" | "dark" | "light dark";
|
|
241
|
+
/** Explicit Flow instance. Defaults to the createFlow() singleton. */
|
|
242
|
+
flow?: Flow;
|
|
243
|
+
};
|
|
244
|
+
export type FlowWidgetHandle = {
|
|
245
|
+
/**
|
|
246
|
+
* The mounted iframe, so the embedder owns geometry and visibility. Null
|
|
247
|
+
* under SSR, where nothing was mounted.
|
|
248
|
+
*/
|
|
249
|
+
readonly frame: HTMLIFrameElement | null;
|
|
250
|
+
/**
|
|
251
|
+
* Sends a widget-specific message (e.g. `{ type: "xp-refresh" }`), pinned to
|
|
252
|
+
* the Flow ID origin.
|
|
253
|
+
*/
|
|
254
|
+
post: (message: unknown) => void;
|
|
255
|
+
/** Tears down the iframe and its bridge. */
|
|
256
|
+
destroy: () => void;
|
|
257
|
+
};
|
|
258
|
+
export type FlowWidgetProps = {
|
|
259
|
+
/** Which inline widget to mount. */
|
|
260
|
+
widget: FlowWidgetName;
|
|
261
|
+
/** Class applied to the host element the widget iframe fills. */
|
|
262
|
+
className?: string;
|
|
263
|
+
/** Override the Flow ID origin; defaults to the resolved Flow's `host`. */
|
|
264
|
+
host?: string;
|
|
265
|
+
/** Color scheme for the widget chrome; defaults to "light dark" (the OS). */
|
|
266
|
+
theme?: "light" | "dark" | "light dark";
|
|
267
|
+
};
|
|
220
268
|
export type DialogHost = {
|
|
221
269
|
open: (options?: DialogOpenOptions) => void;
|
|
222
270
|
close: () => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flow-industries/id",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"main": "./dist/sdk/client/index.js",
|
|
5
5
|
"module": "./dist/sdk/client/index.js",
|
|
6
6
|
"types": "./dist/sdk/client/index.d.ts",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"build:sdk": "tsc --project tsconfig.sdk.json",
|
|
59
59
|
"prepublishOnly": "bun run build:sdk",
|
|
60
60
|
"start": "bun run src/index.ts",
|
|
61
|
+
"worker": "bun run src/worker.ts",
|
|
61
62
|
"email:dev": "email dev --dir src/emails --port 3010",
|
|
62
63
|
"db:generate": "bunx @better-auth/cli generate",
|
|
63
64
|
"db:migrate:gen": "bunx drizzle-kit generate",
|
|
@@ -91,6 +92,7 @@
|
|
|
91
92
|
"devDependencies": {
|
|
92
93
|
"@better-auth/cli": "^1.4.17",
|
|
93
94
|
"@biomejs/biome": "2.4.12",
|
|
95
|
+
"@electric-sql/pglite": "^0.5.4",
|
|
94
96
|
"@flow-industries/lint": "0.1.0",
|
|
95
97
|
"@react-email/ui": "^6.6.0",
|
|
96
98
|
"@tailwindcss/vite": "^4.1.18",
|
|
@@ -112,7 +114,7 @@
|
|
|
112
114
|
},
|
|
113
115
|
"dependencies": {
|
|
114
116
|
"@aws-sdk/client-s3": "^3.1073.0",
|
|
115
|
-
"@flow-industries/ui": "^0.
|
|
117
|
+
"@flow-industries/ui": "^0.19.0",
|
|
116
118
|
"@hono/otel": "^1.1.2",
|
|
117
119
|
"@openobserve/browser-logs": "^0.3.1",
|
|
118
120
|
"@openobserve/browser-rum": "^0.3.1",
|