@pafi-dev/core 0.3.0-beta.0 → 0.3.0-beta.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/dist/index.d.cts CHANGED
@@ -7,8 +7,8 @@ import { SimulationResult } from './relay/index.cjs';
7
7
  export { buildRelaySwapParams, decodeExtData, decodeMintAndSwap, encodeExtData, encodeMintAndSwap, simulateMintAndSwap } from './relay/index.cjs';
8
8
  export { getIssuer, getMintRequestNonce, getPointTokenBalance, getPointTokenIssuer, getPointTokenIssuerAddress, getReceiverConsentNonce, getTokenName, getUsdt, isActiveIssuer, isMinter, verifyMintCap } from './contract/index.cjs';
9
9
  export { buildAllPaths, combineRoutes, findBestQuote, quoteBestRoute, quoteExactInput, quoteExactInputSingle } from './quoting/index.cjs';
10
- import { SwapSimulationResult } from './swap/index.cjs';
11
- export { SETTLE_ALL, SWAP_EXACT_IN, TAKE_ALL, V4_SWAP, buildErc20ApprovalCalldata, buildPermit2ApprovalCalldata, buildSwapFromQuote, buildUniversalRouterExecuteArgs, buildV4SwapInput, checkAllowance, simulateSwap } from './swap/index.cjs';
10
+ import { O as Operation, P as PartialUserOperation, U as UserOperation, S as SwapSimulationResult } from './index-BpUYHGu3.cjs';
11
+ export { B as BuildSwapWithGasDeductionParams, E as ENTRY_POINT_V07, a as PaymasterFields, b as SETTLE_ALL, c as SWAP_EXACT_IN, T as TAKE_ALL, d as UserOpReceipt, V as V4_SWAP, Z as ZERO_VALUE, e as buildErc20ApprovalCalldata, f as buildPermit2ApprovalCalldata, g as buildSwapFromQuote, h as buildSwapWithGasDeduction, i as buildUniversalRouterExecuteArgs, j as buildV4SwapInput, k as checkAllowance, s as simulateSwap } from './index-BpUYHGu3.cjs';
12
12
  import { LoginMessageParams } from './auth/index.cjs';
13
13
  export { VerifyLoginResult, createLoginMessage, parseLoginMessage, verifyLoginMessage } from './auth/index.cjs';
14
14
 
@@ -74,74 +74,6 @@ declare class ApiError extends PafiSDKError {
74
74
  constructor(message: string, status?: number | undefined);
75
75
  }
76
76
 
77
- /**
78
- * ERC-4337 v0.7 EntryPoint standard address (deployed deterministically
79
- * at the same address across chains).
80
- * https://eips.ethereum.org/EIPS/eip-4337
81
- */
82
- declare const ENTRY_POINT_V07: Address;
83
- /**
84
- * A single call inside a batch. `BatchExecutor.execute(Call[])` iterates
85
- * and invokes each one. When the batch runs via EIP-7702 delegation,
86
- * `msg.sender` for each call is the user's EOA.
87
- */
88
- interface Operation {
89
- target: Address;
90
- value: bigint;
91
- data: Hex;
92
- }
93
- /**
94
- * Paymaster fields attached to a UserOperation. Populated by the
95
- * Coinbase Paymaster (via PAFI Backend proxy) before the user signs.
96
- */
97
- interface PaymasterFields {
98
- paymaster: Address;
99
- paymasterData: Hex;
100
- paymasterVerificationGasLimit: bigint;
101
- paymasterPostOpGasLimit: bigint;
102
- }
103
- /**
104
- * Partial UserOp used during preparation — before paymaster fields are
105
- * attached or the user signs.
106
- */
107
- interface PartialUserOperation {
108
- sender: Address;
109
- nonce: bigint;
110
- callData: Hex;
111
- callGasLimit: bigint;
112
- verificationGasLimit: bigint;
113
- preVerificationGas: bigint;
114
- maxFeePerGas: bigint;
115
- maxPriorityFeePerGas: bigint;
116
- }
117
- /**
118
- * Full ERC-4337 v0.7 UserOperation, ready for bundler submission.
119
- */
120
- interface UserOperation extends PartialUserOperation {
121
- paymaster: Address;
122
- paymasterData: Hex;
123
- paymasterVerificationGasLimit: bigint;
124
- paymasterPostOpGasLimit: bigint;
125
- signature: Hex;
126
- }
127
- /**
128
- * Receipt returned by a bundler after a UserOp lands on-chain.
129
- */
130
- interface UserOpReceipt {
131
- userOpHash: Hex;
132
- success: boolean;
133
- txHash: Hex;
134
- blockNumber: bigint;
135
- gasUsed: bigint;
136
- /** Effective gas cost paid (wei). */
137
- actualGasCost: bigint;
138
- }
139
- /**
140
- * Sentinel operation value used in tests + docs when `Operation.value`
141
- * is irrelevant (ERC-20 transfers, for example).
142
- */
143
- declare const ZERO_VALUE = 0n;
144
-
145
77
  /**
146
78
  * Build an ERC-20 `transfer(to, amount)` operation. Used inside a batch
147
79
  * to move fee tokens from the user to the fee recipient atomically with
@@ -812,6 +744,188 @@ declare function buildMockBurnConsentTypedData(domain: PointTokenDomainConfig, m
812
744
  declare function signMockBurnConsent(walletClient: WalletClient, domain: PointTokenDomainConfig, message: MockBurnConsent): Promise<EIP712Signature>;
813
745
  declare function verifyMockBurnConsent(domain: PointTokenDomainConfig, message: MockBurnConsent, signature: Hex, expectedUser: Address): Promise<SignatureVerification>;
814
746
 
747
+ /**
748
+ * Options for opening a PAFI Web modal — passed through by all adapters.
749
+ * Web-only fields (width/height/windowName) are ignored by mobile
750
+ * adapters that can't resize a system in-app browser.
751
+ */
752
+ interface ModalOpenOptions {
753
+ /** Web popup pixel width. Default 900. Ignored on mobile. */
754
+ width?: number;
755
+ /** Web popup pixel height. Default 700. Ignored on mobile. */
756
+ height?: number;
757
+ /**
758
+ * `window.open()` target name. Same name across calls re-uses an
759
+ * already-open popup. Default: `"pafi-web"`. Web-only.
760
+ */
761
+ windowName?: string;
762
+ /**
763
+ * Called when the modal closes — either user-initiated (clicked
764
+ * close, swiped down on mobile) or programmatically via `handle.close()`.
765
+ */
766
+ onClose?: () => void;
767
+ /**
768
+ * Called when the opened window posts a message back to the parent
769
+ * via `window.opener.postMessage(data, origin)`. PAFI Web uses this
770
+ * to signal "swap complete" / "perp deposit complete" back to the
771
+ * issuer app without needing a redirect.
772
+ *
773
+ * `origin` is the posting window's origin — caller MUST verify it
774
+ * matches the expected PAFI Web host before trusting `data`.
775
+ */
776
+ onMessage?: (data: unknown, origin: string) => void;
777
+ /**
778
+ * Allowed origins for `onMessage` — messages from other origins are
779
+ * silently dropped. Pass the PAFI Web host(s), e.g.
780
+ * `["https://app.pacificfinance.org", "https://app-dev.pacificfinance.org"]`.
781
+ *
782
+ * Default: empty (all messages rejected). Set explicitly for security.
783
+ */
784
+ allowedOrigins?: string[];
785
+ }
786
+ /**
787
+ * Handle to an open PAFI Web modal. Methods are no-ops when the modal
788
+ * has already closed — safe to call without tracking state yourself.
789
+ */
790
+ interface PafiWebModalHandle {
791
+ /** True when the modal is still open. */
792
+ readonly isOpen: boolean;
793
+ /** Close the modal. Fires `onClose` if the callback was supplied. */
794
+ close(): void;
795
+ /** Bring the modal to focus (web popup only; mobile ignores). */
796
+ focus(): void;
797
+ /**
798
+ * Post a message INTO the modal — useful for ping/pong handshakes
799
+ * with PAFI Web. The modal page must be on the same origin or
800
+ * explicitly listen for the message.
801
+ */
802
+ postMessage(data: unknown): void;
803
+ }
804
+ /**
805
+ * Adapter that knows how to open a URL in the right UX for the host
806
+ * platform. Callers register one via `setPafiWebModalAdapter()`; if
807
+ * none is registered, the core module falls back to `openWebPopup()`
808
+ * (if `window` is present) or throws (in Node / React Native without
809
+ * an adapter set).
810
+ *
811
+ * ## Mobile adapter example (React Native)
812
+ *
813
+ * ```ts
814
+ * import { setPafiWebModalAdapter } from '@pafi-dev/core';
815
+ * import InAppBrowser from 'react-native-inappbrowser-reborn';
816
+ *
817
+ * setPafiWebModalAdapter({
818
+ * async open(url, options) {
819
+ * const result = await InAppBrowser.open(url, {
820
+ * // iOS: SFSafariViewController
821
+ * dismissButtonStyle: 'close',
822
+ * preferredBarTintColor: '#1a1a1a',
823
+ * preferredControlTintColor: 'white',
824
+ * // Android: Chrome Custom Tab
825
+ * toolbarColor: '#1a1a1a',
826
+ * secondaryToolbarColor: 'black',
827
+ * });
828
+ * options?.onClose?.();
829
+ * return {
830
+ * isOpen: false,
831
+ * close: () => InAppBrowser.close(),
832
+ * focus: () => {},
833
+ * postMessage: () => {},
834
+ * };
835
+ * },
836
+ * });
837
+ * ```
838
+ *
839
+ * ## Expo adapter example
840
+ *
841
+ * ```ts
842
+ * import * as WebBrowser from 'expo-web-browser';
843
+ *
844
+ * setPafiWebModalAdapter({
845
+ * async open(url, options) {
846
+ * await WebBrowser.openBrowserAsync(url);
847
+ * options?.onClose?.();
848
+ * return { isOpen: false, close: WebBrowser.dismissBrowser, focus: () => {}, postMessage: () => {} };
849
+ * },
850
+ * });
851
+ * ```
852
+ */
853
+ interface PafiWebModalAdapter {
854
+ open(url: string, options?: ModalOpenOptions): PafiWebModalHandle | Promise<PafiWebModalHandle>;
855
+ }
856
+
857
+ /**
858
+ * Web browser popup adapter. Opens the given URL in a centered
859
+ * `window.open()` popup, polls for close, and optionally forwards
860
+ * `postMessage` events back to the caller.
861
+ *
862
+ * Runtime requirement: `window.open` must exist. Throws if called
863
+ * under Node / SSR / React Native — use `setPafiWebModalAdapter()` to
864
+ * provide a platform-specific adapter in those environments.
865
+ *
866
+ * ## Popup blocking
867
+ *
868
+ * Browsers block `window.open()` unless it happens inside a user
869
+ * gesture (click handler). Callers MUST wire this into a direct click
870
+ * handler — wrapping it in a `setTimeout` or async await before the
871
+ * open call will trigger the blocker.
872
+ */
873
+ declare function openWebPopup(url: string, options?: ModalOpenOptions): PafiWebModalHandle;
874
+ /**
875
+ * The web popup packaged as a {@link PafiWebModalAdapter} so callers
876
+ * can register it explicitly (e.g. in a test harness).
877
+ */
878
+ declare const webPopupAdapter: PafiWebModalAdapter;
879
+
880
+ /**
881
+ * Register the adapter used by `openPafiWebModal()`. Typically called
882
+ * once during app initialization — mobile apps register a
883
+ * SFSafariViewController / Chrome Custom Tabs adapter, desktop apps
884
+ * can leave it unset (web popup is the default).
885
+ *
886
+ * Pass `null` to unregister and fall back to the default.
887
+ */
888
+ declare function setPafiWebModalAdapter(adapter: PafiWebModalAdapter | null): void;
889
+ /**
890
+ * Return the currently registered adapter, or `null` when none is set.
891
+ * Useful for tests that want to snapshot-and-restore the adapter.
892
+ */
893
+ declare function getPafiWebModalAdapter(): PafiWebModalAdapter | null;
894
+ /**
895
+ * Open PAFI Web in the host platform's appropriate UX:
896
+ *
897
+ * - Browser (window.open): centered popup, 900×700 by default
898
+ * - React Native (with adapter registered): SFSafariViewController
899
+ * / Chrome Custom Tabs via `react-native-inappbrowser-reborn` or
900
+ * `expo-web-browser`
901
+ * - Desktop (with adapter registered): custom BrowserWindow / new tab
902
+ *
903
+ * Resolution order:
904
+ * 1. If an adapter was registered via `setPafiWebModalAdapter()`, use it.
905
+ * 2. Else if `window.open` is available, use the built-in web popup.
906
+ * 3. Else throw with a clear error pointing at the adapter registry.
907
+ *
908
+ * @example
909
+ * ```ts
910
+ * // User clicks "Trade on PAFI" button
911
+ * button.addEventListener('click', async () => {
912
+ * const modal = await openPafiWebModal('https://app.pacificfinance.org', {
913
+ * allowedOrigins: ['https://app.pacificfinance.org'],
914
+ * onMessage: (data, origin) => {
915
+ * if (typeof data === 'object' && data && 'txHash' in data) {
916
+ * console.log('Swap confirmed:', data.txHash);
917
+ * modal.close();
918
+ * }
919
+ * },
920
+ * onClose: () => {
921
+ * console.log('User closed modal');
922
+ * },
923
+ * });
924
+ * });
925
+ * ```
926
+ */
927
+ declare function openPafiWebModal(url: string, options?: ModalOpenOptions): Promise<PafiWebModalHandle>;
928
+
815
929
  declare class PafiSDK {
816
930
  private _pointTokenAddress?;
817
931
  private _relayContractAddress?;
@@ -974,4 +1088,4 @@ declare class PafiSDK {
974
1088
  signLoginMessage(message: string): Promise<Hex>;
975
1089
  }
976
1090
 
977
- export { ApiError, BATCH_EXECUTOR_ABI, MOCK_BATCH_EXECUTOR_ADDRESS_BASE_MAINNET as BATCH_EXECUTOR_ADDRESS_BASE_MAINNET, MOCK_BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA as BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA, MOCK_BURN_CONSENT_TYPES as BURN_CONSENT_TYPES, BestQuote, type BuildPartialUserOpParams, type MockBurnConsent as BurnConsent, COMMON_POOLS, COMMON_TOKENS, MOCK_ADDRESSES as CONTRACT_ADDRESSES, ChainConfig, type CheckEthAndBranchParams, ConfigurationError, type ContractAddresses, EIP712Signature, ENTRY_POINT_V07, LoginMessageParams, MOCK_MINT_REQUEST_V2_TYPES as MINT_REQUEST_V2_TYPES, MintParams, MintRequest, type MockMintRequestV2 as MintRequestV2, type Operation, POINT_TOKEN_POOLS, MOCK_POINT_TOKEN_V2_ABI as POINT_TOKEN_V2_ABI, PafiSDK, PafiSDKConfig, PafiSDKError, type PartialUserOperation, PathKey, type PaymasterConfig, type PaymasterFields, PointTokenDomainConfig, PoolKey, QuoteResult, MOCK_RELAYER_V2_ABI as RELAYER_V2_ABI, MOCK_RELAYER_V2_MINT_SELECTOR as RELAYER_V2_MINT_SELECTOR, ReceiverConsent, SUPPORTED_CHAINS, type MockSignatureStruct as SignatureStruct, SignatureVerification, SigningError, SimulationError, SimulationResult, type SponsorshipScenario, type SubmissionPath, SwapParams, SwapSimulationResult, UNIVERSAL_ROUTER_ADDRESSES, type UserOpReceipt, type UserOperation, V4_QUOTER_ADDRESSES, ZERO_VALUE, _resetPaymasterConfigForTests, assembleUserOperation, buildMockBurnConsentTypedData as buildBurnConsentTypedData, buildMockMintRequestV2TypedData as buildMintRequestV2TypedData, buildPartialUserOperation, checkEthAndBranch, encodeBatchExecute, erc20ApproveOp, erc20BurnOp, erc20TransferOp, getMockAddresses as getContractAddresses, getPaymasterConfig, isPaymasterConfigured, mintRequestTypes, rawCallOp, receiverConsentTypes, setPaymasterConfig, signMockBurnConsent as signBurnConsent, signMockMintRequestV2 as signMintRequestV2, verifyMockBurnConsent as verifyBurnConsent, verifyMockMintRequestV2 as verifyMintRequestV2 };
1091
+ export { ApiError, BATCH_EXECUTOR_ABI, MOCK_BATCH_EXECUTOR_ADDRESS_BASE_MAINNET as BATCH_EXECUTOR_ADDRESS_BASE_MAINNET, MOCK_BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA as BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA, MOCK_BURN_CONSENT_TYPES as BURN_CONSENT_TYPES, BestQuote, type BuildPartialUserOpParams, type MockBurnConsent as BurnConsent, COMMON_POOLS, COMMON_TOKENS, MOCK_ADDRESSES as CONTRACT_ADDRESSES, ChainConfig, type CheckEthAndBranchParams, ConfigurationError, type ContractAddresses, EIP712Signature, LoginMessageParams, MOCK_MINT_REQUEST_V2_TYPES as MINT_REQUEST_V2_TYPES, MintParams, MintRequest, type MockMintRequestV2 as MintRequestV2, type ModalOpenOptions, Operation, POINT_TOKEN_POOLS, MOCK_POINT_TOKEN_V2_ABI as POINT_TOKEN_V2_ABI, PafiSDK, PafiSDKConfig, PafiSDKError, type PafiWebModalAdapter, type PafiWebModalHandle, PartialUserOperation, PathKey, type PaymasterConfig, PointTokenDomainConfig, PoolKey, QuoteResult, MOCK_RELAYER_V2_ABI as RELAYER_V2_ABI, MOCK_RELAYER_V2_MINT_SELECTOR as RELAYER_V2_MINT_SELECTOR, ReceiverConsent, SUPPORTED_CHAINS, type MockSignatureStruct as SignatureStruct, SignatureVerification, SigningError, SimulationError, SimulationResult, type SponsorshipScenario, type SubmissionPath, SwapParams, SwapSimulationResult, UNIVERSAL_ROUTER_ADDRESSES, UserOperation, V4_QUOTER_ADDRESSES, _resetPaymasterConfigForTests, assembleUserOperation, buildMockBurnConsentTypedData as buildBurnConsentTypedData, buildMockMintRequestV2TypedData as buildMintRequestV2TypedData, buildPartialUserOperation, checkEthAndBranch, encodeBatchExecute, erc20ApproveOp, erc20BurnOp, erc20TransferOp, getMockAddresses as getContractAddresses, getPafiWebModalAdapter, getPaymasterConfig, isPaymasterConfigured, mintRequestTypes, openPafiWebModal, openWebPopup, rawCallOp, receiverConsentTypes, setPafiWebModalAdapter, setPaymasterConfig, signMockBurnConsent as signBurnConsent, signMockMintRequestV2 as signMintRequestV2, verifyMockBurnConsent as verifyBurnConsent, verifyMockMintRequestV2 as verifyMintRequestV2, webPopupAdapter };
package/dist/index.d.ts CHANGED
@@ -7,8 +7,8 @@ import { SimulationResult } from './relay/index.js';
7
7
  export { buildRelaySwapParams, decodeExtData, decodeMintAndSwap, encodeExtData, encodeMintAndSwap, simulateMintAndSwap } from './relay/index.js';
8
8
  export { getIssuer, getMintRequestNonce, getPointTokenBalance, getPointTokenIssuer, getPointTokenIssuerAddress, getReceiverConsentNonce, getTokenName, getUsdt, isActiveIssuer, isMinter, verifyMintCap } from './contract/index.js';
9
9
  export { buildAllPaths, combineRoutes, findBestQuote, quoteBestRoute, quoteExactInput, quoteExactInputSingle } from './quoting/index.js';
10
- import { SwapSimulationResult } from './swap/index.js';
11
- export { SETTLE_ALL, SWAP_EXACT_IN, TAKE_ALL, V4_SWAP, buildErc20ApprovalCalldata, buildPermit2ApprovalCalldata, buildSwapFromQuote, buildUniversalRouterExecuteArgs, buildV4SwapInput, checkAllowance, simulateSwap } from './swap/index.js';
10
+ import { O as Operation, P as PartialUserOperation, U as UserOperation, S as SwapSimulationResult } from './index-CNALKsH1.js';
11
+ export { B as BuildSwapWithGasDeductionParams, E as ENTRY_POINT_V07, a as PaymasterFields, b as SETTLE_ALL, c as SWAP_EXACT_IN, T as TAKE_ALL, d as UserOpReceipt, V as V4_SWAP, Z as ZERO_VALUE, e as buildErc20ApprovalCalldata, f as buildPermit2ApprovalCalldata, g as buildSwapFromQuote, h as buildSwapWithGasDeduction, i as buildUniversalRouterExecuteArgs, j as buildV4SwapInput, k as checkAllowance, s as simulateSwap } from './index-CNALKsH1.js';
12
12
  import { LoginMessageParams } from './auth/index.js';
13
13
  export { VerifyLoginResult, createLoginMessage, parseLoginMessage, verifyLoginMessage } from './auth/index.js';
14
14
 
@@ -74,74 +74,6 @@ declare class ApiError extends PafiSDKError {
74
74
  constructor(message: string, status?: number | undefined);
75
75
  }
76
76
 
77
- /**
78
- * ERC-4337 v0.7 EntryPoint standard address (deployed deterministically
79
- * at the same address across chains).
80
- * https://eips.ethereum.org/EIPS/eip-4337
81
- */
82
- declare const ENTRY_POINT_V07: Address;
83
- /**
84
- * A single call inside a batch. `BatchExecutor.execute(Call[])` iterates
85
- * and invokes each one. When the batch runs via EIP-7702 delegation,
86
- * `msg.sender` for each call is the user's EOA.
87
- */
88
- interface Operation {
89
- target: Address;
90
- value: bigint;
91
- data: Hex;
92
- }
93
- /**
94
- * Paymaster fields attached to a UserOperation. Populated by the
95
- * Coinbase Paymaster (via PAFI Backend proxy) before the user signs.
96
- */
97
- interface PaymasterFields {
98
- paymaster: Address;
99
- paymasterData: Hex;
100
- paymasterVerificationGasLimit: bigint;
101
- paymasterPostOpGasLimit: bigint;
102
- }
103
- /**
104
- * Partial UserOp used during preparation — before paymaster fields are
105
- * attached or the user signs.
106
- */
107
- interface PartialUserOperation {
108
- sender: Address;
109
- nonce: bigint;
110
- callData: Hex;
111
- callGasLimit: bigint;
112
- verificationGasLimit: bigint;
113
- preVerificationGas: bigint;
114
- maxFeePerGas: bigint;
115
- maxPriorityFeePerGas: bigint;
116
- }
117
- /**
118
- * Full ERC-4337 v0.7 UserOperation, ready for bundler submission.
119
- */
120
- interface UserOperation extends PartialUserOperation {
121
- paymaster: Address;
122
- paymasterData: Hex;
123
- paymasterVerificationGasLimit: bigint;
124
- paymasterPostOpGasLimit: bigint;
125
- signature: Hex;
126
- }
127
- /**
128
- * Receipt returned by a bundler after a UserOp lands on-chain.
129
- */
130
- interface UserOpReceipt {
131
- userOpHash: Hex;
132
- success: boolean;
133
- txHash: Hex;
134
- blockNumber: bigint;
135
- gasUsed: bigint;
136
- /** Effective gas cost paid (wei). */
137
- actualGasCost: bigint;
138
- }
139
- /**
140
- * Sentinel operation value used in tests + docs when `Operation.value`
141
- * is irrelevant (ERC-20 transfers, for example).
142
- */
143
- declare const ZERO_VALUE = 0n;
144
-
145
77
  /**
146
78
  * Build an ERC-20 `transfer(to, amount)` operation. Used inside a batch
147
79
  * to move fee tokens from the user to the fee recipient atomically with
@@ -812,6 +744,188 @@ declare function buildMockBurnConsentTypedData(domain: PointTokenDomainConfig, m
812
744
  declare function signMockBurnConsent(walletClient: WalletClient, domain: PointTokenDomainConfig, message: MockBurnConsent): Promise<EIP712Signature>;
813
745
  declare function verifyMockBurnConsent(domain: PointTokenDomainConfig, message: MockBurnConsent, signature: Hex, expectedUser: Address): Promise<SignatureVerification>;
814
746
 
747
+ /**
748
+ * Options for opening a PAFI Web modal — passed through by all adapters.
749
+ * Web-only fields (width/height/windowName) are ignored by mobile
750
+ * adapters that can't resize a system in-app browser.
751
+ */
752
+ interface ModalOpenOptions {
753
+ /** Web popup pixel width. Default 900. Ignored on mobile. */
754
+ width?: number;
755
+ /** Web popup pixel height. Default 700. Ignored on mobile. */
756
+ height?: number;
757
+ /**
758
+ * `window.open()` target name. Same name across calls re-uses an
759
+ * already-open popup. Default: `"pafi-web"`. Web-only.
760
+ */
761
+ windowName?: string;
762
+ /**
763
+ * Called when the modal closes — either user-initiated (clicked
764
+ * close, swiped down on mobile) or programmatically via `handle.close()`.
765
+ */
766
+ onClose?: () => void;
767
+ /**
768
+ * Called when the opened window posts a message back to the parent
769
+ * via `window.opener.postMessage(data, origin)`. PAFI Web uses this
770
+ * to signal "swap complete" / "perp deposit complete" back to the
771
+ * issuer app without needing a redirect.
772
+ *
773
+ * `origin` is the posting window's origin — caller MUST verify it
774
+ * matches the expected PAFI Web host before trusting `data`.
775
+ */
776
+ onMessage?: (data: unknown, origin: string) => void;
777
+ /**
778
+ * Allowed origins for `onMessage` — messages from other origins are
779
+ * silently dropped. Pass the PAFI Web host(s), e.g.
780
+ * `["https://app.pacificfinance.org", "https://app-dev.pacificfinance.org"]`.
781
+ *
782
+ * Default: empty (all messages rejected). Set explicitly for security.
783
+ */
784
+ allowedOrigins?: string[];
785
+ }
786
+ /**
787
+ * Handle to an open PAFI Web modal. Methods are no-ops when the modal
788
+ * has already closed — safe to call without tracking state yourself.
789
+ */
790
+ interface PafiWebModalHandle {
791
+ /** True when the modal is still open. */
792
+ readonly isOpen: boolean;
793
+ /** Close the modal. Fires `onClose` if the callback was supplied. */
794
+ close(): void;
795
+ /** Bring the modal to focus (web popup only; mobile ignores). */
796
+ focus(): void;
797
+ /**
798
+ * Post a message INTO the modal — useful for ping/pong handshakes
799
+ * with PAFI Web. The modal page must be on the same origin or
800
+ * explicitly listen for the message.
801
+ */
802
+ postMessage(data: unknown): void;
803
+ }
804
+ /**
805
+ * Adapter that knows how to open a URL in the right UX for the host
806
+ * platform. Callers register one via `setPafiWebModalAdapter()`; if
807
+ * none is registered, the core module falls back to `openWebPopup()`
808
+ * (if `window` is present) or throws (in Node / React Native without
809
+ * an adapter set).
810
+ *
811
+ * ## Mobile adapter example (React Native)
812
+ *
813
+ * ```ts
814
+ * import { setPafiWebModalAdapter } from '@pafi-dev/core';
815
+ * import InAppBrowser from 'react-native-inappbrowser-reborn';
816
+ *
817
+ * setPafiWebModalAdapter({
818
+ * async open(url, options) {
819
+ * const result = await InAppBrowser.open(url, {
820
+ * // iOS: SFSafariViewController
821
+ * dismissButtonStyle: 'close',
822
+ * preferredBarTintColor: '#1a1a1a',
823
+ * preferredControlTintColor: 'white',
824
+ * // Android: Chrome Custom Tab
825
+ * toolbarColor: '#1a1a1a',
826
+ * secondaryToolbarColor: 'black',
827
+ * });
828
+ * options?.onClose?.();
829
+ * return {
830
+ * isOpen: false,
831
+ * close: () => InAppBrowser.close(),
832
+ * focus: () => {},
833
+ * postMessage: () => {},
834
+ * };
835
+ * },
836
+ * });
837
+ * ```
838
+ *
839
+ * ## Expo adapter example
840
+ *
841
+ * ```ts
842
+ * import * as WebBrowser from 'expo-web-browser';
843
+ *
844
+ * setPafiWebModalAdapter({
845
+ * async open(url, options) {
846
+ * await WebBrowser.openBrowserAsync(url);
847
+ * options?.onClose?.();
848
+ * return { isOpen: false, close: WebBrowser.dismissBrowser, focus: () => {}, postMessage: () => {} };
849
+ * },
850
+ * });
851
+ * ```
852
+ */
853
+ interface PafiWebModalAdapter {
854
+ open(url: string, options?: ModalOpenOptions): PafiWebModalHandle | Promise<PafiWebModalHandle>;
855
+ }
856
+
857
+ /**
858
+ * Web browser popup adapter. Opens the given URL in a centered
859
+ * `window.open()` popup, polls for close, and optionally forwards
860
+ * `postMessage` events back to the caller.
861
+ *
862
+ * Runtime requirement: `window.open` must exist. Throws if called
863
+ * under Node / SSR / React Native — use `setPafiWebModalAdapter()` to
864
+ * provide a platform-specific adapter in those environments.
865
+ *
866
+ * ## Popup blocking
867
+ *
868
+ * Browsers block `window.open()` unless it happens inside a user
869
+ * gesture (click handler). Callers MUST wire this into a direct click
870
+ * handler — wrapping it in a `setTimeout` or async await before the
871
+ * open call will trigger the blocker.
872
+ */
873
+ declare function openWebPopup(url: string, options?: ModalOpenOptions): PafiWebModalHandle;
874
+ /**
875
+ * The web popup packaged as a {@link PafiWebModalAdapter} so callers
876
+ * can register it explicitly (e.g. in a test harness).
877
+ */
878
+ declare const webPopupAdapter: PafiWebModalAdapter;
879
+
880
+ /**
881
+ * Register the adapter used by `openPafiWebModal()`. Typically called
882
+ * once during app initialization — mobile apps register a
883
+ * SFSafariViewController / Chrome Custom Tabs adapter, desktop apps
884
+ * can leave it unset (web popup is the default).
885
+ *
886
+ * Pass `null` to unregister and fall back to the default.
887
+ */
888
+ declare function setPafiWebModalAdapter(adapter: PafiWebModalAdapter | null): void;
889
+ /**
890
+ * Return the currently registered adapter, or `null` when none is set.
891
+ * Useful for tests that want to snapshot-and-restore the adapter.
892
+ */
893
+ declare function getPafiWebModalAdapter(): PafiWebModalAdapter | null;
894
+ /**
895
+ * Open PAFI Web in the host platform's appropriate UX:
896
+ *
897
+ * - Browser (window.open): centered popup, 900×700 by default
898
+ * - React Native (with adapter registered): SFSafariViewController
899
+ * / Chrome Custom Tabs via `react-native-inappbrowser-reborn` or
900
+ * `expo-web-browser`
901
+ * - Desktop (with adapter registered): custom BrowserWindow / new tab
902
+ *
903
+ * Resolution order:
904
+ * 1. If an adapter was registered via `setPafiWebModalAdapter()`, use it.
905
+ * 2. Else if `window.open` is available, use the built-in web popup.
906
+ * 3. Else throw with a clear error pointing at the adapter registry.
907
+ *
908
+ * @example
909
+ * ```ts
910
+ * // User clicks "Trade on PAFI" button
911
+ * button.addEventListener('click', async () => {
912
+ * const modal = await openPafiWebModal('https://app.pacificfinance.org', {
913
+ * allowedOrigins: ['https://app.pacificfinance.org'],
914
+ * onMessage: (data, origin) => {
915
+ * if (typeof data === 'object' && data && 'txHash' in data) {
916
+ * console.log('Swap confirmed:', data.txHash);
917
+ * modal.close();
918
+ * }
919
+ * },
920
+ * onClose: () => {
921
+ * console.log('User closed modal');
922
+ * },
923
+ * });
924
+ * });
925
+ * ```
926
+ */
927
+ declare function openPafiWebModal(url: string, options?: ModalOpenOptions): Promise<PafiWebModalHandle>;
928
+
815
929
  declare class PafiSDK {
816
930
  private _pointTokenAddress?;
817
931
  private _relayContractAddress?;
@@ -974,4 +1088,4 @@ declare class PafiSDK {
974
1088
  signLoginMessage(message: string): Promise<Hex>;
975
1089
  }
976
1090
 
977
- export { ApiError, BATCH_EXECUTOR_ABI, MOCK_BATCH_EXECUTOR_ADDRESS_BASE_MAINNET as BATCH_EXECUTOR_ADDRESS_BASE_MAINNET, MOCK_BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA as BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA, MOCK_BURN_CONSENT_TYPES as BURN_CONSENT_TYPES, BestQuote, type BuildPartialUserOpParams, type MockBurnConsent as BurnConsent, COMMON_POOLS, COMMON_TOKENS, MOCK_ADDRESSES as CONTRACT_ADDRESSES, ChainConfig, type CheckEthAndBranchParams, ConfigurationError, type ContractAddresses, EIP712Signature, ENTRY_POINT_V07, LoginMessageParams, MOCK_MINT_REQUEST_V2_TYPES as MINT_REQUEST_V2_TYPES, MintParams, MintRequest, type MockMintRequestV2 as MintRequestV2, type Operation, POINT_TOKEN_POOLS, MOCK_POINT_TOKEN_V2_ABI as POINT_TOKEN_V2_ABI, PafiSDK, PafiSDKConfig, PafiSDKError, type PartialUserOperation, PathKey, type PaymasterConfig, type PaymasterFields, PointTokenDomainConfig, PoolKey, QuoteResult, MOCK_RELAYER_V2_ABI as RELAYER_V2_ABI, MOCK_RELAYER_V2_MINT_SELECTOR as RELAYER_V2_MINT_SELECTOR, ReceiverConsent, SUPPORTED_CHAINS, type MockSignatureStruct as SignatureStruct, SignatureVerification, SigningError, SimulationError, SimulationResult, type SponsorshipScenario, type SubmissionPath, SwapParams, SwapSimulationResult, UNIVERSAL_ROUTER_ADDRESSES, type UserOpReceipt, type UserOperation, V4_QUOTER_ADDRESSES, ZERO_VALUE, _resetPaymasterConfigForTests, assembleUserOperation, buildMockBurnConsentTypedData as buildBurnConsentTypedData, buildMockMintRequestV2TypedData as buildMintRequestV2TypedData, buildPartialUserOperation, checkEthAndBranch, encodeBatchExecute, erc20ApproveOp, erc20BurnOp, erc20TransferOp, getMockAddresses as getContractAddresses, getPaymasterConfig, isPaymasterConfigured, mintRequestTypes, rawCallOp, receiverConsentTypes, setPaymasterConfig, signMockBurnConsent as signBurnConsent, signMockMintRequestV2 as signMintRequestV2, verifyMockBurnConsent as verifyBurnConsent, verifyMockMintRequestV2 as verifyMintRequestV2 };
1091
+ export { ApiError, BATCH_EXECUTOR_ABI, MOCK_BATCH_EXECUTOR_ADDRESS_BASE_MAINNET as BATCH_EXECUTOR_ADDRESS_BASE_MAINNET, MOCK_BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA as BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA, MOCK_BURN_CONSENT_TYPES as BURN_CONSENT_TYPES, BestQuote, type BuildPartialUserOpParams, type MockBurnConsent as BurnConsent, COMMON_POOLS, COMMON_TOKENS, MOCK_ADDRESSES as CONTRACT_ADDRESSES, ChainConfig, type CheckEthAndBranchParams, ConfigurationError, type ContractAddresses, EIP712Signature, LoginMessageParams, MOCK_MINT_REQUEST_V2_TYPES as MINT_REQUEST_V2_TYPES, MintParams, MintRequest, type MockMintRequestV2 as MintRequestV2, type ModalOpenOptions, Operation, POINT_TOKEN_POOLS, MOCK_POINT_TOKEN_V2_ABI as POINT_TOKEN_V2_ABI, PafiSDK, PafiSDKConfig, PafiSDKError, type PafiWebModalAdapter, type PafiWebModalHandle, PartialUserOperation, PathKey, type PaymasterConfig, PointTokenDomainConfig, PoolKey, QuoteResult, MOCK_RELAYER_V2_ABI as RELAYER_V2_ABI, MOCK_RELAYER_V2_MINT_SELECTOR as RELAYER_V2_MINT_SELECTOR, ReceiverConsent, SUPPORTED_CHAINS, type MockSignatureStruct as SignatureStruct, SignatureVerification, SigningError, SimulationError, SimulationResult, type SponsorshipScenario, type SubmissionPath, SwapParams, SwapSimulationResult, UNIVERSAL_ROUTER_ADDRESSES, UserOperation, V4_QUOTER_ADDRESSES, _resetPaymasterConfigForTests, assembleUserOperation, buildMockBurnConsentTypedData as buildBurnConsentTypedData, buildMockMintRequestV2TypedData as buildMintRequestV2TypedData, buildPartialUserOperation, checkEthAndBranch, encodeBatchExecute, erc20ApproveOp, erc20BurnOp, erc20TransferOp, getMockAddresses as getContractAddresses, getPafiWebModalAdapter, getPaymasterConfig, isPaymasterConfigured, mintRequestTypes, openPafiWebModal, openWebPopup, rawCallOp, receiverConsentTypes, setPafiWebModalAdapter, setPaymasterConfig, signMockBurnConsent as signBurnConsent, signMockMintRequestV2 as signMintRequestV2, verifyMockBurnConsent as verifyBurnConsent, verifyMockMintRequestV2 as verifyMintRequestV2, webPopupAdapter };