@thehoneyjar/sigil-lens 0.1.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/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # @sigil/lens
2
+
3
+ Address impersonation for testing different user states. View your app as any address.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @sigil/lens
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### React Hooks
14
+
15
+ ```tsx
16
+ import { useLens, useIsImpersonating, useLensActions } from '@sigil/lens'
17
+
18
+ function MyComponent() {
19
+ const { enabled, impersonatedAddress, realAddress } = useLens()
20
+ const isImpersonating = useIsImpersonating()
21
+ const { setImpersonatedAddress, clearImpersonation } = useLensActions()
22
+
23
+ return (
24
+ <div>
25
+ {isImpersonating ? (
26
+ <p>Viewing as: {impersonatedAddress}</p>
27
+ ) : (
28
+ <p>Viewing as: {realAddress}</p>
29
+ )}
30
+ <button onClick={() => setImpersonatedAddress('0x...')}>
31
+ Impersonate
32
+ </button>
33
+ <button onClick={clearImpersonation}>
34
+ Stop
35
+ </button>
36
+ </div>
37
+ )
38
+ }
39
+ ```
40
+
41
+ ### Wagmi Integration
42
+
43
+ ```tsx
44
+ import { useLensAwareAccount } from '@sigil/lens/wagmi'
45
+
46
+ function WalletInfo() {
47
+ const { address, realAddress, isImpersonating } = useLensAwareAccount()
48
+
49
+ // Use `address` for reading data (respects impersonation)
50
+ const { data: balance } = useBalance({ address })
51
+
52
+ // Use `realAddress` for signing transactions
53
+ return (
54
+ <div>
55
+ <p>Viewing: {address}</p>
56
+ {isImpersonating && <Badge>Lens Active</Badge>}
57
+ </div>
58
+ )
59
+ }
60
+ ```
61
+
62
+ ### Service API
63
+
64
+ ```typescript
65
+ import { createLensService } from '@sigil/lens'
66
+
67
+ const lensService = createLensService()
68
+
69
+ // Impersonate an address
70
+ lensService.setImpersonatedAddress('0x...')
71
+
72
+ // Get current state
73
+ const state = lensService.getState()
74
+
75
+ // Save addresses for quick access
76
+ lensService.saveAddress({ address: '0x...', label: 'Whale' })
77
+
78
+ // Clear impersonation
79
+ lensService.clearImpersonation()
80
+ ```
81
+
82
+ ## API
83
+
84
+ ### Hooks
85
+
86
+ | Hook | Description |
87
+ |------|-------------|
88
+ | `useLens()` | Get full lens state |
89
+ | `useLensContext()` | Get lens context for components |
90
+ | `useIsImpersonating()` | Check if currently impersonating |
91
+ | `useImpersonatedAddress()` | Get impersonated address |
92
+ | `useRealAddress()` | Get real connected address |
93
+ | `useEffectiveAddress()` | Get effective address (impersonated or real) |
94
+ | `useSavedAddresses()` | Get saved addresses and actions |
95
+ | `useLensActions()` | Get lens actions |
96
+
97
+ ### Wagmi Hooks
98
+
99
+ | Hook | Description |
100
+ |------|-------------|
101
+ | `useLensAwareAccount()` | Wagmi useAccount that respects lens |
102
+
103
+ ### Service
104
+
105
+ | Method | Description |
106
+ |--------|-------------|
107
+ | `getState()` | Get current state |
108
+ | `setImpersonatedAddress(address)` | Set impersonated address |
109
+ | `clearImpersonation()` | Clear impersonation |
110
+ | `saveAddress(entry)` | Save an address |
111
+ | `removeAddress(address)` | Remove saved address |
112
+ | `getContext()` | Get lens context |
113
+ | `subscribe(listener)` | Subscribe to state changes |
114
+
115
+ ## Persistence
116
+
117
+ Saved addresses are persisted to localStorage under the key `sigil-lens-storage`.
118
+
119
+ ## License
120
+
121
+ MIT
@@ -0,0 +1,227 @@
1
+ import { Address } from 'viem';
2
+ import * as zustand_middleware from 'zustand/middleware';
3
+ import * as zustand from 'zustand';
4
+
5
+ /**
6
+ * Lens Service Types
7
+ *
8
+ * Types for address impersonation functionality.
9
+ */
10
+
11
+ /**
12
+ * Saved address entry for quick selection
13
+ */
14
+ interface SavedAddress {
15
+ address: Address;
16
+ label: string;
17
+ addedAt: number;
18
+ }
19
+ /**
20
+ * Lens state
21
+ */
22
+ interface LensState {
23
+ /** Whether lens impersonation is enabled */
24
+ enabled: boolean;
25
+ /** Currently impersonated address */
26
+ impersonatedAddress: Address | null;
27
+ /** The real connected wallet address */
28
+ realAddress: Address | null;
29
+ /** Saved addresses for quick selection */
30
+ savedAddresses: SavedAddress[];
31
+ }
32
+ /**
33
+ * Lens context for components
34
+ */
35
+ interface LensContext {
36
+ /** Whether currently impersonating */
37
+ isImpersonating: boolean;
38
+ /** The impersonated address (if any) */
39
+ impersonatedAddress: Address | null;
40
+ /** The real connected address */
41
+ realAddress: Address | null;
42
+ }
43
+ /**
44
+ * Lens service interface
45
+ */
46
+ interface LensService {
47
+ /** Get current lens state */
48
+ getState(): LensState;
49
+ /** Enable lens and set impersonated address */
50
+ setImpersonatedAddress(address: Address): void;
51
+ /** Clear impersonation */
52
+ clearImpersonation(): void;
53
+ /** Set the real address (from wallet connection) */
54
+ setRealAddress(address: Address | null): void;
55
+ /** Save an address for quick access */
56
+ saveAddress(entry: Omit<SavedAddress, 'addedAt'>): void;
57
+ /** Remove a saved address */
58
+ removeAddress(address: Address): void;
59
+ /** Get lens context */
60
+ getContext(): LensContext;
61
+ /** Subscribe to state changes */
62
+ subscribe(listener: (state: LensState) => void): () => void;
63
+ }
64
+ /**
65
+ * Lens error
66
+ */
67
+ declare class LensError extends Error {
68
+ code: string;
69
+ recoverable: boolean;
70
+ constructor(message: string, code: string, recoverable?: boolean);
71
+ }
72
+ /**
73
+ * Lens error codes
74
+ */
75
+ declare const LensErrorCodes: {
76
+ readonly INVALID_ADDRESS: "LENS_INVALID_ADDRESS";
77
+ readonly NOT_CONNECTED: "LENS_NOT_CONNECTED";
78
+ };
79
+
80
+ /**
81
+ * Lens store actions
82
+ */
83
+ interface LensActions {
84
+ setImpersonatedAddress: (address: Address) => void;
85
+ clearImpersonation: () => void;
86
+ setRealAddress: (address: Address | null) => void;
87
+ saveAddress: (entry: Omit<SavedAddress, 'addedAt'>) => void;
88
+ removeAddress: (address: Address) => void;
89
+ reset: () => void;
90
+ }
91
+ /**
92
+ * Combined lens store type
93
+ */
94
+ type LensStore = LensState & LensActions;
95
+ /**
96
+ * Create the lens store
97
+ */
98
+ declare const useLensStore: zustand.UseBoundStore<Omit<zustand.StoreApi<LensStore>, "persist"> & {
99
+ persist: {
100
+ setOptions: (options: Partial<zustand_middleware.PersistOptions<LensStore, {
101
+ savedAddresses: SavedAddress[];
102
+ }>>) => void;
103
+ clearStorage: () => void;
104
+ rehydrate: () => void | Promise<void>;
105
+ hasHydrated: () => boolean;
106
+ onHydrate: (fn: (state: LensStore) => void) => () => void;
107
+ onFinishHydration: (fn: (state: LensStore) => void) => () => void;
108
+ getOptions: () => Partial<zustand_middleware.PersistOptions<LensStore, {
109
+ savedAddresses: SavedAddress[];
110
+ }>>;
111
+ };
112
+ }>;
113
+ /**
114
+ * Get lens store state (for non-React contexts)
115
+ */
116
+ declare function getLensState(): LensState;
117
+
118
+ /**
119
+ * Lens Service Implementation
120
+ *
121
+ * Provides lens functionality for non-React contexts.
122
+ */
123
+
124
+ /**
125
+ * Create a lens service
126
+ */
127
+ declare function createLensService(): LensService;
128
+ /**
129
+ * Get the default lens service
130
+ */
131
+ declare function getLensService(): LensService;
132
+ /**
133
+ * Reset the default lens service
134
+ */
135
+ declare function resetLensService(): void;
136
+
137
+ /**
138
+ * Lens React Hooks
139
+ *
140
+ * React hooks for accessing lens state.
141
+ */
142
+
143
+ /**
144
+ * Hook to get the full lens state
145
+ *
146
+ * @example
147
+ * ```tsx
148
+ * function LensStatus() {
149
+ * const { enabled, impersonatedAddress, realAddress } = useLens()
150
+ * return <div>{enabled ? `Impersonating ${impersonatedAddress}` : 'Not impersonating'}</div>
151
+ * }
152
+ * ```
153
+ */
154
+ declare function useLens(): LensState;
155
+ /**
156
+ * Hook to get lens context for components
157
+ *
158
+ * @example
159
+ * ```tsx
160
+ * function AddressDisplay() {
161
+ * const { isImpersonating, impersonatedAddress, realAddress } = useLensContext()
162
+ * return <div>{isImpersonating ? impersonatedAddress : realAddress}</div>
163
+ * }
164
+ * ```
165
+ */
166
+ declare function useLensContext(): LensContext;
167
+ /**
168
+ * Hook to check if currently impersonating
169
+ *
170
+ * @example
171
+ * ```tsx
172
+ * function LensBadge() {
173
+ * const isImpersonating = useIsImpersonating()
174
+ * if (!isImpersonating) return null
175
+ * return <Badge variant="warning">Lens Active</Badge>
176
+ * }
177
+ * ```
178
+ */
179
+ declare function useIsImpersonating(): boolean;
180
+ /**
181
+ * Hook to get the impersonated address (or null if not impersonating)
182
+ */
183
+ declare function useImpersonatedAddress(): Address | null;
184
+ /**
185
+ * Hook to get the real connected address
186
+ */
187
+ declare function useRealAddress(): Address | null;
188
+ /**
189
+ * Hook to get the effective address (impersonated if active, otherwise real)
190
+ */
191
+ declare function useEffectiveAddress(): Address | undefined;
192
+ /**
193
+ * Hook to get saved addresses and actions
194
+ *
195
+ * @example
196
+ * ```tsx
197
+ * function SavedAddressList() {
198
+ * const { savedAddresses, saveAddress, removeAddress, selectAddress } = useSavedAddresses()
199
+ * return (
200
+ * <ul>
201
+ * {savedAddresses.map(({ address, label }) => (
202
+ * <li key={address} onClick={() => selectAddress(address)}>
203
+ * {label}: {address}
204
+ * <button onClick={() => removeAddress(address)}>Remove</button>
205
+ * </li>
206
+ * ))}
207
+ * </ul>
208
+ * )
209
+ * }
210
+ * ```
211
+ */
212
+ declare function useSavedAddresses(): {
213
+ savedAddresses: SavedAddress[];
214
+ saveAddress: (entry: Omit<SavedAddress, 'addedAt'>) => void;
215
+ removeAddress: (address: `0x${string}`) => void;
216
+ selectAddress: (address: `0x${string}`) => void;
217
+ };
218
+ /**
219
+ * Hook to get lens actions
220
+ */
221
+ declare function useLensActions(): {
222
+ setImpersonatedAddress: (address: `0x${string}`) => void;
223
+ clearImpersonation: () => void;
224
+ setRealAddress: (address: `0x${string}` | null) => void;
225
+ };
226
+
227
+ export { type LensContext, LensError, LensErrorCodes, type LensService, type LensState, type SavedAddress, createLensService, getLensService, getLensState, resetLensService, useEffectiveAddress, useImpersonatedAddress, useIsImpersonating, useLens, useLensActions, useLensContext, useLensStore, useRealAddress, useSavedAddresses };
package/dist/index.js ADDED
@@ -0,0 +1,203 @@
1
+ // src/types.ts
2
+ var LensError = class extends Error {
3
+ constructor(message, code, recoverable = true) {
4
+ super(message);
5
+ this.code = code;
6
+ this.recoverable = recoverable;
7
+ this.name = "LensError";
8
+ }
9
+ };
10
+ var LensErrorCodes = {
11
+ INVALID_ADDRESS: "LENS_INVALID_ADDRESS",
12
+ NOT_CONNECTED: "LENS_NOT_CONNECTED"
13
+ };
14
+
15
+ // src/store.ts
16
+ import { create } from "zustand";
17
+ import { persist } from "zustand/middleware";
18
+ var initialState = {
19
+ enabled: false,
20
+ impersonatedAddress: null,
21
+ realAddress: null,
22
+ savedAddresses: []
23
+ };
24
+ var useLensStore = create()(
25
+ persist(
26
+ (set) => ({
27
+ ...initialState,
28
+ setImpersonatedAddress: (address) => set({
29
+ enabled: true,
30
+ impersonatedAddress: address
31
+ }),
32
+ clearImpersonation: () => set({
33
+ enabled: false,
34
+ impersonatedAddress: null
35
+ }),
36
+ setRealAddress: (address) => set({ realAddress: address }),
37
+ saveAddress: (entry) => set((state) => {
38
+ if (state.savedAddresses.some((a) => a.address === entry.address)) {
39
+ return state;
40
+ }
41
+ return {
42
+ savedAddresses: [
43
+ ...state.savedAddresses,
44
+ { ...entry, addedAt: Date.now() }
45
+ ]
46
+ };
47
+ }),
48
+ removeAddress: (address) => set((state) => ({
49
+ savedAddresses: state.savedAddresses.filter((a) => a.address !== address)
50
+ })),
51
+ reset: () => set(initialState)
52
+ }),
53
+ {
54
+ name: "sigil-lens-storage",
55
+ partialize: (state) => ({
56
+ savedAddresses: state.savedAddresses
57
+ })
58
+ }
59
+ )
60
+ );
61
+ function getLensState() {
62
+ const state = useLensStore.getState();
63
+ return {
64
+ enabled: state.enabled,
65
+ impersonatedAddress: state.impersonatedAddress,
66
+ realAddress: state.realAddress,
67
+ savedAddresses: state.savedAddresses
68
+ };
69
+ }
70
+
71
+ // src/service.ts
72
+ function createLensService() {
73
+ const store = useLensStore;
74
+ return {
75
+ getState() {
76
+ return getLensState();
77
+ },
78
+ setImpersonatedAddress(address) {
79
+ store.getState().setImpersonatedAddress(address);
80
+ },
81
+ clearImpersonation() {
82
+ store.getState().clearImpersonation();
83
+ },
84
+ setRealAddress(address) {
85
+ store.getState().setRealAddress(address);
86
+ },
87
+ saveAddress(entry) {
88
+ store.getState().saveAddress(entry);
89
+ },
90
+ removeAddress(address) {
91
+ store.getState().removeAddress(address);
92
+ },
93
+ getContext() {
94
+ const state = getLensState();
95
+ return {
96
+ isImpersonating: state.enabled && state.impersonatedAddress !== null,
97
+ impersonatedAddress: state.impersonatedAddress,
98
+ realAddress: state.realAddress
99
+ };
100
+ },
101
+ subscribe(listener) {
102
+ return store.subscribe((state) => {
103
+ listener({
104
+ enabled: state.enabled,
105
+ impersonatedAddress: state.impersonatedAddress,
106
+ realAddress: state.realAddress,
107
+ savedAddresses: state.savedAddresses
108
+ });
109
+ });
110
+ }
111
+ };
112
+ }
113
+ var defaultLensService = null;
114
+ function getLensService() {
115
+ if (!defaultLensService) {
116
+ defaultLensService = createLensService();
117
+ }
118
+ return defaultLensService;
119
+ }
120
+ function resetLensService() {
121
+ if (defaultLensService) {
122
+ useLensStore.getState().reset();
123
+ }
124
+ defaultLensService = null;
125
+ }
126
+
127
+ // src/hooks.ts
128
+ function useLens() {
129
+ return useLensStore((state) => ({
130
+ enabled: state.enabled,
131
+ impersonatedAddress: state.impersonatedAddress,
132
+ realAddress: state.realAddress,
133
+ savedAddresses: state.savedAddresses
134
+ }));
135
+ }
136
+ function useLensContext() {
137
+ return useLensStore((state) => ({
138
+ isImpersonating: state.enabled && state.impersonatedAddress !== null,
139
+ impersonatedAddress: state.impersonatedAddress,
140
+ realAddress: state.realAddress
141
+ }));
142
+ }
143
+ function useIsImpersonating() {
144
+ return useLensStore(
145
+ (state) => state.enabled && state.impersonatedAddress !== null
146
+ );
147
+ }
148
+ function useImpersonatedAddress() {
149
+ return useLensStore(
150
+ (state) => state.enabled ? state.impersonatedAddress : null
151
+ );
152
+ }
153
+ function useRealAddress() {
154
+ return useLensStore((state) => state.realAddress);
155
+ }
156
+ function useEffectiveAddress() {
157
+ return useLensStore((state) => {
158
+ if (state.enabled && state.impersonatedAddress) {
159
+ return state.impersonatedAddress;
160
+ }
161
+ return state.realAddress ?? void 0;
162
+ });
163
+ }
164
+ function useSavedAddresses() {
165
+ const savedAddresses = useLensStore((state) => state.savedAddresses);
166
+ const saveAddress = useLensStore((state) => state.saveAddress);
167
+ const removeAddress = useLensStore((state) => state.removeAddress);
168
+ const setImpersonatedAddress = useLensStore((state) => state.setImpersonatedAddress);
169
+ return {
170
+ savedAddresses,
171
+ saveAddress: (entry) => saveAddress(entry),
172
+ removeAddress,
173
+ selectAddress: setImpersonatedAddress
174
+ };
175
+ }
176
+ function useLensActions() {
177
+ const setImpersonatedAddress = useLensStore((state) => state.setImpersonatedAddress);
178
+ const clearImpersonation = useLensStore((state) => state.clearImpersonation);
179
+ const setRealAddress = useLensStore((state) => state.setRealAddress);
180
+ return {
181
+ setImpersonatedAddress,
182
+ clearImpersonation,
183
+ setRealAddress
184
+ };
185
+ }
186
+ export {
187
+ LensError,
188
+ LensErrorCodes,
189
+ createLensService,
190
+ getLensService,
191
+ getLensState,
192
+ resetLensService,
193
+ useEffectiveAddress,
194
+ useImpersonatedAddress,
195
+ useIsImpersonating,
196
+ useLens,
197
+ useLensActions,
198
+ useLensContext,
199
+ useLensStore,
200
+ useRealAddress,
201
+ useSavedAddresses
202
+ };
203
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/store.ts","../src/service.ts","../src/hooks.ts"],"sourcesContent":["/**\n * Lens Service Types\n *\n * Types for address impersonation functionality.\n */\n\nimport type { Address } from 'viem'\n\n/**\n * Saved address entry for quick selection\n */\nexport interface SavedAddress {\n address: Address\n label: string\n addedAt: number\n}\n\n/**\n * Lens state\n */\nexport interface LensState {\n /** Whether lens impersonation is enabled */\n enabled: boolean\n /** Currently impersonated address */\n impersonatedAddress: Address | null\n /** The real connected wallet address */\n realAddress: Address | null\n /** Saved addresses for quick selection */\n savedAddresses: SavedAddress[]\n}\n\n/**\n * Lens context for components\n */\nexport interface LensContext {\n /** Whether currently impersonating */\n isImpersonating: boolean\n /** The impersonated address (if any) */\n impersonatedAddress: Address | null\n /** The real connected address */\n realAddress: Address | null\n}\n\n/**\n * Lens service interface\n */\nexport interface LensService {\n /** Get current lens state */\n getState(): LensState\n /** Enable lens and set impersonated address */\n setImpersonatedAddress(address: Address): void\n /** Clear impersonation */\n clearImpersonation(): void\n /** Set the real address (from wallet connection) */\n setRealAddress(address: Address | null): void\n /** Save an address for quick access */\n saveAddress(entry: Omit<SavedAddress, 'addedAt'>): void\n /** Remove a saved address */\n removeAddress(address: Address): void\n /** Get lens context */\n getContext(): LensContext\n /** Subscribe to state changes */\n subscribe(listener: (state: LensState) => void): () => void\n}\n\n/**\n * Lens error\n */\nexport class LensError extends Error {\n constructor(\n message: string,\n public code: string,\n public recoverable: boolean = true\n ) {\n super(message)\n this.name = 'LensError'\n }\n}\n\n/**\n * Lens error codes\n */\nexport const LensErrorCodes = {\n INVALID_ADDRESS: 'LENS_INVALID_ADDRESS',\n NOT_CONNECTED: 'LENS_NOT_CONNECTED',\n} as const\n","/**\n * Lens Store\n *\n * Zustand store for lens state management.\n */\n\nimport { create } from 'zustand'\nimport { persist } from 'zustand/middleware'\nimport type { Address } from 'viem'\nimport type { LensState, SavedAddress } from './types'\n\n/**\n * Lens store actions\n */\ninterface LensActions {\n setImpersonatedAddress: (address: Address) => void\n clearImpersonation: () => void\n setRealAddress: (address: Address | null) => void\n saveAddress: (entry: Omit<SavedAddress, 'addedAt'>) => void\n removeAddress: (address: Address) => void\n reset: () => void\n}\n\n/**\n * Combined lens store type\n */\nexport type LensStore = LensState & LensActions\n\n/**\n * Initial lens state\n */\nconst initialState: LensState = {\n enabled: false,\n impersonatedAddress: null,\n realAddress: null,\n savedAddresses: [],\n}\n\n/**\n * Create the lens store\n */\nexport const useLensStore = create<LensStore>()(\n persist(\n (set) => ({\n ...initialState,\n\n setImpersonatedAddress: (address: Address) =>\n set({\n enabled: true,\n impersonatedAddress: address,\n }),\n\n clearImpersonation: () =>\n set({\n enabled: false,\n impersonatedAddress: null,\n }),\n\n setRealAddress: (address: Address | null) =>\n set({ realAddress: address }),\n\n saveAddress: (entry: Omit<SavedAddress, 'addedAt'>) =>\n set((state) => {\n // Don't add duplicates\n if (state.savedAddresses.some((a) => a.address === entry.address)) {\n return state\n }\n return {\n savedAddresses: [\n ...state.savedAddresses,\n { ...entry, addedAt: Date.now() },\n ],\n }\n }),\n\n removeAddress: (address: Address) =>\n set((state) => ({\n savedAddresses: state.savedAddresses.filter((a) => a.address !== address),\n })),\n\n reset: () => set(initialState),\n }),\n {\n name: 'sigil-lens-storage',\n partialize: (state) => ({\n savedAddresses: state.savedAddresses,\n }),\n }\n )\n)\n\n/**\n * Get lens store state (for non-React contexts)\n */\nexport function getLensState(): LensState {\n const state = useLensStore.getState()\n return {\n enabled: state.enabled,\n impersonatedAddress: state.impersonatedAddress,\n realAddress: state.realAddress,\n savedAddresses: state.savedAddresses,\n }\n}\n","/**\n * Lens Service Implementation\n *\n * Provides lens functionality for non-React contexts.\n */\n\nimport type { Address } from 'viem'\nimport type { LensService, LensState, LensContext, SavedAddress } from './types'\nimport { useLensStore, getLensState } from './store'\n\n/**\n * Create a lens service\n */\nexport function createLensService(): LensService {\n const store = useLensStore\n\n return {\n getState(): LensState {\n return getLensState()\n },\n\n setImpersonatedAddress(address: Address): void {\n store.getState().setImpersonatedAddress(address)\n },\n\n clearImpersonation(): void {\n store.getState().clearImpersonation()\n },\n\n setRealAddress(address: Address | null): void {\n store.getState().setRealAddress(address)\n },\n\n saveAddress(entry: Omit<SavedAddress, 'addedAt'>): void {\n store.getState().saveAddress(entry)\n },\n\n removeAddress(address: Address): void {\n store.getState().removeAddress(address)\n },\n\n getContext(): LensContext {\n const state = getLensState()\n return {\n isImpersonating: state.enabled && state.impersonatedAddress !== null,\n impersonatedAddress: state.impersonatedAddress,\n realAddress: state.realAddress,\n }\n },\n\n subscribe(listener: (state: LensState) => void): () => void {\n return store.subscribe((state) => {\n listener({\n enabled: state.enabled,\n impersonatedAddress: state.impersonatedAddress,\n realAddress: state.realAddress,\n savedAddresses: state.savedAddresses,\n })\n })\n },\n }\n}\n\n/**\n * Default lens service singleton\n */\nlet defaultLensService: LensService | null = null\n\n/**\n * Get the default lens service\n */\nexport function getLensService(): LensService {\n if (!defaultLensService) {\n defaultLensService = createLensService()\n }\n return defaultLensService\n}\n\n/**\n * Reset the default lens service\n */\nexport function resetLensService(): void {\n if (defaultLensService) {\n useLensStore.getState().reset()\n }\n defaultLensService = null\n}\n","/**\n * Lens React Hooks\n *\n * React hooks for accessing lens state.\n */\n\nimport type { Address } from 'viem'\nimport { useLensStore } from './store'\nimport type { LensState, LensContext, SavedAddress } from './types'\n\n/**\n * Hook to get the full lens state\n *\n * @example\n * ```tsx\n * function LensStatus() {\n * const { enabled, impersonatedAddress, realAddress } = useLens()\n * return <div>{enabled ? `Impersonating ${impersonatedAddress}` : 'Not impersonating'}</div>\n * }\n * ```\n */\nexport function useLens(): LensState {\n return useLensStore((state) => ({\n enabled: state.enabled,\n impersonatedAddress: state.impersonatedAddress,\n realAddress: state.realAddress,\n savedAddresses: state.savedAddresses,\n }))\n}\n\n/**\n * Hook to get lens context for components\n *\n * @example\n * ```tsx\n * function AddressDisplay() {\n * const { isImpersonating, impersonatedAddress, realAddress } = useLensContext()\n * return <div>{isImpersonating ? impersonatedAddress : realAddress}</div>\n * }\n * ```\n */\nexport function useLensContext(): LensContext {\n return useLensStore((state) => ({\n isImpersonating: state.enabled && state.impersonatedAddress !== null,\n impersonatedAddress: state.impersonatedAddress,\n realAddress: state.realAddress,\n }))\n}\n\n/**\n * Hook to check if currently impersonating\n *\n * @example\n * ```tsx\n * function LensBadge() {\n * const isImpersonating = useIsImpersonating()\n * if (!isImpersonating) return null\n * return <Badge variant=\"warning\">Lens Active</Badge>\n * }\n * ```\n */\nexport function useIsImpersonating(): boolean {\n return useLensStore(\n (state) => state.enabled && state.impersonatedAddress !== null\n )\n}\n\n/**\n * Hook to get the impersonated address (or null if not impersonating)\n */\nexport function useImpersonatedAddress(): Address | null {\n return useLensStore((state) =>\n state.enabled ? state.impersonatedAddress : null\n )\n}\n\n/**\n * Hook to get the real connected address\n */\nexport function useRealAddress(): Address | null {\n return useLensStore((state) => state.realAddress)\n}\n\n/**\n * Hook to get the effective address (impersonated if active, otherwise real)\n */\nexport function useEffectiveAddress(): Address | undefined {\n return useLensStore((state) => {\n if (state.enabled && state.impersonatedAddress) {\n return state.impersonatedAddress\n }\n return state.realAddress ?? undefined\n })\n}\n\n/**\n * Hook to get saved addresses and actions\n *\n * @example\n * ```tsx\n * function SavedAddressList() {\n * const { savedAddresses, saveAddress, removeAddress, selectAddress } = useSavedAddresses()\n * return (\n * <ul>\n * {savedAddresses.map(({ address, label }) => (\n * <li key={address} onClick={() => selectAddress(address)}>\n * {label}: {address}\n * <button onClick={() => removeAddress(address)}>Remove</button>\n * </li>\n * ))}\n * </ul>\n * )\n * }\n * ```\n */\nexport function useSavedAddresses() {\n const savedAddresses = useLensStore((state) => state.savedAddresses)\n const saveAddress = useLensStore((state) => state.saveAddress)\n const removeAddress = useLensStore((state) => state.removeAddress)\n const setImpersonatedAddress = useLensStore((state) => state.setImpersonatedAddress)\n\n return {\n savedAddresses,\n saveAddress: (entry: Omit<SavedAddress, 'addedAt'>) => saveAddress(entry),\n removeAddress,\n selectAddress: setImpersonatedAddress,\n }\n}\n\n/**\n * Hook to get lens actions\n */\nexport function useLensActions() {\n const setImpersonatedAddress = useLensStore((state) => state.setImpersonatedAddress)\n const clearImpersonation = useLensStore((state) => state.clearImpersonation)\n const setRealAddress = useLensStore((state) => state.setRealAddress)\n\n return {\n setImpersonatedAddress,\n clearImpersonation,\n setRealAddress,\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,56 @@
1
+ import { Address } from 'viem';
2
+
3
+ /**
4
+ * Lens Wagmi Integration
5
+ *
6
+ * Wagmi-aware hooks for lens functionality.
7
+ */
8
+
9
+ /**
10
+ * Return type for useLensAwareAccount
11
+ */
12
+ interface LensAwareAccount {
13
+ /** Address for reads - impersonated if lens enabled, otherwise real */
14
+ address: Address | undefined;
15
+ /** The user's real connected address (always available for signing) */
16
+ realAddress: Address | undefined;
17
+ /** Whether currently impersonating another address */
18
+ isImpersonating: boolean;
19
+ /** The impersonated address (if any) */
20
+ impersonatedAddress: Address | null;
21
+ /** Whether the wallet is connected */
22
+ isConnected: boolean;
23
+ }
24
+ /**
25
+ * Hook that returns impersonated address for reads, real address for writes.
26
+ *
27
+ * Use this hook in place of wagmi's `useAccount` when you want components
28
+ * to display data for an impersonated address while still being able to
29
+ * sign transactions with the real connected wallet.
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * function WalletInfo() {
34
+ * const { address, realAddress, isImpersonating } = useLensAwareAccount()
35
+ *
36
+ * // Use `address` for reading data (respects impersonation)
37
+ * const { data: balance } = useBalance({ address })
38
+ *
39
+ * // Use `realAddress` for signing transactions
40
+ * const { writeContract } = useWriteContract()
41
+ *
42
+ * return (
43
+ * <div>
44
+ * <p>Viewing: {address}</p>
45
+ * {isImpersonating && <Badge>Lens Active</Badge>}
46
+ * <button onClick={() => writeContract({ ... })}>
47
+ * Sign with {realAddress}
48
+ * </button>
49
+ * </div>
50
+ * )
51
+ * }
52
+ * ```
53
+ */
54
+ declare function useLensAwareAccount(): LensAwareAccount;
55
+
56
+ export { type LensAwareAccount, useLensAwareAccount };