@flow-industries/id 0.10.0 → 0.12.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.
@@ -0,0 +1,52 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * TanStack Start integration — the whole Flow ID wiring a Start app needs,
4
+ * so integrating a new domain is one route file plus one root wrapper:
5
+ *
6
+ * ```tsx
7
+ * // src/routes/flow.session.ts — the first-party session route + SSR fn
8
+ * import { createServerFn } from "@tanstack/react-start";
9
+ * import { createFileRoute } from "@tanstack/react-router";
10
+ * import { flowSessionHandlers, resolveFlowSessionRequest } from "@flow-industries/id/start/server";
11
+ *
12
+ * export const getFlowSession = createServerFn({ method: "GET" }).handler(resolveFlowSessionRequest);
13
+ * export const Route = createFileRoute("/flow/session")({ server: { handlers: flowSessionHandlers() } });
14
+ *
15
+ * // src/routes/__root.tsx
16
+ * beforeLoad: () => flowSessionContext(getFlowSession),
17
+ * // and in the root component:
18
+ * <FlowRoot session={session}>{children}</FlowRoot>
19
+ * ```
20
+ *
21
+ * The server fn stays in app source because TanStack's compiler splits it
22
+ * into the server bundle there; everything it does lives here.
23
+ */
24
+ import { useMemo } from "react";
25
+ import { createFlow, createStaticFlow, getFlow } from "../client";
26
+ import { FlowIdProvider } from "../react";
27
+ /**
28
+ * The `beforeLoad` body: during SSR resolve the session server-side (via the
29
+ * app's `getFlowSession` server fn, which appends rotated Set-Cookie values);
30
+ * in the browser snapshot the live singleton instead — no network.
31
+ */
32
+ export async function flowSessionContext(getSession) {
33
+ if (typeof window === "undefined")
34
+ return { session: await getSession() };
35
+ const flow = getFlow();
36
+ const session = flow?.user && flow.jwt
37
+ ? { user: flow.user, jwt: flow.jwt, address: flow.address }
38
+ : null;
39
+ return { session };
40
+ }
41
+ /**
42
+ * Renders the subtree under a request-scoped static Flow on the server and
43
+ * the seeded browser singleton on the client, so the first client render
44
+ * matches the SSR HTML and no bootstrap refresh runs while the hydrated JWT
45
+ * is fresh.
46
+ */
47
+ export function FlowRoot({ session, autoGuest, host, children, }) {
48
+ const flow = useMemo(() => typeof window === "undefined"
49
+ ? createStaticFlow(session, { host })
50
+ : createFlow({ initialState: session, autoGuest, host }), [session, autoGuest, host]);
51
+ return _jsx(FlowIdProvider, { flow: flow, children: children });
52
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Server half of the TanStack Start integration: the session-route handlers
3
+ * and the SSR resolve used by the app's `getFlowSession` server fn. Import
4
+ * only from app-source files the Start compiler splits server-side (the
5
+ * session route file) — see `@flow-industries/id/start` for the wiring.
6
+ */
7
+ import type { FlowSessionState, SessionRouteOptions } from "../types";
8
+ /**
9
+ * The `getFlowSession` server-fn handler: resolves the visitor's session
10
+ * from the request cookies during SSR. A server-side refresh rotates the
11
+ * token, so the rotated Set-Cookie values are appended to the response here
12
+ * rather than left to callers. The audience is pinned by `APP_ORIGIN`
13
+ * (mandatory behind a TLS-terminating proxy), falling back to the request
14
+ * origin in dev.
15
+ */
16
+ export declare function resolveFlowSessionRequest(): Promise<FlowSessionState | null>;
17
+ /**
18
+ * Route handlers for the app's session route file:
19
+ * `createFileRoute("/flow/session")({ server: { handlers: flowSessionHandlers() } })`.
20
+ * The route path must match the client's `sessionPath` (default
21
+ * `/flow/session`).
22
+ */
23
+ export declare function flowSessionHandlers(opts?: SessionRouteOptions): {
24
+ GET: ({ request }: {
25
+ request: Request;
26
+ }) => Promise<Response>;
27
+ POST: ({ request }: {
28
+ request: Request;
29
+ }) => Promise<Response>;
30
+ DELETE: ({ request }: {
31
+ request: Request;
32
+ }) => Promise<Response>;
33
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Server half of the TanStack Start integration: the session-route handlers
3
+ * and the SSR resolve used by the app's `getFlowSession` server fn. Import
4
+ * only from app-source files the Start compiler splits server-side (the
5
+ * session route file) — see `@flow-industries/id/start` for the wiring.
6
+ */
7
+ import { getRequestHeader, getRequestUrl, setResponseHeader, } from "@tanstack/react-start/server";
8
+ import { defaultAudience, defaultIdHost } from "../id-host";
9
+ import { resolveSession } from "../server";
10
+ import { handleSessionRequest } from "../session-route";
11
+ /**
12
+ * The `getFlowSession` server-fn handler: resolves the visitor's session
13
+ * from the request cookies during SSR. A server-side refresh rotates the
14
+ * token, so the rotated Set-Cookie values are appended to the response here
15
+ * rather than left to callers. The audience is pinned by `APP_ORIGIN`
16
+ * (mandatory behind a TLS-terminating proxy), falling back to the request
17
+ * origin in dev.
18
+ */
19
+ export async function resolveFlowSessionRequest() {
20
+ const audience = defaultAudience(getRequestUrl().origin);
21
+ const { state, setCookies } = await resolveSession(getRequestHeader("cookie"), { audience, issuerUrl: defaultIdHost(audience) });
22
+ if (setCookies.length > 0)
23
+ setResponseHeader("Set-Cookie", setCookies);
24
+ return state;
25
+ }
26
+ /**
27
+ * Route handlers for the app's session route file:
28
+ * `createFileRoute("/flow/session")({ server: { handlers: flowSessionHandlers() } })`.
29
+ * The route path must match the client's `sessionPath` (default
30
+ * `/flow/session`).
31
+ */
32
+ export function flowSessionHandlers(opts = {}) {
33
+ const handler = ({ request }) => handleSessionRequest(request, opts);
34
+ return { GET: handler, POST: handler, DELETE: handler };
35
+ }
@@ -5,7 +5,7 @@ export type { Bridge, BridgeParameters, FlowAccount, FlowRemote, FlowRemoteConfi
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
7
  export type { CreateRoomInput, MyRooms, RoomChannel, RoomDetail, RoomList, RoomMemberEntry, RoomMembers, RoomOccupancy, RoomOwner, RoomPresenceEntry, RoomPresenceSnapshot, RoomRestrictionKind, RoomRole, RoomSummary, RoomSurfaceSettings, RoomsApi, RoomVisibility, UpdateRoomInput, VerifyRoomContext, } from "./rooms";
8
- export type { AccessKeyOptions, AccessKeyPreparation, Address, CreateDialogHostOptions, CreateFlowOptions, DialogHost, DialogOpenOptions, FinalizeAccessKeyParams, Flow, FlowConnectorParameters, FlowCookieNames, FlowIdProviderProps, FlowSessionState, FlowState, Listener, LoginOptions, MountProfileOptions, PrepareArgsWithAuth, PrepareTransactionRequestPhase, ProfileButtonHandle, ProfileButtonProps, ProfilePosition, RefreshCookieConfig, ResolveAccountParams, ResolvedAccessKeyOptions, RootCredential, RunLoginParams, RunLoginResult, SendCallsArgs, SendTransactionArgs, Session, SigningContext, SignMessageArgs, SignTypedDataArgs, Store, StoredAccessKey, WagmiConnectCapabilities, WagmiConnectParams, } from "./sdk";
9
- export type { ResolvedFlowSession, ResolveSessionOptions } from "./server";
8
+ export type { AccessKeyOptions, AccessKeyPreparation, Address, CreateDialogHostOptions, CreateFlowOptions, DialogHost, DialogOpenOptions, FinalizeAccessKeyParams, Flow, FlowConnectorParameters, FlowCookieNames, FlowIdProviderProps, FlowSessionState, FlowState, Listener, LoginOptions, MountProfileOptions, PrepareArgsWithAuth, PrepareTransactionRequestPhase, ProfileButtonHandle, ProfileButtonProps, ProfilePosition, ResolveAccountParams, ResolvedAccessKeyOptions, RootCredential, RunLoginParams, RunLoginResult, SendCallsArgs, SendTransactionArgs, Session, SigningContext, SignMessageArgs, SignTypedDataArgs, Store, StoredAccessKey, WagmiConnectCapabilities, WagmiConnectParams, } from "./sdk";
9
+ export type { ResolvedFlowSession, ResolveSessionOptions, SessionRouteOptions, SessionRouteResponse, SessionRouteSession, } from "./server";
10
10
  export type { CoinAsset, IdentifiedTx, TxApprove, TxConvert, TxSend, TxSwap, } from "./tx";
11
11
  export type { ActionDayContext, ActionEventKind, ActionSessionState, ActiveActionResponse, LevelProgress, PublicProfile, XpGrantResult, XpRecentGrant, XpSummary, } from "./xp";
@@ -72,13 +72,14 @@ export type CreateFlowOptions = {
72
72
  */
73
73
  autoGuest?: boolean;
74
74
  /**
75
- * If true, the JWT and the rotating refresh token are mirrored into
76
- * first-party cookies on the app's own origin so the app's server can
77
- * resolve the session per-request (see `@flow-industries/id/server`).
78
- * Off by default — a backend that never reads them shouldn't start
79
- * receiving refresh tokens on every request.
75
+ * Path of the app's first-party session route (see
76
+ * `@flow-industries/id/server`). The refresh token lives in an HttpOnly
77
+ * cookie owned by the app's server; the client resolves, installs, and
78
+ * revokes the session exclusively through this same-origin route. Override
79
+ * only when the app cannot claim the default path — the route registration
80
+ * must use the same value.
80
81
  */
81
- cookies?: boolean;
82
+ sessionPath?: string;
82
83
  /**
83
84
  * Session state resolved server-side (via `resolveSession`) to seed the
84
85
  * store synchronously, so the first client render matches the SSR HTML and
@@ -114,10 +115,6 @@ export type FlowCookieNames = {
114
115
  jwt: string;
115
116
  refresh: string;
116
117
  };
117
- export type RefreshCookieConfig = {
118
- name: string;
119
- secure: boolean;
120
- };
121
118
  export type LoginOptions = {
122
119
  mode?: "iframe" | "popup";
123
120
  signUp?: boolean;
@@ -1,5 +1,5 @@
1
- import type { VerifiedFlowJWT } from "./auth";
2
- import type { FlowSessionState } from "./sdk";
1
+ import type { FlowCredential, FlowUser, VerifiedFlowJWT } from "./auth";
2
+ import type { Address, FlowSessionState } from "./sdk";
3
3
  import type { PublicProfile } from "./xp";
4
4
  export type ResolveSessionOptions = {
5
5
  /** The calling app's origin, e.g. `https://flow.game` — must match the JWT `aud`. */
@@ -26,3 +26,31 @@ export type ResolvedFlowSession = {
26
26
  /** Public profile, only when requested via `profile: true` and resolvable. */
27
27
  profile?: PublicProfile;
28
28
  };
29
+ export type SessionRouteOptions = {
30
+ /**
31
+ * The app's public origin, e.g. `https://flow.game` — the JWT audience and
32
+ * what cookie names derive from. Defaults to the `APP_ORIGIN` env var, then
33
+ * the request's own origin (fine in dev; behind a TLS-terminating proxy set
34
+ * `APP_ORIGIN`).
35
+ */
36
+ audience?: string;
37
+ /** Flow ID origin; defaults per `defaultIdHost` (`FLOW_ID_HOST` on servers). */
38
+ issuerUrl?: string;
39
+ /** Route path for `createSessionHandler`'s own path check. */
40
+ path?: string;
41
+ };
42
+ /**
43
+ * A session as the session route reports it to the browser client.
44
+ * `credential`/`address` are present only when the token was rotated
45
+ * server-side — the rotation response is authoritative for signing state,
46
+ * while the JWT hot path knows neither and the client must keep what it has.
47
+ */
48
+ export type SessionRouteSession = {
49
+ user: FlowUser;
50
+ jwt: string;
51
+ credential?: FlowCredential | null;
52
+ address?: Address | null;
53
+ };
54
+ export type SessionRouteResponse = {
55
+ state: SessionRouteSession | null;
56
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flow-industries/id",
3
- "version": "0.10.0",
3
+ "version": "0.12.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",
@@ -33,6 +33,14 @@
33
33
  "./server": {
34
34
  "types": "./dist/sdk/server.d.ts",
35
35
  "import": "./dist/sdk/server.js"
36
+ },
37
+ "./start": {
38
+ "types": "./dist/sdk/start/index.d.ts",
39
+ "import": "./dist/sdk/start/index.js"
40
+ },
41
+ "./start/server": {
42
+ "types": "./dist/sdk/start/server.d.ts",
43
+ "import": "./dist/sdk/start/server.js"
36
44
  }
37
45
  },
38
46
  "files": [
@@ -66,7 +74,8 @@
66
74
  "viem": ">=2.47.10",
67
75
  "ox": ">=0.14.0",
68
76
  "react": ">=18",
69
- "@wagmi/core": ">=3.0.0"
77
+ "@wagmi/core": ">=3.0.0",
78
+ "@tanstack/react-start": ">=1.168.0"
70
79
  },
71
80
  "peerDependenciesMeta": {
72
81
  "react": {
@@ -74,6 +83,9 @@
74
83
  },
75
84
  "@wagmi/core": {
76
85
  "optional": true
86
+ },
87
+ "@tanstack/react-start": {
88
+ "optional": true
77
89
  }
78
90
  },
79
91
  "devDependencies": {
@@ -83,6 +95,7 @@
83
95
  "@react-email/ui": "^6.6.0",
84
96
  "@tailwindcss/vite": "^4.1.18",
85
97
  "@tanstack/react-router-devtools": "^1.160.0",
98
+ "@tanstack/react-start": "^1.168.28",
86
99
  "@tanstack/router-cli": "^1.167.17",
87
100
  "@tanstack/router-plugin": "^1.160.0",
88
101
  "@types/bun": "latest",