@flow-industries/id 0.23.1 → 0.23.2

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/README.md CHANGED
@@ -53,7 +53,7 @@ app path; read the new session after navigation instead of continuing after
53
53
 
54
54
  `ProfileButton` and `flow.openAccount()` open `/account` in a normal new tab.
55
55
  The source app stays loaded and refreshes its session on refocus. Sign-in and
56
- own-account management no longer use an embedded dialog. See the
56
+ own-account management no longer use an embedded dialog. The remaining dialog supports signing, public profiles, and widgets. SDK `ConnectResponse` remains a deprecated type alias for source compatibility; sign-in itself returns through the first-party callback. See the
57
57
  [integration guide](docs/integration-guide.md) for server wiring and migration.
58
58
 
59
59
  ## Public profile overlays
@@ -72,7 +72,7 @@ export function createFlow(options = {}) {
72
72
  if (currentFlow)
73
73
  return currentFlow;
74
74
  const host = resolveIdHost(options.host);
75
- const dialogUrl = `${host}/dialog/?v=2`;
75
+ const dialogUrl = `${host}/dialog/`;
76
76
  const sessionPath = options.sessionPath ?? DEFAULT_SESSION_PATH;
77
77
  const rpId = options.rpId ??
78
78
  (isLocalHostname(window.location.hostname) ? "localhost" : undefined);
@@ -1,19 +1,7 @@
1
1
  import type { CreateDialogHostOptions, DialogHost } from "../types";
2
2
  /**
3
- * Creates a host that owns the dialog iframe (or popup) and exposes an RPC
4
- * channel into the Flow auth dialog at `id.flow.industries`.
5
- *
6
- * The iframe is mounted lazily on first use, kept hidden until `open()` is
7
- * called, and reused across requests so a single passkey-bound iframe handles
8
- * login, signing, and silent restore. The iframe is required (not just
9
- * `fetch`) because it's first-party to id.flow.industries and is the only way
10
- * to read the cross-origin cookie session in third-party-cookie-blocking
11
- * browsers (Safari, Firefox).
12
- *
13
- * Returned methods:
14
- * - `request()` — open the dialog UI and dispatch an RPC (interactive flows)
15
- * - `requestSilent()` — dispatch without showing the dialog (silent restore)
16
- * - `open()`/`close()` — manual visibility control
17
- * - `destroy()` — tear down the iframe and abort pending requests
3
+ * Creates the retained signing dialog host. Its iframe mounts lazily and is
4
+ * reused across signing requests. Authentication uses the first-party session
5
+ * handler and top-level authorization page independently.
18
6
  */
19
7
  export declare function createDialogHost(options: CreateDialogHostOptions): DialogHost;
@@ -16,21 +16,9 @@ const VISIBLE_STYLE = {
16
16
  background: "transparent",
17
17
  };
18
18
  /**
19
- * Creates a host that owns the dialog iframe (or popup) and exposes an RPC
20
- * channel into the Flow auth dialog at `id.flow.industries`.
21
- *
22
- * The iframe is mounted lazily on first use, kept hidden until `open()` is
23
- * called, and reused across requests so a single passkey-bound iframe handles
24
- * login, signing, and silent restore. The iframe is required (not just
25
- * `fetch`) because it's first-party to id.flow.industries and is the only way
26
- * to read the cross-origin cookie session in third-party-cookie-blocking
27
- * browsers (Safari, Firefox).
28
- *
29
- * Returned methods:
30
- * - `request()` — open the dialog UI and dispatch an RPC (interactive flows)
31
- * - `requestSilent()` — dispatch without showing the dialog (silent restore)
32
- * - `open()`/`close()` — manual visibility control
33
- * - `destroy()` — tear down the iframe and abort pending requests
19
+ * Creates the retained signing dialog host. Its iframe mounts lazily and is
20
+ * reused across signing requests. Authentication uses the first-party session
21
+ * handler and top-level authorization page independently.
34
22
  */
35
23
  export function createDialogHost(options) {
36
24
  const { host, container = document.body } = options;
@@ -187,17 +175,15 @@ export function createDialogHost(options) {
187
175
  });
188
176
  });
189
177
  }
190
- /** Opens the dialog UI and dispatches an interactive RPC (login, sign, etc.). */
178
+ /** Opens the dialog UI and dispatches a signing RPC. */
191
179
  async function request(method, params) {
192
180
  ensureFrame();
193
181
  open();
194
182
  return dispatchRequest(method, params);
195
183
  }
196
184
  /**
197
- * Dispatches an RPC without showing the dialog UI. Used for signInHeadless flows
198
- * (silent restore, refresh, sign-out) where the dialog route runs invisibly
199
- * and resolves immediately. The iframe is still mounted so postMessage
200
- * works, but its `display` stays `none`.
185
+ * @deprecated Use request() for signing. Retained for callers that manage
186
+ * visibility manually; this does not support background authentication.
201
187
  */
202
188
  async function requestSilent(method, params) {
203
189
  ensureFrame();
@@ -47,7 +47,7 @@ export function createFlowWidget(options) {
47
47
  const hostOrigin = new URL(host).origin;
48
48
  let theme = options.theme ?? "light dark";
49
49
  const route = WIDGET_ROUTE[options.widget];
50
- const frame = makeIframe(`${host}${route}?v=2`, WIDGET_TITLE[options.widget]);
50
+ const frame = makeIframe(`${host}${route}`, WIDGET_TITLE[options.widget]);
51
51
  frame.style.background = "transparent";
52
52
  const container = options.container ?? document.body;
53
53
  // Appended before bridging: `contentWindow` is null until the frame is in the
@@ -1,9 +1,6 @@
1
1
  export declare const METHODS: {
2
- readonly connect: "wallet_connect";
3
2
  readonly signMessage: "personal_sign";
4
3
  readonly signTypedData: "eth_signTypedData";
5
4
  readonly sendTransaction: "eth_sendTransaction";
6
5
  readonly sendCalls: "wallet_sendCalls";
7
- readonly guest: "wallet_guest";
8
- readonly signOut: "wallet_signout";
9
6
  };
@@ -1,9 +1,6 @@
1
1
  export const METHODS = {
2
- connect: "wallet_connect",
3
2
  signMessage: "personal_sign",
4
3
  signTypedData: "eth_signTypedData",
5
4
  sendTransaction: "eth_sendTransaction",
6
5
  sendCalls: "wallet_sendCalls",
7
- guest: "wallet_guest",
8
- signOut: "wallet_signout",
9
6
  };
@@ -30,7 +30,7 @@ function createViewer(options) {
30
30
  setOverlayFocus(frame, ready && visible);
31
31
  }
32
32
  function mount(username) {
33
- const el = makeIframe(`${host}/dialog/?v=2`, "Flow ID profile");
33
+ const el = makeIframe(`${host}/dialog/`, "Flow ID profile");
34
34
  el.dataset.flowProfileView = "";
35
35
  el.inert = true;
36
36
  Object.assign(el.style, OVERLAY_STYLE, { pointerEvents: "none" });
@@ -43,10 +43,6 @@ function createViewer(options) {
43
43
  targetOrigin: hostOrigin,
44
44
  });
45
45
  bridge = opened;
46
- // The dialog SPA has no deep-link history fallback, so the frame loads at
47
- // `/dialog/` and `init` asks it to land on the profile. Sending the route
48
- // here rather than as a follow-up message keeps the sign-in root from ever
49
- // mounting, even for the frame it takes to navigate away from it.
50
46
  sendBridgeNotification(opened, "__internal", {
51
47
  type: "init",
52
48
  mode: "iframe",
@@ -63,21 +59,7 @@ function createViewer(options) {
63
59
  .catch(() => { });
64
60
  opened.on("close", () => close());
65
61
  opened.on("__internal", (payload) => {
66
- // A viewer looking at their own profile can reach the account view from
67
- // here, which offers the same sign-in and sign-out the pill's dialog
68
- // does. Those run on the host — it owns the session — so dropping them
69
- // would leave the buttons doing nothing at all.
70
- if (payload.type === "profile-login") {
71
- close();
72
- void flow
73
- .login(payload.mode === "signup" ? { signUp: true } : { signIn: true })
74
- .catch(() => { });
75
- }
76
- else if (payload.type === "profile-logout") {
77
- close();
78
- void flow.logout().catch(() => { });
79
- }
80
- else if (payload.type === "profile-token-request") {
62
+ if (payload.type === "profile-token-request") {
81
63
  void answerTokenRequest(opened, flow, payload.id);
82
64
  }
83
65
  });
@@ -13,7 +13,7 @@ export declare function restoreCredential(store: Store<FlowState>): Promise<void
13
13
  * Clears local-only auth state: active credential in IDB, the access key for
14
14
  * the current address (if any), and the in-memory store. Does NOT touch the
15
15
  * server cookie session — the caller (createFlow.logout) handles that
16
- * separately via `wallet_signout`.
16
+ * separately through the first-party session handler.
17
17
  */
18
18
  export declare function runLogout(store: Store<FlowState>): Promise<void>;
19
19
  /**
@@ -24,7 +24,7 @@ export async function restoreCredential(store) {
24
24
  * Clears local-only auth state: active credential in IDB, the access key for
25
25
  * the current address (if any), and the in-memory store. Does NOT touch the
26
26
  * server cookie session — the caller (createFlow.logout) handles that
27
- * separately via `wallet_signout`.
27
+ * separately through the first-party session handler.
28
28
  */
29
29
  export async function runLogout(store) {
30
30
  const state = store.getSnapshot();
@@ -11,8 +11,8 @@ export { GAME_LIFECYCLE_EVENT_NAMES } from "./game";
11
11
  export type { AccountProfileData } from "./landing";
12
12
  export type { Bridge, BridgeParameters, FlowAccount, FlowRemote, FlowRemoteConfig, FromWindowOptions, MessageResponse, Messenger, OneOf, Payload, QueuedRequest, ReadyOptions, RemoteFlowState, RemoteState, Schema, Storage, Topic, WithReady, } from "./messenger";
13
13
  export type { OtpVerificationFailure, OtpVerificationResult, VerificationAdapter, } from "./otp";
14
- 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";
15
- export { getConnectCapabilities, isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
14
+ export type { Call, ConnectCapabilities, ConnectResponse, MethodName, MethodParams, MethodResult, RestoreResponse, RpcRequest, SendCallsParams, SendCallsRequest, SendCallsResponse, SendTransactionParams, SendTransactionRequest, SendTransactionResponse, SignMessageRequest, SignMessageResponse, SignTypedDataRequest, SignTypedDataResponse, TransactionArgs, TypedData, TypedDataDomain, TypedDataField, } from "./protocol";
15
+ export { isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
16
16
  export type { ReportOperation, ReportRequest, ReportResponse, ReportsApi, ReportTransport, } from "./reports";
17
17
  export type { CreateRoomEventInput, RoomEventArchive, RoomEventAttendance, RoomEventFrequency, RoomEventInstance, RoomEventInterest, RoomEventInterestState, RoomEventList, RoomEventOccurrence, RoomEventRecurrence, RoomEventRoomRef, RoomEventRun, RoomEventSeries, RoomEventStatus, SetInterestInput, UpdateRoomEventInput, } from "./room-events";
18
18
  export type { CreateRoomInput, GlobalRole, ModerationSubject, MyRooms, PlayerPositionReport, RoleChangeVerdict, RoomCapabilities, RoomCapability, RoomChannel, RoomDetail, RoomList, RoomMemberEntry, RoomMembers, RoomOccupancy, RoomOwner, RoomPlayerPosition, RoomPresenceEntry, RoomPresenceSnapshot, RoomRestrictionKind, RoomRole, RoomSummary, RoomSurfaceSettings, RoomsApi, RoomVisibility, StaffEntry, UpdateRoomInput, VerifyRoomContext, Viewer, VoiceDecisionReason, VoiceDecisionSubject, VoiceRoomDecision, } from "./rooms";
@@ -1,3 +1,3 @@
1
1
  export { BODY_REGIONS, COSMETIC_MATERIALS } from "./cosmetics";
2
2
  export { GAME_LIFECYCLE_EVENT_NAMES } from "./game";
3
- export { getConnectCapabilities, isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
3
+ export { isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
@@ -100,11 +100,6 @@ export type Schema = [
100
100
  type: "profile-token";
101
101
  id: string;
102
102
  token: string | null;
103
- } | {
104
- type: "profile-login";
105
- mode: "signin" | "signup";
106
- } | {
107
- type: "profile-logout";
108
103
  } | {
109
104
  type: "dialog-shown";
110
105
  } | {
@@ -1,18 +1,16 @@
1
1
  import type { RawRecord, RawValue } from "../json";
2
2
  import type { AdditionalSession, FlowCredential, FlowUser, WebAuthnSignature } from "./auth";
3
3
  import type { Address } from "./sdk";
4
- export type MethodName = "wallet_connect" | "personal_sign" | "eth_signTypedData" | "eth_sendTransaction" | "wallet_sendCalls" | "wallet_guest" | "wallet_signout";
4
+ export type MethodName = "personal_sign" | "eth_signTypedData" | "eth_sendTransaction" | "wallet_sendCalls";
5
5
  export type ConnectCapabilities = {
6
6
  createAccount?: boolean;
7
7
  signIn?: boolean;
8
8
  accessKeyHash?: string;
9
+ /** @deprecated Sign-in always uses the dedicated top-level page. */
9
10
  signInHeadless?: boolean;
10
11
  credentialId?: string;
11
12
  /**
12
- * The current guest's access JWT, forwarded so a sign-up upgrades that guest
13
- * in place even where the guest cookie is unreadable (the iOS top-level
14
- * sign-up popup). The server verifies it before letting it stand in for the
15
- * cookie session; see the register endpoint.
13
+ * @deprecated Guest proof is managed by the first-party session handler.
16
14
  */
17
15
  guestToken?: string;
18
16
  /**
@@ -22,9 +20,7 @@ export type ConnectCapabilities = {
22
20
  */
23
21
  additionalAudiences?: readonly string[];
24
22
  };
25
- export type ConnectRequest = [{
26
- capabilities?: ConnectCapabilities;
27
- }];
23
+ /** @deprecated Login navigates; use SessionRouteResponse for completed sessions. */
28
24
  export type ConnectResponse = {
29
25
  jwt: string;
30
26
  /** First-party rotating refresh token; the SDK persists it in the app origin. */
@@ -83,43 +79,17 @@ export type RestoreResponse = {
83
79
  credential: FlowCredential | null;
84
80
  address: Address | null;
85
81
  };
86
- export type GuestRequest = [] | [{
87
- additionalAudiences?: readonly string[];
88
- }];
89
- /**
90
- * A guest has no passkey and no derivable wallet address yet, so `credential`
91
- * and `address` are always null — the shape mirrors RestoreResponse so the SDK
92
- * can commit either to the same store fields.
93
- */
94
- export type GuestResponse = {
95
- jwt: string;
96
- refreshToken: string;
97
- user: FlowUser;
98
- credential: null;
99
- address: null;
100
- additionalSessions?: AdditionalSession[];
101
- };
102
- export type SignOutRequest = [];
103
- export type SignOutResponse = {
104
- ok: true;
105
- };
106
82
  export type MethodParams = {
107
- wallet_connect: ConnectRequest;
108
83
  personal_sign: SignMessageRequest;
109
84
  eth_signTypedData: SignTypedDataRequest;
110
85
  eth_sendTransaction: SendTransactionRequest;
111
86
  wallet_sendCalls: SendCallsRequest;
112
- wallet_guest: GuestRequest;
113
- wallet_signout: SignOutRequest;
114
87
  };
115
88
  export type MethodResult = {
116
- wallet_connect: ConnectResponse;
117
89
  personal_sign: SignMessageResponse;
118
90
  eth_signTypedData: SignTypedDataResponse;
119
91
  eth_sendTransaction: SendTransactionResponse;
120
92
  wallet_sendCalls: SendCallsResponse;
121
- wallet_guest: GuestResponse;
122
- wallet_signout: SignOutResponse;
123
93
  };
124
94
  export type RpcRequest = {
125
95
  id: string | number;
@@ -143,12 +113,6 @@ export type SendCallsParams = {
143
113
  chainId?: string;
144
114
  capabilities?: RawRecord;
145
115
  };
146
- /**
147
- * Unwraps the connect capabilities from a wallet_connect RPC request (they ride
148
- * as the first param), or undefined. Several dialog surfaces read them (mode,
149
- * accessKeyHash, guestToken), so the cast lives here rather than being repeated.
150
- */
151
- export declare function getConnectCapabilities(request: RpcRequest | undefined): ConnectCapabilities | undefined;
152
116
  export declare function isPersonalSignParams(params: readonly unknown[] | undefined): params is readonly [string, string];
153
117
  export declare function isSendTransactionParams(params: readonly unknown[] | undefined): params is readonly [SendTransactionParams];
154
118
  export declare function isSendCallsParams(params: readonly unknown[] | undefined): params is readonly [SendCallsParams];
@@ -1,15 +1,3 @@
1
- /**
2
- * Unwraps the connect capabilities from a wallet_connect RPC request (they ride
3
- * as the first param), or undefined. Several dialog surfaces read them (mode,
4
- * accessKeyHash, guestToken), so the cast lives here rather than being repeated.
5
- */
6
- export function getConnectCapabilities(request) {
7
- const first = request?.params?.[0];
8
- const found = Object.entries(Object(first)).find(([k]) => k === "capabilities")?.[1];
9
- /* SAFETY: the field is read off this app's own wallet_connect params, whose capabilities
10
- block is defined by ConnectCapabilities; a missing one answers undefined. */
11
- return found;
12
- }
13
1
  export function isPersonalSignParams(params) {
14
2
  if (!params || params.length < 2)
15
3
  return false;
@@ -90,8 +90,8 @@ export type CreateFlowOptions = {
90
90
  */
91
91
  initialState?: FlowSessionState | null;
92
92
  /**
93
- * Extra audiences every dialog mint (login, guest) requests refresh tokens
94
- * for, on top of the app's own (AUTH-39). Only audiences the auth server
93
+ * Extra audiences to receive sessions after the app session is installed.
94
+ * Only audiences the auth server
95
95
  * explicitly allowlists for this origin succeed — anything else fails the
96
96
  * mint. The minted sessions are delivered once via `onAdditionalSessions`
97
97
  * and never stored; the app forwards each to its own origin (e.g. the
@@ -229,7 +229,7 @@ export type ProfileButtonHandle = {
229
229
  export type OpenProfileOptions = {
230
230
  /**
231
231
  * Called once when the overlay closes, including its close button, backdrop,
232
- * Escape, closeProfile(), or a sign-in/sign-out handoff. Runs after the
232
+ * Escape, closeProfile(), or an own-account tab handoff. Runs after the
233
233
  * overlay stops accepting input, without waiting for the exit animation.
234
234
  * The latest successful open replaces this callback; omitting it clears the
235
235
  * previous callback. Rejected opens and repeated closes do not notify.
@@ -314,6 +314,7 @@ export type DialogHost = {
314
314
  close: () => void;
315
315
  destroy: () => void;
316
316
  request: <T = unknown>(method: string, params?: readonly unknown[]) => Promise<T>;
317
+ /** @deprecated Manual signing-dialog visibility only; authentication redirects. */
317
318
  requestSilent: <T = unknown>(method: string, params?: readonly unknown[]) => Promise<T>;
318
319
  messenger: import("./messenger").Messenger;
319
320
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flow-industries/id",
3
- "version": "0.23.1",
3
+ "version": "0.23.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -66,10 +66,9 @@
66
66
  "scripts": {
67
67
  "dev": "./dev.sh",
68
68
  "build:dialog": "bunx vite build",
69
- "build:legacy-dialog": "bunx vite build --config vite.legacy.config.ts",
70
69
  "build:playground": "bunx vite build --config vite.playground.config.ts",
71
70
  "build:landing": "bunx vite build --config vite.landing.config.ts",
72
- "build": "bun run build:legacy-dialog && bunx vite build && bunx vite build --config vite.playground.config.ts && bunx vite build --config vite.landing.config.ts",
71
+ "build": "bunx vite build && bunx vite build --config vite.playground.config.ts && bunx vite build --config vite.landing.config.ts",
73
72
  "build:sdk": "tsc --project tsconfig.sdk.json",
74
73
  "prepublishOnly": "bun run build:sdk",
75
74
  "start": "bun run src/index.ts",
@@ -85,7 +84,7 @@
85
84
  "test:sdk-package": "bash scripts/test-sdk-package.sh",
86
85
  "format": "biome format --write",
87
86
  "check": "biome check --write",
88
- "typecheck": "tsr generate && (cd src/legacy-dialog && bunx tsr generate) && tsc --noEmit && tsc -p tsconfig.legacy.json --noEmit",
87
+ "typecheck": "tsr generate && tsc --noEmit",
89
88
  "contracts:generate": "bun scripts/generate-contracts.ts",
90
89
  "contracts:check": "bun scripts/generate-contracts.ts --check && bun scripts/check-contract-compatibility.ts",
91
90
  "db:check": "bun scripts/db-check.ts",