@flow-industries/id 0.2.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.
Files changed (54) hide show
  1. package/README.md +255 -0
  2. package/dist/sdk/chains.d.ts +2 -0
  3. package/dist/sdk/chains.js +2 -0
  4. package/dist/sdk/client/access-key.d.ts +37 -0
  5. package/dist/sdk/client/access-key.js +97 -0
  6. package/dist/sdk/client/create-flow.d.ts +41 -0
  7. package/dist/sdk/client/create-flow.js +259 -0
  8. package/dist/sdk/client/dialog-host.d.ts +19 -0
  9. package/dist/sdk/client/dialog-host.js +192 -0
  10. package/dist/sdk/client/idb.d.ts +5 -0
  11. package/dist/sdk/client/idb.js +47 -0
  12. package/dist/sdk/client/index.d.ts +4 -0
  13. package/dist/sdk/client/index.js +3 -0
  14. package/dist/sdk/client/methods.d.ts +9 -0
  15. package/dist/sdk/client/methods.js +9 -0
  16. package/dist/sdk/client/protocol.d.ts +97 -0
  17. package/dist/sdk/client/protocol.js +9 -0
  18. package/dist/sdk/client/session.d.ts +45 -0
  19. package/dist/sdk/client/session.js +90 -0
  20. package/dist/sdk/client/signing.d.ts +16 -0
  21. package/dist/sdk/client/signing.js +91 -0
  22. package/dist/sdk/client/store.d.ts +3 -0
  23. package/dist/sdk/client/store.js +41 -0
  24. package/dist/sdk/client/types.d.ts +35 -0
  25. package/dist/sdk/client/types.js +0 -0
  26. package/dist/sdk/dialog/remote/Messenger.d.ts +29 -0
  27. package/dist/sdk/dialog/remote/Messenger.js +146 -0
  28. package/dist/sdk/react/hooks.d.ts +33 -0
  29. package/dist/sdk/react/hooks.js +51 -0
  30. package/dist/sdk/react/index.d.ts +3 -0
  31. package/dist/sdk/react/index.js +2 -0
  32. package/dist/sdk/react/provider.d.ts +12 -0
  33. package/dist/sdk/react/provider.js +15 -0
  34. package/dist/sdk/types/auth.d.ts +45 -0
  35. package/dist/sdk/types/auth.js +0 -0
  36. package/dist/sdk/types/dialog.d.ts +55 -0
  37. package/dist/sdk/types/dialog.js +0 -0
  38. package/dist/sdk/types/index.d.ts +7 -0
  39. package/dist/sdk/types/index.js +1 -0
  40. package/dist/sdk/types/messenger.d.ts +162 -0
  41. package/dist/sdk/types/messenger.js +0 -0
  42. package/dist/sdk/types/protocol.d.ts +114 -0
  43. package/dist/sdk/types/protocol.js +17 -0
  44. package/dist/sdk/types/sdk.d.ts +166 -0
  45. package/dist/sdk/types/sdk.js +0 -0
  46. package/dist/sdk/types/tx.d.ts +35 -0
  47. package/dist/sdk/types/tx.js +0 -0
  48. package/dist/sdk/types.d.ts +32 -0
  49. package/dist/sdk/types.js +0 -0
  50. package/dist/sdk/verify.d.ts +15 -0
  51. package/dist/sdk/verify.js +30 -0
  52. package/dist/sdk/wagmi/index.d.ts +25 -0
  53. package/dist/sdk/wagmi/index.js +139 -0
  54. package/package.json +99 -0
@@ -0,0 +1,114 @@
1
+ import type { FlowCredential, FlowUser, WebAuthnSignature } from "./auth";
2
+ import type { Address } from "./sdk";
3
+ export type MethodName = "wallet_connect" | "personal_sign" | "eth_signTypedData" | "eth_sendTransaction" | "wallet_sendCalls" | "wallet_restore" | "wallet_signout";
4
+ export type ConnectCapabilities = {
5
+ createAccount?: boolean;
6
+ signIn?: boolean;
7
+ accessKeyHash?: string;
8
+ headless?: boolean;
9
+ credentialId?: string;
10
+ };
11
+ export type ConnectRequest = [{
12
+ capabilities?: ConnectCapabilities;
13
+ }];
14
+ export type ConnectResponse = {
15
+ jwt: string;
16
+ user: FlowUser;
17
+ credential: FlowCredential;
18
+ webauthn?: WebAuthnSignature;
19
+ };
20
+ export type SignMessageRequest = [message: string, address: string];
21
+ export type SignMessageResponse = `0x${string}`;
22
+ export type TypedDataDomain = {
23
+ name?: string;
24
+ version?: string;
25
+ chainId?: number;
26
+ verifyingContract?: string;
27
+ salt?: string;
28
+ };
29
+ export type TypedDataField = {
30
+ name: string;
31
+ type: string;
32
+ };
33
+ export type TypedData = {
34
+ domain: TypedDataDomain;
35
+ types: Record<string, readonly TypedDataField[]>;
36
+ primaryType: string;
37
+ message: Record<string, unknown>;
38
+ };
39
+ export type SignTypedDataRequest = [address: string, typedData: TypedData];
40
+ export type SignTypedDataResponse = `0x${string}`;
41
+ export type Call = {
42
+ to?: string;
43
+ value?: string;
44
+ data?: string;
45
+ };
46
+ export type TransactionArgs = Call & {
47
+ chainId?: string;
48
+ };
49
+ export type SendTransactionRequest = [TransactionArgs];
50
+ export type SendTransactionResponse = `0x${string}`;
51
+ export type SendCallsRequest = [
52
+ {
53
+ calls: readonly Call[];
54
+ chainId?: string;
55
+ capabilities?: Record<string, unknown>;
56
+ }
57
+ ];
58
+ export type SendCallsResponse = {
59
+ id: string;
60
+ };
61
+ export type RestoreRequest = [];
62
+ export type RestoreResponse = {
63
+ jwt: string;
64
+ user: FlowUser;
65
+ credential: FlowCredential;
66
+ address: Address;
67
+ };
68
+ export type SignOutRequest = [];
69
+ export type SignOutResponse = {
70
+ ok: true;
71
+ };
72
+ export type MethodParams = {
73
+ wallet_connect: ConnectRequest;
74
+ personal_sign: SignMessageRequest;
75
+ eth_signTypedData: SignTypedDataRequest;
76
+ eth_sendTransaction: SendTransactionRequest;
77
+ wallet_sendCalls: SendCallsRequest;
78
+ wallet_restore: RestoreRequest;
79
+ wallet_signout: SignOutRequest;
80
+ };
81
+ export type MethodResult = {
82
+ wallet_connect: ConnectResponse;
83
+ personal_sign: SignMessageResponse;
84
+ eth_signTypedData: SignTypedDataResponse;
85
+ eth_sendTransaction: SendTransactionResponse;
86
+ wallet_sendCalls: SendCallsResponse;
87
+ wallet_restore: RestoreResponse;
88
+ wallet_signout: SignOutResponse;
89
+ };
90
+ export type RpcRequest = {
91
+ id: string | number;
92
+ method: string;
93
+ params?: readonly unknown[];
94
+ jsonrpc?: string;
95
+ [key: string]: unknown;
96
+ };
97
+ export type SendTransactionParams = {
98
+ to?: string;
99
+ value?: string;
100
+ data?: string;
101
+ chainId?: string;
102
+ };
103
+ export type SendCallsParams = {
104
+ calls: readonly {
105
+ to?: string;
106
+ value?: string;
107
+ data?: string;
108
+ }[];
109
+ chainId?: string;
110
+ capabilities?: Record<string, unknown>;
111
+ };
112
+ export declare function isPersonalSignParams(params: readonly unknown[] | undefined): params is readonly [string, string];
113
+ export declare function isSendTransactionParams(params: readonly unknown[] | undefined): params is readonly [SendTransactionParams];
114
+ export declare function isSendCallsParams(params: readonly unknown[] | undefined): params is readonly [SendCallsParams];
@@ -0,0 +1,17 @@
1
+ export function isPersonalSignParams(params) {
2
+ if (!params || params.length < 2)
3
+ return false;
4
+ return typeof params[0] === "string" && typeof params[1] === "string";
5
+ }
6
+ export function isSendTransactionParams(params) {
7
+ if (!params || params.length < 1)
8
+ return false;
9
+ const p = params[0];
10
+ return p != null && typeof p === "object";
11
+ }
12
+ export function isSendCallsParams(params) {
13
+ if (!params || params.length < 1)
14
+ return false;
15
+ const p = params[0];
16
+ return p != null && typeof p === "object" && Array.isArray(p.calls);
17
+ }
@@ -0,0 +1,166 @@
1
+ import type { Chain, Hex, SendTransactionParameters, SignTypedDataParameters, Transport, WalletClient } from "viem";
2
+ import type { SendCallsParameters } from "viem/actions";
3
+ import type { ReactNode } from "react";
4
+ import type { FlowCredential, FlowUser, WebAuthnSignature } from "./auth";
5
+ import type { ConnectCapabilities, ConnectResponse } from "./protocol";
6
+ export type Address = `0x${string}`;
7
+ export type CreateDialogHostOptions = {
8
+ host: string;
9
+ container?: HTMLElement;
10
+ };
11
+ export type AccessKeyOptions = {
12
+ expiry?: number;
13
+ strict?: boolean;
14
+ };
15
+ export type ResolvedAccessKeyOptions = {
16
+ expiry: number;
17
+ strict: boolean;
18
+ };
19
+ export type StoredAccessKey = {
20
+ privateKey: unknown;
21
+ publicKey: unknown;
22
+ keyAuthorization: unknown;
23
+ };
24
+ export type AccessKeyPreparation = {
25
+ keyPair: {
26
+ privateKey: unknown;
27
+ publicKey: unknown;
28
+ };
29
+ keyAuthUnsigned: unknown;
30
+ accessKeyHash: string;
31
+ };
32
+ export type CreateFlowOptions = {
33
+ host?: string;
34
+ rpId?: string;
35
+ chains?: readonly Chain[];
36
+ accessKey?: boolean | AccessKeyOptions;
37
+ /**
38
+ * If true (default), createFlow attempts a silent restore on startup —
39
+ * if the user has a valid Flow cookie session, state populates without UI.
40
+ */
41
+ autoRestore?: boolean;
42
+ };
43
+ export type FlowState = {
44
+ user: FlowUser | null;
45
+ jwt: string | null;
46
+ credential: FlowCredential | null;
47
+ address: Address | null;
48
+ };
49
+ export type LoginOptions = {
50
+ mode?: "iframe" | "popup";
51
+ signUp?: boolean;
52
+ };
53
+ export type Session = {
54
+ user: FlowUser;
55
+ jwt: string;
56
+ credential: FlowCredential;
57
+ address: Address;
58
+ };
59
+ export type RootCredential = {
60
+ credential: FlowCredential;
61
+ address: Address;
62
+ };
63
+ export type SigningContext = {
64
+ getState(): FlowState;
65
+ getChain(chainId?: number): Chain | undefined;
66
+ getTransport(chainId: number): Transport | undefined;
67
+ rpId?: string;
68
+ strict?: boolean;
69
+ };
70
+ export type SignMessageArgs = {
71
+ message: string;
72
+ chainId?: number;
73
+ };
74
+ export type SignTypedDataArgs = Omit<SignTypedDataParameters, "account"> & {
75
+ chainId?: number;
76
+ };
77
+ export type SendTransactionArgs = Omit<SendTransactionParameters, "account" | "chain"> & {
78
+ chainId?: number;
79
+ };
80
+ export type SendCallsArgs = Omit<SendCallsParameters, "account" | "chain"> & {
81
+ chainId?: number;
82
+ };
83
+ export type Listener<T> = (state: T) => void;
84
+ export type Store<T> = {
85
+ getSnapshot(): T;
86
+ setState(partial: Partial<T>): void;
87
+ subscribe(listener: Listener<T>): () => void;
88
+ };
89
+ export type DialogOpenOptions = {
90
+ mode?: "iframe" | "popup";
91
+ theme?: {
92
+ colorScheme?: string;
93
+ };
94
+ referrer?: {
95
+ title: string;
96
+ icon?: string;
97
+ };
98
+ };
99
+ export type DialogHost = {
100
+ open: (options?: DialogOpenOptions) => void;
101
+ close: () => void;
102
+ destroy: () => void;
103
+ request: <T = unknown>(method: string, params?: readonly unknown[]) => Promise<T>;
104
+ requestSilent: <T = unknown>(method: string, params?: readonly unknown[]) => Promise<T>;
105
+ messenger: import("./messenger").Messenger;
106
+ };
107
+ export type Flow = {
108
+ readonly user: FlowState["user"];
109
+ readonly jwt: FlowState["jwt"];
110
+ readonly credential: FlowState["credential"];
111
+ readonly address: Address | null;
112
+ readonly isAuthenticated: boolean;
113
+ login(options?: LoginOptions): Promise<Session>;
114
+ logout(): Promise<void>;
115
+ restore(): Promise<boolean>;
116
+ refreshJwt(): Promise<boolean>;
117
+ signMessage(args: SignMessageArgs): Promise<Hex>;
118
+ signTypedData(args: SignTypedDataArgs): Promise<Hex>;
119
+ sendTransaction(args: SendTransactionArgs): Promise<Hex>;
120
+ sendCalls(args: SendCallsArgs): Promise<{
121
+ id: string;
122
+ }>;
123
+ walletClient(args?: {
124
+ chainId?: number;
125
+ }): Promise<WalletClient>;
126
+ subscribe(listener: Listener<FlowState>): () => void;
127
+ getState(): FlowState;
128
+ dialog: DialogHost;
129
+ };
130
+ export type FlowConnectorParameters = Omit<CreateFlowOptions, "chains"> & {
131
+ /**
132
+ * Pass an existing Flow instance so wagmi shares state with direct SDK usage.
133
+ * If omitted, the connector creates its own internal Flow (separate state).
134
+ */
135
+ flow?: Flow;
136
+ };
137
+ export type FlowIdProviderProps = {
138
+ /**
139
+ * Explicit Flow instance to scope to descendants. Optional — if omitted,
140
+ * descendants resolve via the singleton set by `createFlow()`.
141
+ */
142
+ flow?: Flow;
143
+ children: ReactNode;
144
+ };
145
+ export type RunLoginParams = {
146
+ dialog: DialogHost;
147
+ store: Store<FlowState>;
148
+ options?: LoginOptions;
149
+ extraCapabilities?: ConnectCapabilities;
150
+ };
151
+ export type RunLoginResult = {
152
+ session: Session;
153
+ webauthn: ConnectResponse["webauthn"];
154
+ };
155
+ export type FinalizeAccessKeyParams = {
156
+ address: Address;
157
+ credential: FlowCredential;
158
+ webauthn: WebAuthnSignature;
159
+ preparation: AccessKeyPreparation;
160
+ };
161
+ export type ResolveAccountParams = {
162
+ credential: FlowCredential;
163
+ address: Address;
164
+ rpId?: string;
165
+ strict?: boolean;
166
+ };
File without changes
@@ -0,0 +1,35 @@
1
+ export type CoinAsset = {
2
+ address: string | null;
3
+ direction: "incoming" | "outgoing";
4
+ name?: string;
5
+ symbol?: string;
6
+ type: "erc20" | null;
7
+ value: bigint;
8
+ decimals?: number | null;
9
+ fiat?: {
10
+ value: number;
11
+ };
12
+ };
13
+ export type TxApprove = {
14
+ type: "approve";
15
+ tokenAddress: string;
16
+ spender: string;
17
+ amount: bigint;
18
+ };
19
+ export type TxSwap = {
20
+ type: "swap";
21
+ assetIn: CoinAsset;
22
+ assetOut: CoinAsset;
23
+ };
24
+ export type TxSend = {
25
+ type: "send";
26
+ asset: CoinAsset;
27
+ to?: string;
28
+ };
29
+ export type TxConvert = {
30
+ type: "convert";
31
+ assetIn: CoinAsset;
32
+ assetOut: CoinAsset;
33
+ direction: "wrap" | "unwrap";
34
+ };
35
+ export type IdentifiedTx = TxApprove | TxSwap | TxSend | TxConvert;
File without changes
@@ -0,0 +1,32 @@
1
+ export type FlowUser = {
2
+ id: string;
3
+ username: string;
4
+ };
5
+ export type FlowCredential = {
6
+ id: string;
7
+ publicKey: string;
8
+ };
9
+ export type AuthResponse = {
10
+ jwt: string;
11
+ user: FlowUser;
12
+ credential: FlowCredential;
13
+ };
14
+ export type AuthConfig = {
15
+ rpId: string;
16
+ rpName: string;
17
+ };
18
+ export type WebAuthnSignature = {
19
+ signature: {
20
+ r: string;
21
+ s: string;
22
+ };
23
+ metadata: {
24
+ authenticatorData: string;
25
+ clientDataJSON: string;
26
+ challengeIndex: number;
27
+ typeIndex: number;
28
+ };
29
+ };
30
+ export type AuthResponseWithWebAuthn = AuthResponse & {
31
+ webauthn?: WebAuthnSignature;
32
+ };
File without changes
@@ -0,0 +1,15 @@
1
+ import type { VerifiedFlowJWT, VerifyOptions } from "./types";
2
+ export type { VerifiedFlowJWT, VerifyOptions } from "./types";
3
+ /**
4
+ * Server-side helper for verifying a Flow JWT. Used by relying-party backends
5
+ * (e.g., flow.game's game server) to authenticate API requests where the
6
+ * client has presented `Authorization: Bearer <jwt>`.
7
+ *
8
+ * Fetches the issuer's JWKS once per process and caches it (the keys rotate
9
+ * but rarely; jose handles refresh transparently). Verifies signature,
10
+ * issuer, audience, and expiry; rejects tokens missing `sub`.
11
+ *
12
+ * `audience` MUST match the calling app's origin — this is what prevents
13
+ * a token issued for `flow.talk` from being replayed against `flow.game`.
14
+ */
15
+ export declare function verifyFlowJWT(token: string, opts: VerifyOptions): Promise<VerifiedFlowJWT>;
@@ -0,0 +1,30 @@
1
+ import { createRemoteJWKSet, jwtVerify } from "jose";
2
+ const jwksCache = new Map();
3
+ const DEFAULT_ISSUER_URL = "https://id.flow.industries";
4
+ /**
5
+ * Server-side helper for verifying a Flow JWT. Used by relying-party backends
6
+ * (e.g., flow.game's game server) to authenticate API requests where the
7
+ * client has presented `Authorization: Bearer <jwt>`.
8
+ *
9
+ * Fetches the issuer's JWKS once per process and caches it (the keys rotate
10
+ * but rarely; jose handles refresh transparently). Verifies signature,
11
+ * issuer, audience, and expiry; rejects tokens missing `sub`.
12
+ *
13
+ * `audience` MUST match the calling app's origin — this is what prevents
14
+ * a token issued for `flow.talk` from being replayed against `flow.game`.
15
+ */
16
+ export async function verifyFlowJWT(token, opts) {
17
+ const issuerUrl = opts.issuerUrl ?? DEFAULT_ISSUER_URL;
18
+ let jwks = jwksCache.get(issuerUrl);
19
+ if (!jwks) {
20
+ jwks = createRemoteJWKSet(new URL(`${issuerUrl}/api/auth/jwks`));
21
+ jwksCache.set(issuerUrl, jwks);
22
+ }
23
+ const { payload } = await jwtVerify(token, jwks, {
24
+ issuer: issuerUrl,
25
+ audience: opts.audience,
26
+ });
27
+ if (!payload.sub)
28
+ throw new Error("JWT missing sub");
29
+ return payload;
30
+ }
@@ -0,0 +1,25 @@
1
+ import type { FlowConnectorParameters } from "../types";
2
+ /**
3
+ * Wagmi connector adapter for Flow. Drop into your wagmi config with
4
+ * `connectors: [flowConnector()]` — no arguments needed in the common case.
5
+ *
6
+ * Resolution order for the underlying Flow instance:
7
+ * 1. `parameters.flow` (explicit override — useful for tests)
8
+ * 2. The Flow singleton set by a prior `createFlow()` call
9
+ * 3. Lazily created on first connector use (also sets the singleton)
10
+ *
11
+ * This means wagmi-only apps get a working Flow without ever calling
12
+ * `createFlow`, and apps mixing wagmi + direct SDK calls automatically
13
+ * share state because they all resolve to the same singleton.
14
+ *
15
+ * The `setup()` method subscribes to the Flow store and emits wagmi
16
+ * `connect`/`disconnect` events whenever the address changes — that's how
17
+ * wagmi state stays in sync when login/logout happens via the SDK rather
18
+ * than through wagmi's own `connect()`.
19
+ */
20
+ export declare function flowConnector(parameters?: FlowConnectorParameters): import("@wagmi/core").CreateConnectorFn<{
21
+ request: (...args: unknown[]) => Promise<unknown>;
22
+ }, Record<string, unknown>, Record<string, unknown>>;
23
+ export declare namespace flowConnector {
24
+ var type: "flow";
25
+ }
@@ -0,0 +1,139 @@
1
+ import { createConnector } from "@wagmi/core";
2
+ import { getAddress, SwitchChainError } from "viem";
3
+ import { createFlow, getFlow as getSingletonFlow } from "../client/create-flow";
4
+ flowConnector.type = "flow";
5
+ /**
6
+ * Wagmi connector adapter for Flow. Drop into your wagmi config with
7
+ * `connectors: [flowConnector()]` — no arguments needed in the common case.
8
+ *
9
+ * Resolution order for the underlying Flow instance:
10
+ * 1. `parameters.flow` (explicit override — useful for tests)
11
+ * 2. The Flow singleton set by a prior `createFlow()` call
12
+ * 3. Lazily created on first connector use (also sets the singleton)
13
+ *
14
+ * This means wagmi-only apps get a working Flow without ever calling
15
+ * `createFlow`, and apps mixing wagmi + direct SDK calls automatically
16
+ * share state because they all resolve to the same singleton.
17
+ *
18
+ * The `setup()` method subscribes to the Flow store and emits wagmi
19
+ * `connect`/`disconnect` events whenever the address changes — that's how
20
+ * wagmi state stays in sync when login/logout happens via the SDK rather
21
+ * than through wagmi's own `connect()`.
22
+ */
23
+ export function flowConnector(parameters = {}) {
24
+ let flow = parameters.flow ?? null;
25
+ return createConnector((config) => {
26
+ const getFlow = () => {
27
+ if (flow)
28
+ return flow;
29
+ const singleton = getSingletonFlow();
30
+ if (singleton) {
31
+ flow = singleton;
32
+ return flow;
33
+ }
34
+ const { flow: _omit, ...rest } = parameters;
35
+ flow = createFlow({
36
+ ...rest,
37
+ chains: [...config.chains],
38
+ });
39
+ return flow;
40
+ };
41
+ return {
42
+ id: "flow",
43
+ name: "Flow",
44
+ type: flowConnector.type,
45
+ async setup() {
46
+ const f = getFlow();
47
+ let lastAddress = null;
48
+ f.subscribe((state) => {
49
+ const next = state.address ? getAddress(state.address) : null;
50
+ if (next === lastAddress)
51
+ return;
52
+ lastAddress = next;
53
+ if (next) {
54
+ config.emitter.emit("connect", {
55
+ accounts: [next],
56
+ chainId: config.chains[0]?.id ?? 1,
57
+ });
58
+ }
59
+ else {
60
+ config.emitter.emit("disconnect");
61
+ }
62
+ });
63
+ },
64
+ async connect(params = {}) {
65
+ const f = getFlow();
66
+ const isReconnecting = params.isReconnecting;
67
+ // Wagmi calls connect({ isReconnecting: true }) on mount when it
68
+ // thinks there's a previous session. Without this branch we'd open
69
+ // the dialog (full sign-in) on every page load. Silent restore
70
+ // handles it without UI; if there's no session, surface that as a
71
+ // throw so wagmi treats the connector as disconnected.
72
+ if (!f.isAuthenticated) {
73
+ if (isReconnecting) {
74
+ const restored = await f.restore();
75
+ if (!restored) {
76
+ throw new Error("No active session to restore");
77
+ }
78
+ }
79
+ else {
80
+ await f.login();
81
+ }
82
+ }
83
+ const address = f.address;
84
+ if (!address)
85
+ throw new Error("Failed to connect");
86
+ const chainId = params.chainId ?? config.chains[0]?.id;
87
+ if (chainId == null) {
88
+ throw new Error("Flow connector requires at least one chain to be configured");
89
+ }
90
+ return {
91
+ accounts: [getAddress(address)],
92
+ chainId,
93
+ };
94
+ },
95
+ async disconnect() {
96
+ await flow?.logout();
97
+ },
98
+ async getAccounts() {
99
+ const f = getFlow();
100
+ if (!f.address)
101
+ return [];
102
+ return [getAddress(f.address)];
103
+ },
104
+ async getChainId() {
105
+ return config.chains[0]?.id ?? 1;
106
+ },
107
+ async isAuthorized() {
108
+ try {
109
+ const accounts = await this.getAccounts();
110
+ return accounts.length > 0;
111
+ }
112
+ catch {
113
+ return false;
114
+ }
115
+ },
116
+ async switchChain({ chainId }) {
117
+ const chain = config.chains.find((c) => c.id === chainId);
118
+ if (!chain)
119
+ throw new SwitchChainError(new Error("Chain not configured"));
120
+ return chain;
121
+ },
122
+ async getClient({ chainId } = {}) {
123
+ const f = getFlow();
124
+ return f.walletClient({ ...(chainId ? { chainId } : {}) });
125
+ },
126
+ async getProvider({ chainId } = {}) {
127
+ const client = await this.getClient({ ...(chainId ? { chainId } : {}) });
128
+ return { request: client.request };
129
+ },
130
+ onAccountsChanged() { },
131
+ onChainChanged(chain) {
132
+ config.emitter.emit("change", { chainId: Number(chain) });
133
+ },
134
+ async onDisconnect() {
135
+ await flow?.logout();
136
+ },
137
+ };
138
+ });
139
+ }
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@flow-industries/id",
3
+ "version": "0.2.0",
4
+ "module": "src/index.ts",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/sdk/client/index.d.ts",
13
+ "import": "./dist/sdk/client/index.js"
14
+ },
15
+ "./react": {
16
+ "types": "./dist/sdk/react/index.d.ts",
17
+ "import": "./dist/sdk/react/index.js"
18
+ },
19
+ "./wagmi": {
20
+ "types": "./dist/sdk/wagmi/index.d.ts",
21
+ "import": "./dist/sdk/wagmi/index.js"
22
+ },
23
+ "./chains": {
24
+ "types": "./dist/sdk/chains.d.ts",
25
+ "import": "./dist/sdk/chains.js"
26
+ },
27
+ "./verify": {
28
+ "types": "./dist/sdk/verify.d.ts",
29
+ "import": "./dist/sdk/verify.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist/sdk"
34
+ ],
35
+ "scripts": {
36
+ "dev": "bunx vite & bunx vite --config vite.playground.config.ts & bunx vite --config vite.landing.config.ts & bun run --watch src/index.ts",
37
+ "dev:dialog": "bunx vite",
38
+ "dev:playground": "bunx vite --config vite.playground.config.ts",
39
+ "dev:landing": "bunx vite --config vite.landing.config.ts",
40
+ "build:dialog": "bunx vite build",
41
+ "build:playground": "bunx vite build --config vite.playground.config.ts",
42
+ "build:landing": "bunx vite build --config vite.landing.config.ts",
43
+ "build": "bunx vite build && bunx vite build --config vite.playground.config.ts && bunx vite build --config vite.landing.config.ts",
44
+ "build:sdk": "tsc --project tsconfig.sdk.json",
45
+ "prepublishOnly": "bun run build:sdk",
46
+ "start": "bun run src/index.ts",
47
+ "db:generate": "bunx @better-auth/cli generate",
48
+ "db:migrate": "bunx drizzle-kit generate && bunx drizzle-kit migrate",
49
+ "db:push": "bunx drizzle-kit push",
50
+ "db:studio": "bunx drizzle-kit studio"
51
+ },
52
+ "peerDependencies": {
53
+ "viem": ">=2.47.10",
54
+ "ox": ">=0.14.0",
55
+ "react": ">=18",
56
+ "@wagmi/core": ">=3.0.0"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "react": { "optional": true },
60
+ "@wagmi/core": { "optional": true }
61
+ },
62
+ "devDependencies": {
63
+ "@better-auth/cli": "^1.4.17",
64
+ "@tailwindcss/vite": "^4.1.18",
65
+ "@tanstack/react-router-devtools": "^1.160.0",
66
+ "@tanstack/router-plugin": "^1.160.0",
67
+ "@types/bun": "latest",
68
+ "@types/react": "^19.2.13",
69
+ "@types/react-dom": "^19.2.3",
70
+ "@vitejs/plugin-react": "^5.1.3",
71
+ "drizzle-kit": "^0.31.8",
72
+ "tailwindcss": "^4.1.18",
73
+ "tw-animate-css": "^1.4.0",
74
+ "typescript": "^5",
75
+ "vite": "^7.3.1"
76
+ },
77
+ "dependencies": {
78
+ "@flow-industries/ui": "^0.11.1",
79
+ "@tanstack/query-sync-storage-persister": "^5.90.22",
80
+ "@tanstack/react-query": "^5.90.20",
81
+ "@tanstack/react-query-persist-client": "^5.90.22",
82
+ "@tanstack/react-router": "^1.160.0",
83
+ "better-auth": "^1.4.17",
84
+ "drizzle-orm": "^0.45.1",
85
+ "geist": "^1.7.0",
86
+ "hono": "^4.11.5",
87
+ "jose": "^6.1.3",
88
+ "lucide-react": "^0.563.0",
89
+ "motion": "^12.33.0",
90
+ "postgres": "^3.4.8",
91
+ "react": "^19.2.4",
92
+ "react-dom": "^19.2.4",
93
+ "react-intersection-observer": "^10.0.2",
94
+ "tempo.ts": "^0.14.2",
95
+ "viem": "2.47.10",
96
+ "wagmi": "^3.4.2",
97
+ "zustand": "^5.0.11"
98
+ }
99
+ }