@moon-x/react-sdk 0.1.0 → 0.3.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 CHANGED
@@ -89,7 +89,7 @@ function SignDemo() {
89
89
  | `solana.rpcs` | `{ [cluster]: { rpc, rpcSubscriptions? } }` | Solana RPC endpoints per cluster. |
90
90
  | `walletConnect.projectId` | `string` | WalletConnect v2 project ID for external-wallet flows. |
91
91
  | `emailConfig`, `passkeyEnrollConfig`, `signMessageConfig`, `signTransactionConfig`, `sendTransactionConfig`, `exportKeyConfig` | various | Per-flow UI overrides — titles, button text, etc. |
92
- | `security.assertionCacheTtlMs` | `number` | Parent-side passkey-assertion cache TTL in milliseconds. **Defaults to `0` (no cache — every sensitive op forces a fresh biometric).** Set to a positive value (e.g. `5 * 60 * 1000`) to opt into a warm window where routine ops skip the OS picker. See [Security: assertion cache + `requireFreshAssertion`](#security-assertion-cache--requirefreshassertion) below for the trade-off. |
92
+ | `security` | `Record<string, never>` | Reserved for future per-app security knobs. The previously-configurable `assertionCacheTtlMs` was removed in Phase 4 of the presence-token gating work — every sensitive op now does a fresh WebAuthn ceremony and mints scope-bound single-use JWTs via the iframe's internal orchestrator, so there is no parent-side cache left to configure. See [Security](#security) below. |
93
93
  | `theme` | `MoonKeyThemeConfig` | Low-level token overrides — fine-grained color palette, full borderRadius scale. Most apps don't need this; `appearance` is the recommended surface. |
94
94
 
95
95
  ## Hooks
@@ -149,38 +149,20 @@ import { useSignMessage as useSignSolanaMessage } from "@moon-x/react-sdk/solana
149
149
 
150
150
  Every signing hook accepts `options.uiOptions.showWalletUI` to toggle modal vs headless mode. With UI, the user sees the message/transaction in a modal and the biometric prompt fires only on the Sign tap. Headless skips the modal entirely.
151
151
 
152
- Every signing hook also accepts a top-level `requireFreshAssertion?: boolean` flag. When `true`, that single call bypasses any parent-side assertion cache and forces a fresh biometric useful for high-value transactions in an otherwise-warm flow. See [Security](#security-assertion-cache--requirefreshassertion) below.
152
+ Every sensitive op now does a fresh WebAuthn ceremony per call the previous per-call `requireFreshAssertion?: boolean` flag was removed from the param types since it has no behavior left to opt into. See [Security](#security) below.
153
153
 
154
- ### Security: assertion cache + `requireFreshAssertion`
154
+ ### Security
155
155
 
156
- MoonX's parent-side assertion cache holds the WebAuthn assertion result (`userHandleB64url` the AES-GCM key that wraps the user's DEK) in JS memory for an integrator-configured TTL. Within that window, routine wallet ops skip the OS passkey picker.
156
+ Every sensitive operation (`signMessage`, `signTransaction`, `signTypedData`, `signHash`, `sign7702Authorization`, `sendTransaction`, `createWallet`, `importKey`, `exportKey`, `addPasskey`, `removePasskey`) drives this server-verified ceremony per call:
157
157
 
158
- **The default is `assertionCacheTtlMs: 0` no cache.** Every sensitive op fires a fresh biometric and the raw userHandle never lingers in the parent JS heap past the moment of use. This is the safe posture: a parent-page XSS can't lift a cached key because there is no cache.
158
+ 1. **Server-issued challenge.** SDK posts to `/auth/passkey/presence/begin`, server inserts a row in `app_user_passkey_challenges` and returns the WebAuthn options.
159
+ 2. **Fresh WebAuthn assertion.** The parent runs `navigator.credentials.get`; the user does a biometric. The assertor strips `response.userHandle` from the server-bound payload (DEK hygiene) and surfaces the userHandle separately for the iframe's local AES-GCM unwrap.
160
+ 3. **Scope-bound, single-use JWT mint.** SDK posts to `/auth/passkey/presence/verify` with `purpose: "internal"` and the scope set this op needs (e.g. `["keyshare_read", "sign"]`). Server consumes the challenge, verifies the signature against the credential's stored public key, mints one short-lived JWT per scope with a unique `jti`.
161
+ 4. **Per-endpoint enforcement.** Each scoped JWT carries the `X-MoonX-Presence` header on its matching gated endpoint. MoonX middleware pins the JWT's `op` claim to the endpoint, then burns the `jti` in `platform.app_presence_jti_used` via `INSERT ... ON CONFLICT DO NOTHING`. Replay of the same token is rejected as `presence token already consumed`. Tokens have a 30-second TTL.
159
162
 
160
- Integrators who want a warm-UX trade-off opt back in:
163
+ What this closes: **captured userHandle + session JWT no longer unlocks DEK material offline.** Even with both, an attacker can't fetch wraps / keyshares / drive the co-signer without producing a fresh WebAuthn signature for each op — which requires the credential's private key in the user's authenticator. See `apps/platform/docs/notes/passkeys/presence-tokens.md` (in the backend repo) for the full threat model and scope matrix.
161
164
 
162
- ```tsx
163
- <MoonKeyProvider
164
- publishableKey={pk}
165
- config={{ security: { assertionCacheTtlMs: 5 * 60 * 1000 } }}
166
- >
167
- ...
168
- </MoonKeyProvider>
169
- ```
170
-
171
- With the cache on, parent-coresident JS (including XSS) can drive cached ops without re-prompting for the duration of the window. The TTL bounds the exposure but doesn't eliminate it. Pick the trade-off deliberately.
172
-
173
- Per-call escape hatch — works regardless of the global setting:
174
-
175
- ```tsx
176
- await signTransaction({
177
- transaction: tx,
178
- wallet,
179
- requireFreshAssertion: true, // force a fresh biometric for THIS op
180
- });
181
- ```
182
-
183
- Sensitive lifecycle ops (`exportKey`, `addPasskey`, `removePasskey`) ignore the cache unconditionally — they always re-prompt.
165
+ The previously-configurable `security.assertionCacheTtlMs` and per-call `requireFreshAssertion` were removed entirely when presence-token gating shipped — they no longer exist on the public TypeScript surface. Every op is always-fresh by construction.
184
166
 
185
167
  ### Theming
186
168
 
@@ -238,4 +220,4 @@ For React Native apps, use [`@moon-x/react-native-sdk`](https://www.npmjs.com/pa
238
220
 
239
221
  ## License
240
222
 
241
- MIT.
223
+ UNLICENSED. All rights reserved.
@@ -690,7 +690,6 @@ var useSendTransaction = function useSendTransaction() {
690
690
  transaction: transactionString,
691
691
  wallet: params.wallet,
692
692
  rpcUrl: rpcUrl,
693
- requireFreshAssertion: params.requireFreshAssertion,
694
693
  options: _object_spread_props(_object_spread({}, params.options), {
695
694
  wsEndpoint: wsEndpoint
696
695
  })
@@ -450,7 +450,6 @@ var useSendTransaction = function useSendTransaction() {
450
450
  transaction: transactionString,
451
451
  wallet: params.wallet,
452
452
  rpcUrl: rpcUrl,
453
- requireFreshAssertion: params.requireFreshAssertion,
454
453
  options: _object_spread_props(_object_spread({}, params.options), {
455
454
  wsEndpoint: wsEndpoint
456
455
  })
@@ -1126,7 +1126,7 @@ var useSignTransaction = function useSignTransaction() {
1126
1126
  var shared = useSharedEthSignTransaction();
1127
1127
  return {
1128
1128
  signTransaction: function signTransaction(param) {
1129
- var transaction = param.transaction, wallet = param.wallet, requireFreshAssertion = param.requireFreshAssertion, options = param.options;
1129
+ var transaction = param.transaction, wallet = param.wallet, options = param.options;
1130
1130
  return _async_to_generator(function() {
1131
1131
  var _coreSDK_config_ethereum, _coreSDK_config, _coreSDK_config_ethereum1, _coreSDK_config1, _coreSDK_config_signTransactionConfig, _coreSDK_config2, serializedTransaction, showWalletUI, error;
1132
1132
  return _ts_generator(this, function(_state) {
@@ -1159,7 +1159,6 @@ var useSignTransaction = function useSignTransaction() {
1159
1159
  params: {
1160
1160
  transaction: serializedTransaction,
1161
1161
  wallet: stripWalletMethods(wallet),
1162
- requireFreshAssertion: requireFreshAssertion,
1163
1162
  options: {
1164
1163
  uiOptions: options === null || options === void 0 ? void 0 : options.uiOptions
1165
1164
  }
@@ -1286,7 +1285,7 @@ var useSign7702Authorization = function useSign7702Authorization() {
1286
1285
  var coreSDK = useAuthSDK();
1287
1286
  return {
1288
1287
  signAuthorization: function signAuthorization(param) {
1289
- var contractAddress = param.contractAddress, nonce = param.nonce, executor = param.executor, wallet = param.wallet, requireFreshAssertion = param.requireFreshAssertion, options = param.options;
1288
+ var contractAddress = param.contractAddress, nonce = param.nonce, executor = param.executor, wallet = param.wallet, options = param.options;
1290
1289
  return _async_to_generator(function() {
1291
1290
  var _coreSDK_config_ethereum, _coreSDK_config, walletChainId, targetChain, _coreSDK_config_ethereum1, _coreSDK_config1, derivedChainId, _coreSDK_config_signMessageConfig, _coreSDK_config2, showWalletUI, error;
1292
1291
  return _ts_generator(this, function(_state) {
@@ -1322,7 +1321,6 @@ var useSign7702Authorization = function useSign7702Authorization() {
1322
1321
  nonce: nonce,
1323
1322
  executor: executor,
1324
1323
  wallet: stripWalletMethods(wallet),
1325
- requireFreshAssertion: requireFreshAssertion,
1326
1324
  options: {
1327
1325
  uiOptions: options === null || options === void 0 ? void 0 : options.uiOptions
1328
1326
  }
@@ -1357,7 +1355,7 @@ var useSendTransaction = function useSendTransaction() {
1357
1355
  var shared = useSharedEthSendTransaction();
1358
1356
  return {
1359
1357
  sendTransaction: function sendTransaction(param) {
1360
- var transaction = param.transaction, wallet = param.wallet, requireFreshAssertion = param.requireFreshAssertion, options = param.options;
1358
+ var transaction = param.transaction, wallet = param.wallet, options = param.options;
1361
1359
  return _async_to_generator(function() {
1362
1360
  var _coreSDK_config_ethereum, _coreSDK_config, _coreSDK_config_ethereum1, _coreSDK_config1, _coreSDK_config_signMessageConfig, _coreSDK_config2, _ref, preparedTx, rpcUrl, showWalletUI, response, error;
1363
1361
  return _ts_generator(this, function(_state) {
@@ -1391,7 +1389,6 @@ var useSendTransaction = function useSendTransaction() {
1391
1389
  transaction: preparedTx,
1392
1390
  wallet: stripWalletMethods(wallet),
1393
1391
  rpcUrl: rpcUrl,
1394
- requireFreshAssertion: requireFreshAssertion,
1395
1392
  options: {
1396
1393
  uiOptions: options === null || options === void 0 ? void 0 : options.uiOptions
1397
1394
  }
@@ -1321,7 +1321,7 @@ var useSignTransaction = function useSignTransaction() {
1321
1321
  var shared = _ethereum.useSignTransaction.call(void 0);
1322
1322
  return {
1323
1323
  signTransaction: function signTransaction(param) {
1324
- var transaction = param.transaction, wallet = param.wallet, requireFreshAssertion = param.requireFreshAssertion, options = param.options;
1324
+ var transaction = param.transaction, wallet = param.wallet, options = param.options;
1325
1325
  return _async_to_generator(function() {
1326
1326
  var serializedTransaction, showWalletUI, error;
1327
1327
  return _ts_generator(this, function(_state) {
@@ -1402,7 +1402,6 @@ var useSignTransaction = function useSignTransaction() {
1402
1402
  params: {
1403
1403
  transaction: serializedTransaction,
1404
1404
  wallet: stripWalletMethods(wallet),
1405
- requireFreshAssertion: requireFreshAssertion,
1406
1405
  options: {
1407
1406
  uiOptions: _optionalChain([
1408
1407
  options,
@@ -1559,7 +1558,7 @@ var useSign7702Authorization = function useSign7702Authorization() {
1559
1558
  var coreSDK = _chunkSPXMMQ7Zjs.useAuthSDK.call(void 0);
1560
1559
  return {
1561
1560
  signAuthorization: function signAuthorization(param) {
1562
- var contractAddress = param.contractAddress, nonce = param.nonce, executor = param.executor, wallet = param.wallet, requireFreshAssertion = param.requireFreshAssertion, options = param.options;
1561
+ var contractAddress = param.contractAddress, nonce = param.nonce, executor = param.executor, wallet = param.wallet, options = param.options;
1563
1562
  return _async_to_generator(function() {
1564
1563
  var walletChainId, targetChain, derivedChainId, showWalletUI, error;
1565
1564
  return _ts_generator(this, function(_state) {
@@ -1642,7 +1641,6 @@ var useSign7702Authorization = function useSign7702Authorization() {
1642
1641
  nonce: nonce,
1643
1642
  executor: executor,
1644
1643
  wallet: stripWalletMethods(wallet),
1645
- requireFreshAssertion: requireFreshAssertion,
1646
1644
  options: {
1647
1645
  uiOptions: _optionalChain([
1648
1646
  options,
@@ -1683,7 +1681,7 @@ var useSendTransaction = function useSendTransaction() {
1683
1681
  var shared = _ethereum.useSendTransaction.call(void 0);
1684
1682
  return {
1685
1683
  sendTransaction: function sendTransaction(param) {
1686
- var transaction = param.transaction, wallet = param.wallet, requireFreshAssertion = param.requireFreshAssertion, options = param.options;
1684
+ var transaction = param.transaction, wallet = param.wallet, options = param.options;
1687
1685
  return _async_to_generator(function() {
1688
1686
  var _ref, preparedTx, rpcUrl, showWalletUI, response, error;
1689
1687
  return _ts_generator(this, function(_state) {
@@ -1765,7 +1763,6 @@ var useSendTransaction = function useSendTransaction() {
1765
1763
  transaction: preparedTx,
1766
1764
  wallet: stripWalletMethods(wallet),
1767
1765
  rpcUrl: rpcUrl,
1768
- requireFreshAssertion: requireFreshAssertion,
1769
1766
  options: {
1770
1767
  uiOptions: _optionalChain([
1771
1768
  options,
@@ -155,7 +155,6 @@ declare const useSignMessage: () => {
155
155
  signMessage: (params: {
156
156
  message: string;
157
157
  wallet: PublicWallet;
158
- requireFreshAssertion?: boolean;
159
158
  options?: {
160
159
  uiOptions?: SignMessageUIOptions;
161
160
  };
@@ -166,10 +165,9 @@ declare const useSignMessage: () => {
166
165
  error: undefined;
167
166
  };
168
167
  declare const useSignTransaction: () => {
169
- signTransaction: ({ transaction, wallet, requireFreshAssertion, options, }: {
168
+ signTransaction: ({ transaction, wallet, options, }: {
170
169
  transaction: string | object;
171
170
  wallet: PublicWallet;
172
- requireFreshAssertion?: boolean;
173
171
  options?: {
174
172
  uiOptions?: SignTransactionUIOptions;
175
173
  };
@@ -185,7 +183,6 @@ declare const useSignHash: () => {
185
183
  signHash: (params: {
186
184
  hash: `0x${string}` | string;
187
185
  wallet: PublicWallet;
188
- requireFreshAssertion?: boolean;
189
186
  options?: {
190
187
  uiOptions?: any;
191
188
  };
@@ -202,7 +199,6 @@ declare const useSignTypedData: () => {
202
199
  primaryType: string;
203
200
  message: any;
204
201
  wallet: PublicWallet;
205
- requireFreshAssertion?: boolean;
206
202
  options?: {
207
203
  uiOptions?: any;
208
204
  };
@@ -213,12 +209,11 @@ declare const useSignTypedData: () => {
213
209
  error: undefined;
214
210
  };
215
211
  declare const useSign7702Authorization: () => {
216
- signAuthorization: ({ contractAddress, nonce, executor, wallet, requireFreshAssertion, options, }: {
212
+ signAuthorization: ({ contractAddress, nonce, executor, wallet, options, }: {
217
213
  contractAddress: `0x${string}`;
218
214
  nonce?: number;
219
215
  executor?: "self" | `0x${string}`;
220
216
  wallet: PublicWallet | PublicEthereumWallet;
221
- requireFreshAssertion?: boolean;
222
217
  options?: {
223
218
  uiOptions?: any;
224
219
  };
@@ -235,7 +230,7 @@ declare const useSign7702Authorization: () => {
235
230
  error: undefined;
236
231
  };
237
232
  declare const useSendTransaction: () => {
238
- sendTransaction: ({ transaction, wallet, requireFreshAssertion, options, }: {
233
+ sendTransaction: ({ transaction, wallet, options, }: {
239
234
  transaction: {
240
235
  to?: string;
241
236
  value?: string | number | bigint;
@@ -249,7 +244,6 @@ declare const useSendTransaction: () => {
249
244
  maxFeePerGas?: string | number | bigint;
250
245
  };
251
246
  wallet: PublicWallet | PublicEthereumWallet;
252
- requireFreshAssertion?: boolean;
253
247
  options?: {
254
248
  uiOptions?: any;
255
249
  };
@@ -155,7 +155,6 @@ declare const useSignMessage: () => {
155
155
  signMessage: (params: {
156
156
  message: string;
157
157
  wallet: PublicWallet;
158
- requireFreshAssertion?: boolean;
159
158
  options?: {
160
159
  uiOptions?: SignMessageUIOptions;
161
160
  };
@@ -166,10 +165,9 @@ declare const useSignMessage: () => {
166
165
  error: undefined;
167
166
  };
168
167
  declare const useSignTransaction: () => {
169
- signTransaction: ({ transaction, wallet, requireFreshAssertion, options, }: {
168
+ signTransaction: ({ transaction, wallet, options, }: {
170
169
  transaction: string | object;
171
170
  wallet: PublicWallet;
172
- requireFreshAssertion?: boolean;
173
171
  options?: {
174
172
  uiOptions?: SignTransactionUIOptions;
175
173
  };
@@ -185,7 +183,6 @@ declare const useSignHash: () => {
185
183
  signHash: (params: {
186
184
  hash: `0x${string}` | string;
187
185
  wallet: PublicWallet;
188
- requireFreshAssertion?: boolean;
189
186
  options?: {
190
187
  uiOptions?: any;
191
188
  };
@@ -202,7 +199,6 @@ declare const useSignTypedData: () => {
202
199
  primaryType: string;
203
200
  message: any;
204
201
  wallet: PublicWallet;
205
- requireFreshAssertion?: boolean;
206
202
  options?: {
207
203
  uiOptions?: any;
208
204
  };
@@ -213,12 +209,11 @@ declare const useSignTypedData: () => {
213
209
  error: undefined;
214
210
  };
215
211
  declare const useSign7702Authorization: () => {
216
- signAuthorization: ({ contractAddress, nonce, executor, wallet, requireFreshAssertion, options, }: {
212
+ signAuthorization: ({ contractAddress, nonce, executor, wallet, options, }: {
217
213
  contractAddress: `0x${string}`;
218
214
  nonce?: number;
219
215
  executor?: "self" | `0x${string}`;
220
216
  wallet: PublicWallet | PublicEthereumWallet;
221
- requireFreshAssertion?: boolean;
222
217
  options?: {
223
218
  uiOptions?: any;
224
219
  };
@@ -235,7 +230,7 @@ declare const useSign7702Authorization: () => {
235
230
  error: undefined;
236
231
  };
237
232
  declare const useSendTransaction: () => {
238
- sendTransaction: ({ transaction, wallet, requireFreshAssertion, options, }: {
233
+ sendTransaction: ({ transaction, wallet, options, }: {
239
234
  transaction: {
240
235
  to?: string;
241
236
  value?: string | number | bigint;
@@ -249,7 +244,6 @@ declare const useSendTransaction: () => {
249
244
  maxFeePerGas?: string | number | bigint;
250
245
  };
251
246
  wallet: PublicWallet | PublicEthereumWallet;
252
- requireFreshAssertion?: boolean;
253
247
  options?: {
254
248
  uiOptions?: any;
255
249
  };
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
  export { LoginWithEmailState, PasskeyStatusEntry, RegisterPasskeyResult, UseAddPasskeyResult, UseLoginWithEmailCallbacks, UsePasskeyStatusResult, UseRemovePasskeyResult, useAddPasskey, useLoginWithEmail, usePasskeyStatus, useRegisterPasskey, useRemovePasskey, useUser } from '@moon-x/core/react';
2
- import { WalletListEntry, AuthAppearance, PrefillConfig, WalletChainType, MoonKeyThemeConfig, PasskeyEnrollConfig, SignMessageConfig, ExportKeyConfig, SignTransactionConfig, SendTransactionConfig, Chain, LogoutResponse, EmailOtpFlowState, Wallet } from '@moon-x/core/types';
2
+ import { WalletListEntry, AuthAppearance, PrefillConfig, WalletChainType, MoonKeyThemeConfig, PasskeyEnrollConfig, SignMessageConfig, ExportKeyConfig, SignTransactionConfig, SendTransactionConfig, Chain, LogoutResponse, EmailOtpFlowState, SendEmailOtpResponse, Wallet } from '@moon-x/core/types';
3
3
  export { Chain, Factor, IdpProvider, Network, PublicEthereumWallet, PublicWallet, WalletConnectConfig, WalletListEntry } from '@moon-x/core/types';
4
4
  import React$1, { ReactNode } from 'react';
5
- export { e as ethereum } from './ethereum-DobH9IQl.mjs';
6
- export { s as solana } from './solana-CzXRbze_.mjs';
5
+ export { e as ethereum } from './ethereum-CGSlkQOw.mjs';
6
+ export { s as solana } from './solana-Cr7r3wi8.mjs';
7
7
  export { estimateEvmGas, estimateEvmGasReserve, getChainById, getDefaultChain, getEvmGasPrice, getEvmMaxPriorityFeePerGas, getEvmNonce, getRpcUrl, isChainSupported, setChainRpcUrl, validateChainConfig } from '@moon-x/core/lib';
8
8
  export { arbitrum, arbitrumSepolia, avalanche, avalancheFuji, base, baseSepolia, bsc, bscTestnet, goerli, holesky, mainnet, optimism, optimismSepolia, polygon, polygonAmoy, sepolia } from 'viem/chains';
9
9
  import './base-wallet-CzJLpndu.mjs';
@@ -120,37 +120,20 @@ interface MoonKeyConfig {
120
120
  appearance?: AuthAppearance;
121
121
  loginMethods?: ("email" | "google" | "apple" | "wallet")[];
122
122
  /**
123
- * Security-policy knobs. Safe defaults (the entire `security` object
124
- * can be omitted for the strictest posture).
123
+ * Reserved for future per-app security knobs. Currently has no
124
+ * fields the previously-configurable `assertionCacheTtlMs` was
125
+ * removed when presence-token gating shipped. Every sensitive op
126
+ * now drives a fresh WebAuthn ceremony via the internal orchestrator,
127
+ * so there is nothing left to configure here today. Future knobs
128
+ * (e.g. presence-token TTL overrides) would slot in here.
125
129
  */
126
- security?: {
127
- /**
128
- * TTL in milliseconds for the parent-side passkey assertion cache.
129
- *
130
- * Default: 0 (no cache — every sensitive op forces a fresh
131
- * biometric prompt). This is the safe-by-default posture; the raw
132
- * userHandle (the AES-GCM KEK that unwraps the user's DEK) never
133
- * lingers in the parent JS heap past the moment of use.
134
- *
135
- * Set to a positive number (e.g. 5 * 60 * 1000) only if the
136
- * integrating app has a UX that genuinely benefits from skipping
137
- * the OS passkey prompt on routine ops within a window. The
138
- * trade-off: during the warm window, parent-coresident JS that
139
- * can reach the SDK can drive wallet ops without re-prompting.
140
- *
141
- * Sensitive operations (export, addPasskey, removePasskey, and
142
- * any call passing `requireFreshAssertion: true`) bypass the
143
- * cache regardless of this setting.
144
- */
145
- assertionCacheTtlMs?: number;
146
- };
130
+ security?: Record<string, never>;
147
131
  prefill?: PrefillConfig;
148
132
  walletChainType?: WalletChainType;
149
133
  isDark?: boolean;
150
134
  theme?: MoonKeyThemeConfig;
151
135
  emailConfig?: {
152
136
  skipVerifiedSuccess?: boolean;
153
- expiresIn?: number;
154
137
  verifiedDisplayTime?: number;
155
138
  verifyEmailTitle?: string;
156
139
  verifyEmailResendTitle?: string;
@@ -212,6 +195,29 @@ interface MoonKeyInstance {
212
195
  refreshToken: string;
213
196
  expiresAt: number;
214
197
  } | null>;
198
+ /**
199
+ * Run a passkey-asserted step-up ceremony and return a short-lived
200
+ * presence token. The token (JWT, `tt:"presence"`) is signed with
201
+ * the app's JWKS key and intended to be passed to your backend in a
202
+ * header (e.g. `X-MoonX-Presence`) on high-risk routes. Your backend
203
+ * verifies it via `@moon-x/node-sdk`'s
204
+ * `client.auth.verifyPresenceToken(token)`.
205
+ *
206
+ * Must be invoked synchronously from a click handler — WebAuthn
207
+ * requires transient activation. Throws if the user has no
208
+ * enrolled passkey or cancels the prompt.
209
+ *
210
+ * @example
211
+ * const { presenceToken } = await getPresenceToken();
212
+ * await fetch('/api/sensitive', {
213
+ * method: 'POST',
214
+ * headers: { 'X-MoonX-Presence': presenceToken },
215
+ * });
216
+ */
217
+ getPresenceToken: () => Promise<{
218
+ presenceToken: string;
219
+ expiresAt: number;
220
+ }>;
215
221
  /**
216
222
  * Start authentication flow (UI-based)
217
223
  * @param params - Optional configuration to override provider-level config
@@ -241,10 +247,15 @@ interface MoonKeyInstance {
241
247
  */
242
248
  setAppearance: (appearance: AuthAppearance) => void;
243
249
  publishableKey: string;
250
+ /**
251
+ * Send the OTP. Returns the platform response — including the
252
+ * authoritative `expires_at` (unix seconds) so headless consumers
253
+ * can render an accurate countdown without inventing their own TTL.
254
+ */
244
255
  sendCode: (params: {
245
256
  email: string;
246
257
  disableSignup?: boolean;
247
- }) => Promise<void>;
258
+ }) => Promise<SendEmailOtpResponse>;
248
259
  loginWithCode: (params: {
249
260
  code: string;
250
261
  }) => Promise<void>;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  export { LoginWithEmailState, PasskeyStatusEntry, RegisterPasskeyResult, UseAddPasskeyResult, UseLoginWithEmailCallbacks, UsePasskeyStatusResult, UseRemovePasskeyResult, useAddPasskey, useLoginWithEmail, usePasskeyStatus, useRegisterPasskey, useRemovePasskey, useUser } from '@moon-x/core/react';
2
- import { WalletListEntry, AuthAppearance, PrefillConfig, WalletChainType, MoonKeyThemeConfig, PasskeyEnrollConfig, SignMessageConfig, ExportKeyConfig, SignTransactionConfig, SendTransactionConfig, Chain, LogoutResponse, EmailOtpFlowState, Wallet } from '@moon-x/core/types';
2
+ import { WalletListEntry, AuthAppearance, PrefillConfig, WalletChainType, MoonKeyThemeConfig, PasskeyEnrollConfig, SignMessageConfig, ExportKeyConfig, SignTransactionConfig, SendTransactionConfig, Chain, LogoutResponse, EmailOtpFlowState, SendEmailOtpResponse, Wallet } from '@moon-x/core/types';
3
3
  export { Chain, Factor, IdpProvider, Network, PublicEthereumWallet, PublicWallet, WalletConnectConfig, WalletListEntry } from '@moon-x/core/types';
4
4
  import React$1, { ReactNode } from 'react';
5
- export { e as ethereum } from './ethereum-BRGKpUFH.js';
6
- export { s as solana } from './solana-D7BgQ4c0.js';
5
+ export { e as ethereum } from './ethereum-CWhbeptv.js';
6
+ export { s as solana } from './solana-nUvZo4Zp.js';
7
7
  export { estimateEvmGas, estimateEvmGasReserve, getChainById, getDefaultChain, getEvmGasPrice, getEvmMaxPriorityFeePerGas, getEvmNonce, getRpcUrl, isChainSupported, setChainRpcUrl, validateChainConfig } from '@moon-x/core/lib';
8
8
  export { arbitrum, arbitrumSepolia, avalanche, avalancheFuji, base, baseSepolia, bsc, bscTestnet, goerli, holesky, mainnet, optimism, optimismSepolia, polygon, polygonAmoy, sepolia } from 'viem/chains';
9
9
  import './base-wallet-CzJLpndu.js';
@@ -120,37 +120,20 @@ interface MoonKeyConfig {
120
120
  appearance?: AuthAppearance;
121
121
  loginMethods?: ("email" | "google" | "apple" | "wallet")[];
122
122
  /**
123
- * Security-policy knobs. Safe defaults (the entire `security` object
124
- * can be omitted for the strictest posture).
123
+ * Reserved for future per-app security knobs. Currently has no
124
+ * fields the previously-configurable `assertionCacheTtlMs` was
125
+ * removed when presence-token gating shipped. Every sensitive op
126
+ * now drives a fresh WebAuthn ceremony via the internal orchestrator,
127
+ * so there is nothing left to configure here today. Future knobs
128
+ * (e.g. presence-token TTL overrides) would slot in here.
125
129
  */
126
- security?: {
127
- /**
128
- * TTL in milliseconds for the parent-side passkey assertion cache.
129
- *
130
- * Default: 0 (no cache — every sensitive op forces a fresh
131
- * biometric prompt). This is the safe-by-default posture; the raw
132
- * userHandle (the AES-GCM KEK that unwraps the user's DEK) never
133
- * lingers in the parent JS heap past the moment of use.
134
- *
135
- * Set to a positive number (e.g. 5 * 60 * 1000) only if the
136
- * integrating app has a UX that genuinely benefits from skipping
137
- * the OS passkey prompt on routine ops within a window. The
138
- * trade-off: during the warm window, parent-coresident JS that
139
- * can reach the SDK can drive wallet ops without re-prompting.
140
- *
141
- * Sensitive operations (export, addPasskey, removePasskey, and
142
- * any call passing `requireFreshAssertion: true`) bypass the
143
- * cache regardless of this setting.
144
- */
145
- assertionCacheTtlMs?: number;
146
- };
130
+ security?: Record<string, never>;
147
131
  prefill?: PrefillConfig;
148
132
  walletChainType?: WalletChainType;
149
133
  isDark?: boolean;
150
134
  theme?: MoonKeyThemeConfig;
151
135
  emailConfig?: {
152
136
  skipVerifiedSuccess?: boolean;
153
- expiresIn?: number;
154
137
  verifiedDisplayTime?: number;
155
138
  verifyEmailTitle?: string;
156
139
  verifyEmailResendTitle?: string;
@@ -212,6 +195,29 @@ interface MoonKeyInstance {
212
195
  refreshToken: string;
213
196
  expiresAt: number;
214
197
  } | null>;
198
+ /**
199
+ * Run a passkey-asserted step-up ceremony and return a short-lived
200
+ * presence token. The token (JWT, `tt:"presence"`) is signed with
201
+ * the app's JWKS key and intended to be passed to your backend in a
202
+ * header (e.g. `X-MoonX-Presence`) on high-risk routes. Your backend
203
+ * verifies it via `@moon-x/node-sdk`'s
204
+ * `client.auth.verifyPresenceToken(token)`.
205
+ *
206
+ * Must be invoked synchronously from a click handler — WebAuthn
207
+ * requires transient activation. Throws if the user has no
208
+ * enrolled passkey or cancels the prompt.
209
+ *
210
+ * @example
211
+ * const { presenceToken } = await getPresenceToken();
212
+ * await fetch('/api/sensitive', {
213
+ * method: 'POST',
214
+ * headers: { 'X-MoonX-Presence': presenceToken },
215
+ * });
216
+ */
217
+ getPresenceToken: () => Promise<{
218
+ presenceToken: string;
219
+ expiresAt: number;
220
+ }>;
215
221
  /**
216
222
  * Start authentication flow (UI-based)
217
223
  * @param params - Optional configuration to override provider-level config
@@ -241,10 +247,15 @@ interface MoonKeyInstance {
241
247
  */
242
248
  setAppearance: (appearance: AuthAppearance) => void;
243
249
  publishableKey: string;
250
+ /**
251
+ * Send the OTP. Returns the platform response — including the
252
+ * authoritative `expires_at` (unix seconds) so headless consumers
253
+ * can render an accurate countdown without inventing their own TTL.
254
+ */
244
255
  sendCode: (params: {
245
256
  email: string;
246
257
  disableSignup?: boolean;
247
- }) => Promise<void>;
258
+ }) => Promise<SendEmailOtpResponse>;
248
259
  loginWithCode: (params: {
249
260
  code: string;
250
261
  }) => Promise<void>;