diff --git a/.nvmrc b/.nvmrc
index 60ade1ae..ce62013c 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-24.19.0
+24.22.1
diff --git a/README.md b/README.md
index ee3b7fdc..40336594 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
- ♻️ Universal solution (Apple Wallet and Google Wallet)
- 💳 Easy and secure addition of payment cards from your app directly
- 💰 Supports Visa, MasterCard, Amex and Discover payment cards
+- 🔐 UAPP (Unified Android Push Provisioning) support for enhanced security
- 🎉 Expo support (expo-plugin)
## Getting started
@@ -21,7 +22,7 @@ To be able to interact with the Google Wallet on the Android please make sure to
1. Visit [the Google Pay Android Push Provisioning API documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/) and request access to it.
2. Once getting an approval from the Google team
- 1. Download the [TapAndPay SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/releases).
+ 1. Download the [TapAndPay SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/releases). The library uses the UAPP APIs (`PaymentCredentialsGenerator`, `PushTokenizeResult`), so older SDK versions without them will not compile. Tested with 18.10.1.
2. Unzip it and extract the SDK into the `/android/libs` folder in your React Native project (if there is no `libs` folder, create one).
3. Add `/android/libs` to `.gitignore`.
@@ -134,7 +135,7 @@ In your `app.json` file, add the following configuration:
"@expensify/react-native-wallet",
{
enableApplePayProvisioning: true,
- googleTapAndPaySdkPath: "./libs/tapandpay-v18.7.0.zip", // path to the Google Tap & Pay SDK zip file
+ googleTapAndPaySdkPath: "./libs/tapandpay-v18.10.1.zip", // path to the Google Tap & Pay SDK zip file
},
],
]
@@ -157,6 +158,7 @@ Here you can find data elements used in the library, essential to work with Goog
### Android
- **Opaque Payment Card** (OPC) - a binary blob of information Google Pay receives from the issuer app that could be presented to TSP to receive a token.
+- **Google Opaque Payment Card** (Google OPC) - an encrypted version of the OPC required for UAPP (Unified Android Push Provisioning) flow. This is generated by your backend using Google's encryption keys during the provisioning process. [Learn more about UAPP →](./docs/UAPP.md)
- **Token Service Provider** (TSP) - a service that enhances payment security by replacing a credit card number during transactions with a unique digital identifier - token. The TSP specifies the tokenization service used to create a given token e.g. Visa, MasterCard, American Express.
- **Token Reference ID** - a unique identifying number to refer to a DPAN (Dynamic Personal Account Number). Token Providers will assign each DPAN an issuer token ID at the time of tokenization.
@@ -166,9 +168,11 @@ Here you can find data elements used in the library, essential to work with Goog
- **Certificates** - an array of NSData objects. Each object contains a DER encoded X.509 certificate, with the leaf first and root last. You must download the root CA to validate the entire chain.
- **Encrypted Pass Data**- an encrypted JSON file containing the sensitive information needed to add a card to Apple Pay (Base 64 encoded). [More details here.](https://developer.apple.com/documentation/passkit/pkaddpaymentpassrequest/encryptedpassdata)
- **Ephemeral Public Key** - a key used by elliptic curve cryptography (ECC) (Base 64 encoded).
+- **Primary Account Identifier** - an opaque issuer id (also called the FPAN ID) that PassKit uses to recognize the same card across reissues and devices. Pass it in `IOSCardData` and to `canAddCardToAppleWallet`. `getCardStatusByIdentifier` matches this value exactly and does not fall back. `addCardToAppleWallet`, the inferred `deviceType`, and `canAddCardToAppleWallet` when you also pass `lastDigits` share one lookup: an exact id match wins, and otherwise the library uses the id of the only pass that is not `deactivated` and has the same last digits. A different card that is still active and ends in the same digits can be picked. Pass the id PassKit stored on the pass (the `primaryAccountIdentifier` from `listAppleWalletPasses`) to skip that lookup.
+- **Device type** - the device the card is being provisioned to: `phone` or `watch`. PassKit does not report the device the user selected, so the library infers it from where the card is already provisioned. When it cannot tell, the value is `unknown`.
# API Reference
-The library offers seven functions for seamless integration and use of the Apple Wallet and Google Wallet APIs. Additionally, it includes one listener that informs when the added card has been activated. Below, these functions are described along with the data types involved.
+The library offers functions for seamless integration and use of the Apple Wallet and Google Wallet APIs. Additionally, it includes listeners and handlers for managing provisioning events. Below, these functions are described along with the data types involved.
## Functions
@@ -178,31 +182,61 @@ The library offers seven functions for seamless integration and use of the Apple
| **checkWalletAvailability** | Checks if the wallet is ready and initializes it if possible. | None | `boolean` | ✅ | ✅ |
| **getCardStatusBySuffix** | Retrieves the current status of a card in the wallet. | `lastDigits: string`
(The last few digits of the card number) | `CardStatus` | ✅ | ✅ |
| **getCardStatusByIdentifier** | Returns the state of a card based on a platform-specific identifier. On Android, it's `Token Reference ID` and on iOS, it's `Primary Account Identifier`. | `identifier: string`,
`tsp: string` | `CardStatus` | ✅ | ✅ |
-| **addCardToGoogleWallet** | Initiates native Push Provisioning flow for adding a card to the Google Wallet. | `data`: `AndroidCardData` | `TokenizationStatus` | ❌ | ✅ |
+| **hasEligibleTokenizationTarget** | Checks whether the card can still be added to a Google Wallet target (the phone or a paired wearable). Google recommends it for the "Add to Google Wallet" button when wearables are supported, because a card already on the phone can still be added to a watch. | `last4Digits: string`,
`network: string`,
`issuerName: string` | `boolean` | ❌ | ✅ |
+| **addCardToGoogleWallet** | Initiates native Push Provisioning flow for adding a card to the Google Wallet. Requires a handler that returns the payment credentials for the UAPP flow. [Learn more →](./docs/UAPP.md) | `data`: `AndroidCardData`,
`handlePaymentCredentials`: `(data: onPaymentCredentialsRequestPayload) => Promise` | `TokenizationStatus` | ❌ | ✅ |
| **resumeAddCardToGoogleWallet** | Resumes the Push Provisioning flow for adding a card to the Google Wallet using existing token reference ID. | `data`: `AndroidResumeCardData` | `TokenizationStatus` | ❌ | ✅ |
| **listTokens** | Lists all tokens currently stored in the Google Wallet. | None | `TokenInfo[]` | ❌ | ✅ |
-| **addCardToAppleWallet** | Initiates native Push Provisioning flow for adding a card to the Apple Wallet. | `data`: `IOSCardData`,
`issuerEncrypt-`
`PayloadCallback: IOSIssuerCallback` | `void` | ✅ | ❌ |
-
+| **listAppleWalletPasses** | Lists Apple Wallet Secure Element passes available to the app, including activation state and whether the pass is remote (for example on Apple Watch). Filter the result for `activationState === 'requireActivation'` or `activationState === 'pending'` to build a pending-cards UI. | None | `IOSWalletPass[]` | ✅ | ❌ |
+| **addCardToAppleWallet** | Initiates native Push Provisioning flow for adding a card to the Apple Wallet. When `IOSCardData.primaryAccountIdentifier` is set, the device picker only lists devices that do not already have the card. If PassKit cannot present the flow because the card is already on every device, the call fails with a clear error. | `data`: `IOSCardData`,
`issuerEncrypt-`
`PayloadCallback: IOSIssuerCallback` | `void` | ✅ | ❌ |
+| **canAddCardToAppleWallet** | Checks whether the card can still be added to the iPhone or a paired Apple Watch. Pass `lastDigits` to use the same id lookup as `addCardToAppleWallet`. Returns `false` on Android. | `primaryAccountIdentifier: string`,
`lastDigits?: string` | `boolean` | ✅ | ✅ |
+| **activateAppleWalletPass** | Activates an existing Secure Element pass in Apple Wallet using activation data from your issuer backend. Resolves `true` when the pass is already active. For `requireActivation`, returns Apple's result, which can be `false`. Rejects for any other state (`pending`, `suspended`), a missing pass, unavailable activation, or invalid or non-base64 activation data. | `data`: `IOSPassActivationData` | `boolean` | ✅ | ❌ |
## Data Types
| Type | Description | Fields |
|------|-------------|--------|
| **AndroidWalletData** | Specific information for Android devices required for wallet transactions. | `deviceID: string`,
`walletAccountID: string` |
-| **AndroidCardData** | Data related to a card that is to be added on Android platform wallets. | `network: string`,
`opaquePaymentCard: string`,
`cardHolderName: string`,
`lastDigits: string`,
`userAddress: UserAddress` |
+| **AndroidCardData** | Data related to a card that is to be added on Android platform wallets. | `network: string`,
`opaquePaymentCard: string`,
`cardHolderName: string`,
`lastDigits: string`,
`userAddress: UserAddress`,
`isVirtualCard?: boolean`,
`isBounceProvisioned?: boolean` |
| **AndroidResumeCardData** | Simplified data structure for resuming card addition to Google Wallet using existing token reference ID. | `network: string`,
`tokenReferenceID: string`,
`cardHolderName?: string`,
`lastDigits?: string` |
+| **AndroidPaymentCredentialsResponse** | Response object containing encrypted payment credentials for UAPP flow. [Learn more →](./docs/UAPP.md) | `opaquePaymentCard: string`,
`googleOpaquePaymentCard: string` |
+| **onPaymentCredentialsRequestPayload** | Payload received when Google Wallet requests payment credentials during UAPP provisioning. [Learn more →](./docs/UAPP.md) | `requestId: string`,
`serverSessionId: string`,
`walletId: string`,
`tokenRequestorId: string \| null`,
`opaquePaymentCard: string` |
| **UserAddress** | Structured address used for cardholder verification. | `name: string`,
`addressOne: string`,
`addressTwo: string`,
`city: string`,
`administrativeArea: string`,
`countryCode: string`,
`postalCode: string`,
`phoneNumber: string` |
-| **IOSCardData** | Data related to a card that is to be added on iOS platform. | `network: string`,
`activationData: string`,
`encryptedPassData: string`,
`ephemeralPublicKey: string`,
`cardHolderTitle: string`,
`cardHolderName: string`,
`lastDigits: string`,
`cardDescription: string`,
`cardDescriptionComment: string` |
-| **onCardActivatedPayload** | Data used by listener to notice when a card's status changes. | `tokenId: string`,
`status: 'activated' \| 'canceled'`
|
-| **IOSIssuerCallback** | This callback is invoked with a nonce, its signature, and a certificate array obtained from Apple. It is expected that you will forward these details to your server or the card issuer's API to securely encrypt the payload required for adding cards to the Apple Wallet. | `(nonce: string, nonceSignature: string, certificate: string[]) => IOSEncryptPayload` |
+| **IOSCardData** | Data related to a card that is to be added on iOS. Set `primaryAccountIdentifier` after the first provisioning so the next attempt targets devices that do not already have the card. | `network: string`,
`activationData: string`,
`encryptedPassData: string`,
`ephemeralPublicKey: string`,
`cardHolderTitle: string`,
`cardHolderName: string`,
`lastDigits: string`,
`cardDescription: string`,
`cardDescriptionComment: string`,
`primaryAccountIdentifier?: string` |
+| **onCardActivatedPayload** | Data used by listener to notice when a card's status changes. | `tokenId?: string \| null`,
`status: 'activated' \| 'canceled'`
|
+| **IOSIssuerCallback** | This callback is invoked with a nonce, its signature, a certificate array obtained from Apple, and the device the card is being added to. Forward these details to your server or the card issuer's API to securely encrypt the payload required for adding cards to the Apple Wallet. `deviceType` is a best-effort value; see `IOSDeviceType`. | `(nonce: string, nonceSignature: string, certificate: string[], deviceType: IOSDeviceType) => IOSEncryptPayload` |
+| **IOSDeviceType** | Best-effort device the card is being provisioned to. PassKit does not report the selected device, so this is inferred from existing passes when `primaryAccountIdentifier` is set, using the same id lookup as `addCardToAppleWallet`. The value is computed when Apple asks for the encrypted payload, including when the user tries again. Passes on a paired Apple Watch are never counted as iPhone passes. `phone` means the card is already on the paired Apple Watch only. `watch` means it is already on the iPhone only. `unknown` means the card is on neither device, or no identifier was provided, so the user may still choose either device. Passes in the `deactivated` state count as not present. | `'phone' \| 'watch' \| 'unknown'` |
+| **IOSAddPaymentPassData** | Data returned when the user continues the provisioning flow. Apple supplies the nonce, its signature, and the certificates. The library adds `deviceType`; Apple does not return it. See `IOSDeviceType`. | `status: number`,
`nonce: string`,
`nonceSignature: string`,
`certificates: string[]`,
`deviceType?: string` |
| **IOSEncryptPayload** | An object containing the necessary elements to complete the addition of a card to Apple Wallet. | `encryptedPassData: string`,
`activationData: string`,
`ephemeralPublicKey: string` |
+| **IOSPassActivationData** | Identifies an existing Apple Wallet Secure Element pass and provides the activation payload returned by your issuer backend. `activationData` must be Base 64 encoded. Set `isRemote` to `true` for a paired Apple Watch pass or `false` for the iPhone pass when the same card is on both. Omit it to look up the iPhone pass first and then the Watch. | `passTypeIdentifier: string`,
`serialNumber: string`,
`activationData: string`,
`isRemote?: boolean` |
+| **IOSWalletPass** | Information about an Apple Wallet Secure Element pass currently available on the device or a paired remote device. | `passTypeIdentifier: string`,
`serialNumber: string`,
`primaryAccountIdentifier?: string`,
`lastDigits?: string`,
`activationState: CardStatus`,
`isRemote: boolean` |
| **TokenInfo** | Information about a token stored in Google Wallet. | `identifier: string`,
`lastDigits: string`,
`tokenState: number` |
+### AndroidCardData Optional Fields
+
+The `AndroidCardData` type includes two optional boolean fields that provide additional information about the card being provisioned:
+
+#### `isVirtualCard?: boolean`
+
+Indicates whether the card being provisioned is a virtual card. Virtual cards are digitally-generated card numbers that are linked to a physical card account. They provide enhanced security by:
+- Allowing users to make online purchases without exposing their physical card number
+- Enabling easy cancellation and regeneration without affecting the physical card
+- Providing transaction-specific or merchant-specific card numbers
+
+When set to `true`, this flag informs Google Wallet that the card being provisioned is a virtual card, which may affect how the card is displayed and managed in the wallet interface.
+
+#### `isBounceProvisioned?: boolean`
+
+Indicates whether the card has been provisioned through "bounce provisioning". Bounce provisioning is a two-step provisioning flow where:
+1. The user initially provisions a card directly through Google Wallet (outside your app)
+2. Your app later "bounces" or redirects the user back to complete additional verification or setup steps
+
+This flag helps Google Wallet track cards that were initially added through the Google Wallet app but require additional app-specific configuration or verification. When set to `true`, it signals that this card was previously provisioned through the Google Wallet interface and is now being completed or updated through your application.
+
## Card Status
| Type | Possible Values |
|------|-----------------|
-| **CardStatus** | `not found`, `active`, `requireAuthorization`, `pending`, `suspended`, `deactivated` |
+| **CardStatus** | `not found`, `active`, `requireActivation`, `pending`, `suspended`, `deactivated` |
## Listeners
@@ -267,6 +301,7 @@ const base64ToHex = (base64: string): string => Buffer.from(base64, "base64").to
nonce: string,
nonceSignature: string,
certificate: string[],
+ deviceType: IOSDeviceType,
): Promise => {
try {
const payload = {
@@ -275,6 +310,7 @@ const base64ToHex = (base64: string): string => Buffer.from(base64, "base64").to
nonceSignature: base64ToHex(nonceSignature),
wspCertificates: certificate,
},
+ deviceType,
serialNumber,
wspId: "APPLE" as const,
}
@@ -283,17 +319,44 @@ const base64ToHex = (base64: string): string => Buffer.from(base64, "base64").to
This will depend on the implementation of your backend/issuer so make sure to check with them otherwise IOS might fail to provision the card.
+# UAPP (Unified Android Push Provisioning)
+
+For Android applications that require enhanced security for card provisioning, this library supports UAPP (Unified Android Push Provisioning) flow with Google Wallet.
+
+📖 **[Read the complete UAPP documentation →](./docs/UAPP.md)**
+
+The UAPP guide covers:
+- What UAPP is and how it works
+- Step-by-step setup instructions
+- Backend implementation requirements
+- Error handling and troubleshooting
+- Complete code examples
+
# Publishing your app
To successfully publish your app, you will need to navigate through a series of mandatory test cases on both platforms.
### Android
+> [!WARNING]
+> **Testing is mandatory before production release.** Your access to the Google Wallet production environment may be revoked if you do not provide the required test evidence for launch approval. Complete all testing requirements before deploying your app.
+
Before deploying your app to the Google Play Store, make sure you have taken care of the security when implementing Push Provisioning and properly tested your code. To accomplish it, please familiarize yourself with [the Google's App Push Provisioning best practices](https://developers.google.com/pay/issuers/apis/push-provisioning/android/best-practices).
The latest information about deploying apps with Google TapAndPay SDK can be found in the [pre-launch process](https://developers.google.com/pay/issuers/apis/push-provisioning/android/launch-process#step_3_issuer_app_product_review) and [beta tests](https://developers.google.com/pay/issuers/apis/push-provisioning/android/beta-testing) sections in Google documentation. Make sure to complete all of the steps specified by Google connected to the __Google's branding__, __API safety__, and __app stability__.
-The app will need to be reviewed by Google. During this process, it will need to pass 4 mandatory test cases that are specified [here](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases). They verify how your app handles card state tracking in different scenarios.
+#### Testing Requirements
+
+The app will need to be reviewed by Google. During this process, it will need to pass 4 mandatory test cases that are specified in the [official Google testing documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases). They verify how your app handles card state tracking in different scenarios.
+
+**Key testing criteria include:**
+- Proper handling of card states (active, pending, suspended, etc.)
+- Correct UI behavior when cards are already provisioned
+- Secure handling of sensitive payment data
+- Compliance with Google's branding guidelines
+- Proper error handling and user feedback
+
+Please refer to the [complete testing criteria documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases) before submitting your app for review.
> [!NOTE]
>Please make sure to hide the `Add to Google Wallet` buttons when cards are already added to the wallet.
@@ -301,7 +364,7 @@ The app will need to be reviewed by Google. During this process, it will need to
### iOS
When implementing the In-App Push Provisioning feature in your App make sure that your app follows Apple's [branding guidelines connected to Apple Wallet](https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/). Remember that you must not create your own buttons or your app could be rejected at revision. You can use the[ AddWalletButton component](#components) instead!
-When the pass is already provisioned, make sure to hide this button and replace it with text like `Added to Apple Wallet`. The card is fully provisioned once it added to your main device (user's iPhone) and all linked devices (for example Apple Watch).
+Keep the Add to Apple Wallet button visible while `canAddCardToAppleWallet(primaryAccountIdentifier, lastDigits)` returns `true`, including after the card is added to the iPhone but not yet to a paired Apple Watch. Show text like `Added to Apple Wallet` only once that call returns `false`. Pass `primaryAccountIdentifier` in `IOSCardData` so the next attempt targets the remaining device, and pass the same `lastDigits` to both calls so they agree. This matches [Apple's in-app provisioning guidance](https://applepaydemo.apple.com/in-app-provisioning#3.3).
Next to branding guidelines, please follow the instructions and best practices from [the In-App provisioning documentation]((#ios)) provided by Apple.
diff --git a/android/src/main/java/com/expensify/wallet/Utils.kt b/android/src/main/java/com/expensify/wallet/Utils.kt
index da8f0a30..7bce2507 100644
--- a/android/src/main/java/com/expensify/wallet/Utils.kt
+++ b/android/src/main/java/com/expensify/wallet/Utils.kt
@@ -29,12 +29,17 @@ object Utils {
.setPhoneNumber(addressMap.getString("phoneNumber") ?: "")
.build()
+ val isVirtual = if (hasKey("isVirtualCard")) this.getBoolean("isVirtualCard") else false
+ val isBounce = if (hasKey("isBounceProvisioned")) this.getBoolean("isBounceProvisioned") else false
+
return CardData(
network = this.getString("network") ?: "",
opaquePaymentCard = this.getString("opaquePaymentCard") ?: "",
cardHolderName = this.getString("cardHolderName") ?: "",
lastDigits = this.getString("lastDigits") ?: "",
- userAddress = userAddress
+ userAddress = userAddress,
+ isVirtualCard = isVirtual,
+ isBounceProvisioned = isBounce,
)
}
diff --git a/android/src/main/java/com/expensify/wallet/WalletModule.kt b/android/src/main/java/com/expensify/wallet/WalletModule.kt
index dfa1a398..af84cf7d 100644
--- a/android/src/main/java/com/expensify/wallet/WalletModule.kt
+++ b/android/src/main/java/com/expensify/wallet/WalletModule.kt
@@ -5,6 +5,15 @@ import android.app.Activity.RESULT_CANCELED
import android.app.Activity.RESULT_OK
import android.content.ActivityNotFoundException
import android.content.Intent
+import androidx.core.content.IntentCompat
+import com.expensify.wallet.Utils.getAsyncResult
+import com.expensify.wallet.Utils.toCardData
+import com.expensify.wallet.error.InvalidNetworkError
+import com.expensify.wallet.event.OnCardActivatedEvent
+import com.expensify.wallet.model.CardData
+import com.expensify.wallet.model.CardStatus
+import com.expensify.wallet.model.TokenizationStatus
+import com.expensify.wallet.model.WalletData
import com.facebook.react.bridge.ActivityEventListener
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.Promise
@@ -15,25 +24,35 @@ import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.WritableMap
import com.facebook.react.modules.core.DeviceEventManagerModule
+import com.google.android.gms.common.api.ApiException
import com.google.android.gms.tapandpay.TapAndPay
import com.google.android.gms.tapandpay.TapAndPayClient
+import com.google.android.gms.tapandpay.issuer.GeneratePaymentCredentialsException
+import com.google.android.gms.tapandpay.issuer.GeneratePaymentCredentialsRequest
+import com.google.android.gms.tapandpay.issuer.GeneratePaymentCredentialsResponse
+import com.google.android.gms.tapandpay.issuer.GetTokenStatusRequest
+import com.google.android.gms.tapandpay.issuer.HasEligibleTokenizationTargetRequest
+import com.google.android.gms.tapandpay.issuer.ListTokensRequest
+import com.google.android.gms.tapandpay.issuer.PaymentCredentialsGenerator
+import com.google.android.gms.tapandpay.issuer.PushTokenizeExtraOptions
import com.google.android.gms.tapandpay.issuer.PushTokenizeRequest
+import com.google.android.gms.tapandpay.issuer.PushTokenizeResult
+import com.google.android.gms.tapandpay.issuer.TokenizeRequest
+import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
-import com.expensify.wallet.Utils.getAsyncResult
-import com.expensify.wallet.Utils.toCardData
-import com.expensify.wallet.error.InvalidNetworkError
-import com.expensify.wallet.event.OnCardActivatedEvent
-import com.expensify.wallet.model.CardStatus
-import com.expensify.wallet.model.TokenizationStatus
-import com.expensify.wallet.model.WalletData
-import com.google.android.gms.common.api.ApiException
-import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.withTimeoutOrNull
import java.nio.charset.Charset
import java.util.Locale
+import java.util.UUID
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.Future
class WalletModule internal constructor(context: ReactApplicationContext) :
@@ -41,11 +60,14 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
companion object {
const val NAME = "RNWallet"
const val REQUEST_CODE_PUSH_TOKENIZE: Int = 0xA001
+ const val REQUEST_CODE_RESUME_TOKENIZE: Int = 0xA003
const val REQUEST_CREATE_WALLET: Int = 0xA002
const val E_SDK_API = "SDK API Error"
const val E_OPERATION_FAILED = "E_OPERATION_FAILED"
const val E_INVALID_DATA = "E_INVALID_DATA"
+
+ const val PAYMENT_CREDENTIALS_TIMEOUT_MS = 60_000L
}
private val activity: Activity
@@ -57,6 +79,8 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
private var pendingPushTokenizePromise: Promise? = null
private val moduleScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
+ private val pendingPaymentCredentials = ConcurrentHashMap>()
+
override fun initialize() {
super.initialize()
reactApplicationContext.addActivityEventListener(cardListener)
@@ -66,42 +90,100 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
super.invalidate()
moduleScope.cancel()
reactApplicationContext.removeActivityEventListener(cardListener)
+ pendingPaymentCredentials.clear()
}
private val cardListener = object : ActivityEventListener {
override fun onActivityResult(
activity: Activity, requestCode: Int, resultCode: Int, data: Intent?
) {
- if (requestCode == REQUEST_CREATE_WALLET) {
- pendingCreateWalletPromise?.resolve(resultCode == RESULT_OK)
- pendingCreateWalletPromise = null
- } else if (requestCode == REQUEST_CODE_PUSH_TOKENIZE) {
- val localPromise = pendingPushTokenizePromise
- pendingPushTokenizePromise = null
- if (resultCode == RESULT_OK) {
- val tokenId = data?.getStringExtra(TapAndPay.EXTRA_ISSUER_TOKEN_ID)
- sendEvent(
- context,
- OnCardActivatedEvent.NAME,
- OnCardActivatedEvent("activated", tokenId).toMap()
- )
- localPromise?.resolve(TokenizationStatus.SUCCESS.code)
- } else if (resultCode == RESULT_CANCELED) {
- sendEvent(
- context,
- OnCardActivatedEvent.NAME,
- OnCardActivatedEvent("canceled", null).toMap()
- )
- localPromise?.resolve(TokenizationStatus.CANCELED.code)
- } else {
- localPromise?.resolve(TokenizationStatus.ERROR.code)
+ when (requestCode) {
+ REQUEST_CREATE_WALLET -> {
+ pendingCreateWalletPromise?.resolve(resultCode == RESULT_OK)
+ pendingCreateWalletPromise = null
}
+ REQUEST_CODE_RESUME_TOKENIZE -> handleResumeTokenizeResult(resultCode, data)
+ REQUEST_CODE_PUSH_TOKENIZE -> handlePushTokenizeResult(resultCode, data)
}
}
override fun onNewIntent(intent: Intent) {}
}
+ private fun takePendingTokenizePromise(): Promise? =
+ pendingPushTokenizePromise.also { pendingPushTokenizePromise = null }
+
+ private fun sendCardActivatedEvent(status: String, tokenId: String?) {
+ sendEvent(reactApplicationContext, OnCardActivatedEvent.NAME, OnCardActivatedEvent(status, tokenId).toMap())
+ }
+
+ private fun handleResumeTokenizeResult(resultCode: Int, data: Intent?) {
+ val promise = takePendingTokenizePromise()
+ when (resultCode) {
+ RESULT_OK -> {
+ sendCardActivatedEvent("activated", data?.getStringExtra(TapAndPay.EXTRA_ISSUER_TOKEN_ID))
+ promise?.resolve(TokenizationStatus.SUCCESS.code)
+ }
+ RESULT_CANCELED -> {
+ sendCardActivatedEvent("canceled", null)
+ promise?.resolve(TokenizationStatus.CANCELED.code)
+ }
+ else -> promise?.resolve(TokenizationStatus.ERROR.code)
+ }
+ }
+
+ private fun handlePushTokenizeResult(resultCode: Int, data: Intent?) {
+ val promise = takePendingTokenizePromise()
+ if (resultCode == RESULT_CANCELED) {
+ sendCardActivatedEvent("canceled", null)
+ promise?.resolve(TokenizationStatus.CANCELED.code)
+ return
+ }
+
+ val result = data?.let {
+ IntentCompat.getParcelableExtra(it, TapAndPay.EXTRA_PUSH_TOKENIZE_RESULT, PushTokenizeResult::class.java)
+ }
+
+ if (result == null) {
+ handlePushTokenizeResultExtras(resultCode, data, promise)
+ return
+ }
+
+ val successfulOutcome = result.tokenizationOutcomes.firstOrNull { it.tokenResult }
+ if (result.cardResult || successfulOutcome != null) {
+ sendCardActivatedEvent("activated", successfulOutcome?.issuerTokenId)
+ promise?.resolve(TokenizationStatus.SUCCESS.code)
+ } else {
+ promise?.reject(E_OPERATION_FAILED, "Card not saved. Status: ${result.cardStatus}")
+ }
+ }
+
+ // Google documents the result both as PushTokenizeResult and as separate extras, so read the extras when the object is missing
+ private fun handlePushTokenizeResultExtras(resultCode: Int, data: Intent?, promise: Promise?) {
+ val hasTokenResult = data?.hasExtra(TapAndPay.EXTRA_TOKEN_RESULT) == true
+ val hasCardResult = data?.hasExtra(TapAndPay.EXTRA_CARD_RESULT) == true
+
+ if (!hasTokenResult && !hasCardResult) {
+ if (resultCode == RESULT_OK) {
+ sendCardActivatedEvent("activated", data?.getStringExtra(TapAndPay.EXTRA_ISSUER_TOKEN_ID))
+ promise?.resolve(TokenizationStatus.SUCCESS.code)
+ } else {
+ promise?.resolve(TokenizationStatus.ERROR.code)
+ }
+ return
+ }
+
+ val tokenResult = data?.getBooleanExtra(TapAndPay.EXTRA_TOKEN_RESULT, false) == true
+ val cardResult = data?.getBooleanExtra(TapAndPay.EXTRA_CARD_RESULT, false) == true
+ if (tokenResult || cardResult) {
+ val tokenId = if (tokenResult) data?.getStringExtra(TapAndPay.EXTRA_ISSUER_TOKEN_ID) else null
+ sendCardActivatedEvent("activated", tokenId)
+ promise?.resolve(TokenizationStatus.SUCCESS.code)
+ } else {
+ promise?.reject(E_OPERATION_FAILED, "Card not saved")
+ }
+ }
+
@ReactMethod
override fun ensureGoogleWalletInitialized(promise: Promise) {
val localPromise = PromiseImpl({ _ ->
@@ -147,7 +229,7 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
@ReactMethod
override fun getCardStatusBySuffix(last4Digits: String, promise: Promise) {
- tapAndPayClient.listTokens()
+ tapAndPayClient.listTokens(ListTokensRequest.Builder().build())
.addOnCompleteListener { task ->
if (!task.isSuccessful || task.result == null) {
promise.resolve(CardStatus.NOT_FOUND_IN_WALLET.code)
@@ -166,7 +248,12 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
@ReactMethod
override fun getCardStatusByIdentifier(identifier: String, tsp: String, promise: Promise) {
- tapAndPayClient.getTokenStatus(getTokenServiceProvider(tsp), identifier)
+ tapAndPayClient.getTokenStatus(
+ GetTokenStatusRequest.Builder()
+ .setTokenServiceProvider(getTokenServiceProvider(tsp))
+ .setIssuerTokenId(identifier)
+ .build()
+ )
.addOnCompleteListener { task ->
if (!task.isSuccessful || task.result == null) {
promise.resolve(CardStatus.NOT_FOUND_IN_WALLET.code)
@@ -183,6 +270,25 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
}
}
+ @ReactMethod
+ override fun hasEligibleTokenizationTarget(last4Digits: String, network: String, issuerName: String, promise: Promise) {
+ try {
+ val request = HasEligibleTokenizationTargetRequest.Builder()
+ .setIdentifier(last4Digits)
+ .setNetwork(getCardNetwork(network))
+ .setTokenServiceProvider(getTokenServiceProvider(network))
+ .setIssuerName(issuerName)
+ .build()
+ tapAndPayClient.hasEligibleTokenizationTarget(request)
+ .addOnSuccessListener { promise.resolve(it) }
+ .addOnFailureListener { e ->
+ promise.reject(E_OPERATION_FAILED, "hasEligibleTokenizationTarget: ${e.localizedMessage}")
+ }
+ } catch (e: InvalidNetworkError) {
+ promise.reject(E_INVALID_DATA, e.message)
+ }
+ }
+
@ReactMethod
override fun addCardToGoogleWallet(
data: ReadableMap, promise: Promise
@@ -197,6 +303,11 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
val displayName = getDisplayName(data, cardData.network)
pendingPushTokenizePromise = promise
+ val pushTokenizeExtraOptions = PushTokenizeExtraOptions.newBuilder()
+ .setIsBounceProvisioned(cardData.isBounceProvisioned)
+ .setEnrollForVirtualCards(cardData.isVirtualCard)
+ .build()
+
val pushTokenizeRequest = PushTokenizeRequest.Builder()
.setOpaquePaymentCard(cardData.opaquePaymentCard.toByteArray(Charset.forName("UTF-8")))
.setNetwork(cardNetwork)
@@ -204,17 +315,130 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
.setDisplayName(displayName)
.setLastDigits(cardData.lastDigits)
.setUserAddress(cardData.userAddress)
+ .setPaymentCredentialsGenerator(createPaymentCredentialsGenerator(cardData))
+ .setPushTokenizeExtraOptions(pushTokenizeExtraOptions)
.build()
- tapAndPayClient.pushTokenize(
- activity, pushTokenizeRequest, REQUEST_CODE_PUSH_TOKENIZE
- )
+ tapAndPayClient.pushTokenize(pushTokenizeRequest)
+ .addOnSuccessListener { pendingIntent ->
+ try {
+ activity.startIntentSenderForResult(
+ pendingIntent.intentSender,
+ REQUEST_CODE_PUSH_TOKENIZE,
+ null, 0, 0, 0
+ )
+ } catch (e: Exception) {
+ pendingPushTokenizePromise = null
+ promise.reject(E_OPERATION_FAILED, "Failed to launch Google Pay: ${e.message}")
+ }
+ }
+ .addOnFailureListener { e ->
+ pendingPushTokenizePromise = null
+ promise.reject(E_OPERATION_FAILED, "Google Pay API Error: ${e.message}")
+ }
} catch (e: java.lang.Exception) {
pendingPushTokenizePromise = null
promise.reject(e)
}
}
+ // Google Wallet only understands GeneratePaymentCredentialsException; UNKNOWN_ERROR covers backend failures and timeouts
+ private fun paymentCredentialsError() =
+ GeneratePaymentCredentialsException(GeneratePaymentCredentialsException.UNKNOWN_ERROR)
+
+ private fun createPaymentCredentialsGenerator(
+ cardData: CardData
+ ): PaymentCredentialsGenerator {
+ return object : PaymentCredentialsGenerator {
+ override fun generate(request: GeneratePaymentCredentialsRequest): Future {
+ if (!request.googleOpaquePaymentCardRequested) {
+ val response = GeneratePaymentCredentialsResponse.Builder()
+ .setOpaquePaymentCard(cardData.opaquePaymentCard.toByteArray(Charsets.UTF_8))
+ .build()
+
+ return CompletableFuture.completedFuture(response)
+ }
+
+ val future = CompletableFuture()
+ val credentials = CompletableDeferred()
+ val requestId = UUID.randomUUID().toString()
+ pendingPaymentCredentials[requestId] = credentials
+ moduleScope.launch(start = CoroutineStart.UNDISPATCHED) {
+ // null on timeout, on reject, or when invalidate() cancels the scope
+ val response = runCatching {
+ withTimeoutOrNull(PAYMENT_CREDENTIALS_TIMEOUT_MS) { credentials.await() }
+ }.getOrNull()
+ pendingPaymentCredentials.remove(requestId)
+ if (response != null) {
+ future.complete(response)
+ } else {
+ future.completeExceptionally(paymentCredentialsError())
+ }
+ }
+
+ val params = Arguments.createMap().apply {
+ putString("requestId", requestId)
+ putString("serverSessionId", request.serverSessionId)
+ putString("walletId", request.walletId)
+ putString("tokenRequestorId", request.tokenRequestorId)
+ putString("opaquePaymentCard", cardData.opaquePaymentCard)
+ }
+
+ // send event to the RN so the Google OPC can be generated on the backend
+ sendEvent(reactApplicationContext, "onPaymentCredentialsRequest", params)
+ return future
+ }
+
+ // This switch enables the UAPP flow
+ override fun getGoogleOpaquePaymentCardSupported(): Boolean {
+ return true
+ }
+ }
+ }
+
+ @ReactMethod
+ override fun AndroidProvidePaymentCredentials(requestId: String, responseData: ReadableMap, promise: Promise) {
+ val credentials = pendingPaymentCredentials.remove(requestId)
+ if (credentials == null) {
+ promise.reject(E_OPERATION_FAILED, "Request ID not found or timed out")
+ return
+ }
+
+ try {
+ val tspOpc = responseData.getString("opaquePaymentCard")
+ val googleOpc = responseData.getString("googleOpaquePaymentCard")
+
+ if (tspOpc == null) {
+ throw Exception("opaquePaymentCard is required")
+ }
+ if (googleOpc == null) {
+ throw Exception("googleOpaquePaymentCard is required")
+ }
+ val response = GeneratePaymentCredentialsResponse.Builder()
+ .setGoogleOpaquePaymentCard(googleOpc.toByteArray(Charsets.UTF_8))
+ .setOpaquePaymentCard(tspOpc.toByteArray(Charsets.UTF_8))
+ .build()
+
+ credentials.complete(response)
+ promise.resolve(true)
+
+ } catch (e: Exception) {
+ credentials.completeExceptionally(paymentCredentialsError())
+ promise.reject(E_OPERATION_FAILED, e.message)
+ }
+ }
+
+ @ReactMethod
+ override fun AndroidRejectPaymentCredentials(requestId: String, errorMessage: String, promise: Promise) {
+ val credentials = pendingPaymentCredentials.remove(requestId)
+ if (credentials == null) {
+ promise.reject(E_OPERATION_FAILED, "Request ID not found or timed out")
+ return
+ }
+ credentials.completeExceptionally(paymentCredentialsError())
+ promise.resolve(true)
+ }
+
@ReactMethod
override fun resumeAddCardToGoogleWallet(data: ReadableMap, promise: Promise) {
if (pendingPushTokenizePromise != null) {
@@ -232,14 +456,13 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
val displayName = getDisplayName(data, network)
pendingPushTokenizePromise = promise
- tapAndPayClient.tokenize(
- activity,
- tokenReferenceID,
- tokenServiceProvider,
- displayName,
- cardNetwork,
- REQUEST_CODE_PUSH_TOKENIZE
- )
+ val tokenizeRequest = TokenizeRequest.Builder()
+ .setIssuerTokenId(tokenReferenceID)
+ .setTokenServiceProvider(tokenServiceProvider)
+ .setCardDisplayName(displayName)
+ .setCardNetwork(cardNetwork)
+ .build()
+ tapAndPayClient.tokenize(activity, tokenizeRequest, REQUEST_CODE_RESUME_TOKENIZE)
} catch (e: java.lang.Exception) {
pendingPushTokenizePromise = null
promise.reject(e)
@@ -248,13 +471,13 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
@ReactMethod
override fun listTokens(promise: Promise) {
- tapAndPayClient.listTokens()
+ tapAndPayClient.listTokens(ListTokensRequest.Builder().build())
.addOnCompleteListener { task ->
if (!task.isSuccessful || task.result == null) {
promise.resolve(Arguments.createArray())
return@addOnCompleteListener
}
-
+
val tokensArray = Arguments.createArray()
task.result.forEach { tokenInfo ->
val tokenData = Arguments.createMap().apply {
@@ -264,7 +487,7 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
}
tokensArray.pushMap(tokenData)
}
-
+
promise.resolve(tokensArray)
}
.addOnFailureListener { e ->
@@ -341,13 +564,13 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
data.getString("cardHolderName")?.let { name ->
if (name.isNotEmpty()) return name
}
-
+
data.getString("lastDigits")?.let { digits ->
if (digits.isNotEmpty()) {
return "${network.uppercase(Locale.getDefault())} Card *$digits"
}
}
-
+
return "${network.uppercase(Locale.getDefault())} Card"
}
@@ -365,6 +588,18 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
// no-op
}
+ override fun listAppleWalletPasses(promise: Promise) {
+ // no-op
+ }
+
+ override fun activateAppleWalletPass(passData: ReadableMap?, promise: Promise?) {
+ // no-op
+ }
+
+ override fun canAddCardToAppleWallet(primaryAccountIdentifier: String, lastDigits: String, promise: Promise) {
+ promise.resolve(false)
+ }
+
override fun addListener(eventType: String?) {
// no-op
}
diff --git a/android/src/main/java/com/expensify/wallet/model/CardData.kt b/android/src/main/java/com/expensify/wallet/model/CardData.kt
index d9191e0e..a348ee77 100644
--- a/android/src/main/java/com/expensify/wallet/model/CardData.kt
+++ b/android/src/main/java/com/expensify/wallet/model/CardData.kt
@@ -5,8 +5,10 @@ import com.google.android.gms.tapandpay.issuer.UserAddress
data class CardData(
val platform: String = "android",
val network: String,
- val opaquePaymentCard: String,
+ val opaquePaymentCard: String, // TSP OPC
val cardHolderName: String,
val lastDigits: String,
val userAddress: UserAddress,
+ val isVirtualCard: Boolean = false,
+ val isBounceProvisioned: Boolean = false,
)
diff --git a/android/src/paper/java/com/expensify/wallet/NativeWalletSpec.java b/android/src/paper/java/com/expensify/wallet/NativeWalletSpec.java
index 999f0cb8..07eb60e4 100644
--- a/android/src/paper/java/com/expensify/wallet/NativeWalletSpec.java
+++ b/android/src/paper/java/com/expensify/wallet/NativeWalletSpec.java
@@ -57,6 +57,14 @@ public NativeWalletSpec(ReactApplicationContext reactContext) {
@DoNotStrip
public abstract void addCardToGoogleWallet(ReadableMap cardData, Promise promise);
+ @ReactMethod
+ @DoNotStrip
+ public abstract void AndroidProvidePaymentCredentials(String requestId, ReadableMap responseData, Promise promise);
+
+ @ReactMethod
+ @DoNotStrip
+ public abstract void AndroidRejectPaymentCredentials(String requestId, String errorMessage, Promise promise);
+
@ReactMethod
@DoNotStrip
public abstract void resumeAddCardToGoogleWallet(ReadableMap cardData, Promise promise);
@@ -65,6 +73,10 @@ public NativeWalletSpec(ReactApplicationContext reactContext) {
@DoNotStrip
public abstract void listTokens(Promise promise);
+ @ReactMethod
+ @DoNotStrip
+ public abstract void listAppleWalletPasses(Promise promise);
+
@ReactMethod
@DoNotStrip
public abstract void IOSPresentAddPaymentPassView(ReadableMap cardData, Promise promise);
@@ -73,6 +85,12 @@ public NativeWalletSpec(ReactApplicationContext reactContext) {
@DoNotStrip
public abstract void IOSHandleAddPaymentPassResponse(ReadableMap payload, Promise promise);
+ public abstract void activateAppleWalletPass(ReadableMap passData, Promise promise);
+
+ @ReactMethod
+ @DoNotStrip
+ public abstract void canAddCardToAppleWallet(String primaryAccountIdentifier, String lastDigits, Promise promise);
+
@ReactMethod
@DoNotStrip
public abstract void addListener(String eventType);
diff --git a/apps/basic-example/Gemfile b/apps/basic-example/Gemfile
index 2d625b45..4a3af07f 100644
--- a/apps/basic-example/Gemfile
+++ b/apps/basic-example/Gemfile
@@ -6,7 +6,7 @@ ruby ">= 2.6.10"
# Exclude problematic versions of cocoapods and activesupport that causes build failures.
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
-gem 'concurrent-ruby', '< 1.3.4'
+gem 'concurrent-ruby', '>= 1.3.7'
# Ruby 3.4.0 has removed some libraries from the standard library.
gem 'bigdecimal'
diff --git a/apps/basic-example/Gemfile.lock b/apps/basic-example/Gemfile.lock
index 0c412bfe..a0ddfbcb 100644
--- a/apps/basic-example/Gemfile.lock
+++ b/apps/basic-example/Gemfile.lock
@@ -15,13 +15,14 @@ GEM
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
- addressable (2.8.7)
- public_suffix (>= 2.0.2, < 7.0)
+ addressable (2.9.0)
+ public_suffix (>= 2.0.2, < 8.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
atomos (0.1.3)
base64 (0.2.0)
+ benchmark (0.5.0)
bigdecimal (3.1.8)
claide (1.1.0)
cocoapods (1.15.2)
@@ -62,7 +63,7 @@ GEM
netrc (~> 0.11)
cocoapods-try (1.2.0)
colored2 (3.1.2)
- concurrent-ruby (1.3.3)
+ concurrent-ruby (1.3.8)
connection_pool (2.4.1)
drb (2.2.1)
escape (0.0.4)
@@ -76,6 +77,7 @@ GEM
i18n (1.14.5)
concurrent-ruby (~> 1.0)
json (2.7.2)
+ logger (1.7.0)
minitest (5.24.1)
molinillo (0.8.0)
mutex_m (0.2.0)
@@ -84,10 +86,8 @@ GEM
netrc (0.11.0)
nkf (0.2.0)
public_suffix (4.0.7)
- rexml (3.2.9)
- strscan
+ rexml (3.4.4)
ruby-macho (2.5.1)
- strscan (3.1.0)
typhoeus (1.4.1)
ethon (>= 0.9.0)
tzinfo (2.0.6)
@@ -105,7 +105,12 @@ PLATFORMS
DEPENDENCIES
activesupport (>= 6.1.7.5, != 7.1.0)
+ benchmark
+ bigdecimal
cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
+ concurrent-ruby (>= 1.3.7)
+ logger
+ mutex_m
RUBY VERSION
ruby 3.2.1p31
diff --git a/apps/common-app/src/CONST.ts b/apps/common-app/src/CONST.ts
index 8752ef19..e3130925 100644
--- a/apps/common-app/src/CONST.ts
+++ b/apps/common-app/src/CONST.ts
@@ -17,6 +17,8 @@ const AndroidDummyCardData: AndroidCardData = {
cardHolderName: 'John Doe',
lastDigits: '4321',
userAddress: dummyAddress,
+ isVirtualCard: false,
+ isBounceProvisioned: false,
};
const AndroidDummyResumeCardData: AndroidResumeCardData = {
@@ -40,4 +42,9 @@ const IOSDummyEncryptPayload: IOSEncryptPayload = {
ephemeralPublicKey: 'ZXBoZW1lcmFsUHVibGljS2V5MTIz',
};
-export {AndroidDummyCardData, AndroidDummyResumeCardData, IOSDummyCardData, IOSDummyEncryptPayload};
+const AndroidDummyPaymentCredentialsResponse = {
+ opaquePaymentCard: 'encryptedCardInformation123456',
+ googleOpaquePaymentCard: 'GOPC',
+};
+
+export {AndroidDummyCardData, AndroidDummyResumeCardData, IOSDummyCardData, IOSDummyEncryptPayload, AndroidDummyPaymentCredentialsResponse};
diff --git a/apps/common-app/src/walletUtils.ts b/apps/common-app/src/walletUtils.ts
index 2d5769bf..8498306e 100644
--- a/apps/common-app/src/walletUtils.ts
+++ b/apps/common-app/src/walletUtils.ts
@@ -1,5 +1,5 @@
import {addCardToAppleWallet, addCardToGoogleWallet, listTokens, resumeAddCardToGoogleWallet} from '@expensify/react-native-wallet';
-import type {CardStatus} from '@expensify/react-native-wallet';
+import type {AndroidPaymentCredentialsResponse, CardStatus, onPaymentCredentialsRequestPayload} from '@expensify/react-native-wallet';
import {Platform} from 'react-native';
import * as CONST from './CONST';
@@ -9,6 +9,12 @@ function issuerEncryptPayloadCallback(_nonce: string, _nonceSignature: string, _
return Promise.resolve(CONST.IOSDummyEncryptPayload);
}
+function handlePaymentCredentialsGeneration(_data: onPaymentCredentialsRequestPayload): Promise {
+ // Here send data to your server or you TSP to generate the payment credentials
+ // for example: fetch('https://tsp.com/generatePaymentCredentials', {method: 'POST', body: data})
+ return Promise.resolve(CONST.AndroidDummyPaymentCredentialsResponse);
+}
+
async function addCardToWallet(cardStatus?: CardStatus) {
if (Platform.OS === 'android') {
if (cardStatus === 'requireActivation') {
@@ -24,7 +30,7 @@ async function addCardToWallet(cardStatus?: CardStatus) {
tokenReferenceID: existingToken.identifier,
});
}
- return addCardToGoogleWallet(CONST.AndroidDummyCardData);
+ return addCardToGoogleWallet(CONST.AndroidDummyCardData, handlePaymentCredentialsGeneration);
} else {
return addCardToAppleWallet(CONST.IOSDummyCardData, issuerEncryptPayloadCallback);
}
diff --git a/apps/expo-example/package-lock.json b/apps/expo-example/package-lock.json
index b30eea4f..0e6c31d9 100644
--- a/apps/expo-example/package-lock.json
+++ b/apps/expo-example/package-lock.json
@@ -24,8 +24,7 @@
},
"../..": {
"name": "@expensify/react-native-wallet",
- "version": "0.1.15",
- "hasInstallScript": true,
+ "version": "0.2.14",
"license": "MIT",
"workspaces": [
"apps/common-app",
@@ -49,7 +48,7 @@
"@typescript-eslint/parser": "^6.15.0",
"del-cli": "^5.0.0",
"eslint": "^8.57.1",
- "eslint-config-expensify": "^2.0.24",
+ "eslint-config-expensify": "2.0.24",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-deprecation": "^2.0.0",
@@ -1520,25 +1519,6 @@
"node": ">=6.9.0"
}
},
- "node_modules/@babel/traverse--for-generate-function-map": {
- "name": "@babel/traverse",
- "version": "7.29.0",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
- "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.29.0",
- "@babel/generator": "^7.29.0",
- "@babel/helper-globals": "^7.28.0",
- "@babel/parser": "^7.29.0",
- "@babel/template": "^7.28.6",
- "@babel/types": "^7.29.0",
- "debug": "^4.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
"node_modules/@babel/types": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
@@ -1885,9 +1865,9 @@
}
},
"node_modules/@expo/fingerprint/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
+ "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -1919,16 +1899,37 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/@expo/fingerprint/node_modules/glob/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@expo/fingerprint/node_modules/glob/node_modules/brace-expansion": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/@expo/fingerprint/node_modules/glob/node_modules/minimatch": {
- "version": "10.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
- "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
"license": "BlueOak-1.0.0",
"dependencies": {
- "@isaacs/brace-expansion": "^5.0.1"
+ "brace-expansion": "^5.0.8"
},
"engines": {
- "node": "20 || >=22"
+ "node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -1944,12 +1945,12 @@
}
},
"node_modules/@expo/fingerprint/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -2276,27 +2277,6 @@
"url": "https://github.com/sponsors/nzakas"
}
},
- "node_modules/@isaacs/balanced-match": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
- "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
- "license": "MIT",
- "engines": {
- "node": "20 || >=22"
- }
- },
- "node_modules/@isaacs/brace-expansion": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz",
- "integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
- "license": "MIT",
- "dependencies": {
- "@isaacs/balanced-match": "^4.0.1"
- },
- "engines": {
- "node": "20 || >=22"
- }
- },
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -2410,9 +2390,9 @@
}
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
- "version": "3.14.2",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
- "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
+ "version": "3.15.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz",
+ "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==",
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
@@ -2983,9 +2963,9 @@
}
},
"node_modules/@react-native/dev-middleware/node_modules/ws": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
- "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
+ "version": "6.2.6",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.6.tgz",
+ "integrity": "sha512-XTrf1gv7kXoVf1hbC3PAyAiPgR8Wz1blcrYIjEsUmr08BLksT41R8KbjmS9408C2ERx7v1JDLD/BkpLEttjfKA==",
"license": "MIT",
"dependencies": {
"async-limiter": "~1.0.0"
@@ -3371,9 +3351,9 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
+ "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3381,13 +3361,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true,
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -3763,10 +3743,9 @@
}
},
"node_modules/@xmldom/xmldom": {
- "version": "0.7.13",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz",
- "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==",
- "deprecated": "this version is no longer supported, please update to at least 0.8.*",
+ "version": "0.8.15",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz",
+ "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@@ -4348,12 +4327,15 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
- "version": "2.9.19",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
- "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
+ "version": "2.11.33",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.33.tgz",
+ "integrity": "sha512-yiVKDX+qCMRKBE084lXvq9EcwFUhKZ2nU8TK1EQQuOgPNR/lmbGxXOeDdlGUqC2Zz11Cs9rk1d/8NfgBmlkt0w==",
"license": "Apache-2.0",
"bin": {
- "baseline-browser-mapping": "dist/cli.js"
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
}
},
"node_modules/better-opn": {
@@ -4416,9 +4398,9 @@
}
},
"node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -4438,9 +4420,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.28.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
- "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+ "version": "4.28.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz",
+ "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==",
"funding": [
{
"type": "opencollective",
@@ -4457,11 +4439,11 @@
],
"license": "MIT",
"dependencies": {
- "baseline-browser-mapping": "^2.9.0",
- "caniuse-lite": "^1.0.30001759",
- "electron-to-chromium": "^1.5.263",
- "node-releases": "^2.0.27",
- "update-browserslist-db": "^1.2.0"
+ "baseline-browser-mapping": "^2.10.44",
+ "caniuse-lite": "^1.0.30001806",
+ "electron-to-chromium": "^1.5.393",
+ "node-releases": "^2.0.51",
+ "update-browserslist-db": "^1.2.3"
},
"bin": {
"browserslist": "cli.js"
@@ -4591,9 +4573,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001769",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz",
- "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==",
+ "version": "1.0.30001819",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001819.tgz",
+ "integrity": "sha512-LFUqIIAwpzsIuevnKnsR9qnStBcgzPShTX61lBwN9uFkkf8o8zLiebEjbW8AYtZiF+1YKDWfdt/pWDtMuG8Xwg==",
"funding": [
{
"type": "opencollective",
@@ -4797,14 +4779,15 @@
}
},
"node_modules/compression": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
- "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.2.tgz",
+ "integrity": "sha512-o8vI5RE5A6EVVOd9o41jKp41aJom+QTEO/Bx8MYNjexMo/Bv2WOjUfZr+aL0WnYSgymUy6zeguqLTsIhV0gMvQ==",
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"compressible": "~2.0.18",
"debug": "2.6.9",
+ "destroy": "1.2.0",
"negotiator": "~0.6.4",
"on-headers": "~1.1.0",
"safe-buffer": "5.2.1",
@@ -4874,6 +4857,19 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
+ "node_modules/content-type": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz",
+ "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -5168,9 +5164,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.286",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
- "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==",
+ "version": "1.5.464",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.464.tgz",
+ "integrity": "sha512-nRa65aFge40viPAKxMKULIY8tcXKwKboJWNn4RoKwyWXJ6SP7BnrDGKUTzc64818jIciH0PK7LSF8QzZes19GA==",
"license": "ISC"
},
"node_modules/emoji-regex": {
@@ -6473,9 +6469,9 @@
}
},
"node_modules/expo/node_modules/@react-native/dev-middleware/node_modules/ws": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
- "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
+ "version": "6.2.6",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.6.tgz",
+ "integrity": "sha512-XTrf1gv7kXoVf1hbC3PAyAiPgR8Wz1blcrYIjEsUmr08BLksT41R8KbjmS9408C2ERx7v1JDLD/BkpLEttjfKA==",
"license": "MIT",
"dependencies": {
"async-limiter": "~1.0.0"
@@ -6487,15 +6483,6 @@
"integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==",
"license": "MIT"
},
- "node_modules/expo/node_modules/@xmldom/xmldom": {
- "version": "0.8.11",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
- "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==",
- "license": "MIT",
- "engines": {
- "node": ">=10.0.0"
- }
- },
"node_modules/expo/node_modules/babel-preset-expo": {
"version": "54.0.10",
"resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-54.0.10.tgz",
@@ -6540,9 +6527,9 @@
}
},
"node_modules/expo/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
+ "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -6676,16 +6663,37 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/expo/node_modules/glob/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/expo/node_modules/glob/node_modules/brace-expansion": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/expo/node_modules/glob/node_modules/minimatch": {
- "version": "10.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
- "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
"license": "BlueOak-1.0.0",
"dependencies": {
- "@isaacs/brace-expansion": "^5.0.1"
+ "brace-expansion": "^5.0.8"
},
"engines": {
- "node": "20 || >=22"
+ "node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -6945,12 +6953,12 @@
}
},
"node_modules/expo/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -6976,9 +6984,9 @@
}
},
"node_modules/expo/node_modules/picomatch": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz",
- "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.2.tgz",
+ "integrity": "sha512-cfDHL6LStTEKlNilboNtobT/kEa30PtAf2Q1OgszfrG/rpVl1xaFWT9ktfkS306GmHgmnad1Sw4wabhlvFtsTw==",
"license": "MIT",
"engines": {
"node": ">=10"
@@ -7053,9 +7061,9 @@
}
},
"node_modules/expo/node_modules/ws": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
- "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
+ "version": "8.21.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
+ "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@@ -7218,9 +7226,9 @@
}
},
"node_modules/flatted": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
- "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz",
+ "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==",
"dev": true,
"license": "ISC"
},
@@ -7512,21 +7520,21 @@
}
},
"node_modules/glob/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
+ "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/glob/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -7699,18 +7707,18 @@
}
},
"node_modules/hermes-estree": {
- "version": "0.32.0",
- "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz",
- "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz",
+ "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==",
"license": "MIT"
},
"node_modules/hermes-parser": {
- "version": "0.32.0",
- "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz",
- "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz",
+ "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==",
"license": "MIT",
"dependencies": {
- "hermes-estree": "0.32.0"
+ "hermes-estree": "0.35.0"
}
},
"node_modules/hosted-git-info": {
@@ -7802,21 +7810,6 @@
"node": ">= 4"
}
},
- "node_modules/image-size": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
- "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==",
- "license": "MIT",
- "dependencies": {
- "queue": "6.0.2"
- },
- "bin": {
- "image-size": "bin/image-size.js"
- },
- "engines": {
- "node": ">=16.x"
- }
- },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -8616,9 +8609,9 @@
"license": "MIT"
},
"node_modules/js-yaml": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+ "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@@ -9213,45 +9206,43 @@
"license": "MIT"
},
"node_modules/metro": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.3.tgz",
- "integrity": "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.8.tgz",
+ "integrity": "sha512-ZbJDJCDlvv0O3QHVbhZkyP2/DtebfEoDZ3wVyYHgu6Uoy6DmmE/bis6lIDBYh+kWPuaueJDegyutPjkIBLtZDQ==",
"license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.24.7",
+ "@babel/code-frame": "^7.29.0",
"@babel/core": "^7.25.2",
- "@babel/generator": "^7.25.0",
- "@babel/parser": "^7.25.3",
- "@babel/template": "^7.25.0",
- "@babel/traverse": "^7.25.3",
- "@babel/types": "^7.25.2",
- "accepts": "^1.3.7",
- "chalk": "^4.0.0",
+ "@babel/generator": "^7.29.1",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "accepts": "^2.0.0",
"ci-info": "^2.0.0",
"connect": "^3.6.5",
"debug": "^4.4.0",
"error-stack-parser": "^2.0.6",
"flow-enums-runtime": "^0.0.6",
"graceful-fs": "^4.2.4",
- "hermes-parser": "0.32.0",
- "image-size": "^1.0.2",
+ "hermes-parser": "0.35.0",
"invariant": "^2.2.4",
"jest-worker": "^29.7.0",
"jsc-safe-url": "^0.2.2",
"lodash.throttle": "^4.1.1",
- "metro-babel-transformer": "0.83.3",
- "metro-cache": "0.83.3",
- "metro-cache-key": "0.83.3",
- "metro-config": "0.83.3",
- "metro-core": "0.83.3",
- "metro-file-map": "0.83.3",
- "metro-resolver": "0.83.3",
- "metro-runtime": "0.83.3",
- "metro-source-map": "0.83.3",
- "metro-symbolicate": "0.83.3",
- "metro-transform-plugins": "0.83.3",
- "metro-transform-worker": "0.83.3",
- "mime-types": "^2.1.27",
+ "metro-babel-transformer": "0.83.8",
+ "metro-cache": "0.83.8",
+ "metro-cache-key": "0.83.8",
+ "metro-config": "0.83.8",
+ "metro-core": "0.83.8",
+ "metro-file-map": "0.83.8",
+ "metro-resolver": "0.83.8",
+ "metro-runtime": "0.83.8",
+ "metro-source-map": "0.83.8",
+ "metro-symbolicate": "0.83.8",
+ "metro-transform-plugins": "0.83.8",
+ "metro-transform-worker": "0.83.8",
+ "mime-types": "^3.0.1",
"nullthrows": "^1.1.1",
"serialize-error": "^2.1.0",
"source-map": "^0.5.6",
@@ -9267,14 +9258,15 @@
}
},
"node_modules/metro-babel-transformer": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.3.tgz",
- "integrity": "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.8.tgz",
+ "integrity": "sha512-tnn0J5wzgTgTx2OJy3Cwr1y79bJz4eNgFQd+2HENOs5Vz6QOMnt05z7J+BedIo9wIbpEa0iN9U1nerxyvMRE9g==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.25.2",
"flow-enums-runtime": "^0.0.6",
- "hermes-parser": "0.32.0",
+ "hermes-parser": "0.35.0",
+ "metro-cache-key": "0.83.8",
"nullthrows": "^1.1.1"
},
"engines": {
@@ -9282,24 +9274,24 @@
}
},
"node_modules/metro-cache": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.3.tgz",
- "integrity": "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.8.tgz",
+ "integrity": "sha512-aogMG5WbKzW5000otNjYrS9hIoORzkCI1faPJK+vxQLaf2BorJKBBFe/jl2Tfsi1mZUglS2EBuBt8B3JB7MYDQ==",
"license": "MIT",
"dependencies": {
"exponential-backoff": "^3.1.1",
"flow-enums-runtime": "^0.0.6",
"https-proxy-agent": "^7.0.5",
- "metro-core": "0.83.3"
+ "metro-core": "0.83.8"
},
"engines": {
"node": ">=20.19.4"
}
},
"node_modules/metro-cache-key": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.3.tgz",
- "integrity": "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.8.tgz",
+ "integrity": "sha512-I38PtcjT4crS5HY9UQ8i6z8S7tJ2WewtPGr/OwS6FcLKfy5T/1hlTaFw+wozUZkEtNpR6Gc0oJuvuKCbSoSN5A==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6"
@@ -9309,18 +9301,18 @@
}
},
"node_modules/metro-config": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.3.tgz",
- "integrity": "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.8.tgz",
+ "integrity": "sha512-crNbNy+/B4tCne2+HjUshwvC57gNBQj+V9fFSy3lHH2RlKcLHib3Mil/SfTX8Pfh2fCY5pPuSu2OKa7YiadB+Q==",
"license": "MIT",
"dependencies": {
"connect": "^3.6.5",
"flow-enums-runtime": "^0.0.6",
"jest-validate": "^29.7.0",
- "metro": "0.83.3",
- "metro-cache": "0.83.3",
- "metro-core": "0.83.3",
- "metro-runtime": "0.83.3",
+ "metro": "0.83.8",
+ "metro-cache": "0.83.8",
+ "metro-core": "0.83.8",
+ "metro-runtime": "0.83.8",
"yaml": "^2.6.1"
},
"engines": {
@@ -9328,23 +9320,23 @@
}
},
"node_modules/metro-core": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.3.tgz",
- "integrity": "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.8.tgz",
+ "integrity": "sha512-NTyOUOQaQKvQgJG9VI2ymN6KTM7gHEqkVFhkPc9bK4BsHSTz/EaXuFBXtC+wtwINLeH9tbusL/jfsSmdEmuU7A==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6",
"lodash.throttle": "^4.1.1",
- "metro-resolver": "0.83.3"
+ "metro-resolver": "0.83.8"
},
"engines": {
"node": ">=20.19.4"
}
},
"node_modules/metro-file-map": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.3.tgz",
- "integrity": "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.8.tgz",
+ "integrity": "sha512-+W++EUuzEXIfWQEFTWQMVThzhWbnJL4gRNJ9WSHzIAM5pT7gsprUxo9+2hrfirURm/TLvrKwhq37oCECJcDSyQ==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.0",
@@ -9362,9 +9354,9 @@
}
},
"node_modules/metro-minify-terser": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.3.tgz",
- "integrity": "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.8.tgz",
+ "integrity": "sha512-7tU0J5/c7LZaZJwTlOb1xq0NepTFvGzRxigDhZOq4jSE6g0BRHmBqe7XvLH3WcRiJNGy+eshcZr34RpMjb6mmg==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6",
@@ -9375,9 +9367,9 @@
}
},
"node_modules/metro-resolver": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.3.tgz",
- "integrity": "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.8.tgz",
+ "integrity": "sha512-piU0NVTI9i37YztDVF5rtn9uxP3NebVT0xZM9NKJ9z0jbigrctUQksi3NoYIeJMvL6Wn2dgAehpcmmnfn+gUwA==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6"
@@ -9387,9 +9379,9 @@
}
},
"node_modules/metro-runtime": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.3.tgz",
- "integrity": "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.8.tgz",
+ "integrity": "sha512-f7FfeM0pamq8vrvs8aO9KvIUabbUKe0WkHFpLt6Q9yIIIsORqNFwlgJeHGraOFPU7Cxqj5yLXkJu5bT1uwDXvw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.25.0",
@@ -9400,19 +9392,18 @@
}
},
"node_modules/metro-source-map": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.3.tgz",
- "integrity": "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.8.tgz",
+ "integrity": "sha512-60Uor7bM+KsVewLkLCcZfkPFCbqjPDdoSmeBuT3+ye+ac80BuLWbbR8DpyxWpUqQeZPdaAT5ZqFgDIs8BNEcVA==",
"license": "MIT",
"dependencies": {
- "@babel/traverse": "^7.25.3",
- "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3",
- "@babel/types": "^7.25.2",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
"flow-enums-runtime": "^0.0.6",
"invariant": "^2.2.4",
- "metro-symbolicate": "0.83.3",
+ "metro-symbolicate": "0.83.8",
"nullthrows": "^1.1.1",
- "ob1": "0.83.3",
+ "ob1": "0.83.8",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
},
@@ -9421,14 +9412,14 @@
}
},
"node_modules/metro-symbolicate": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.3.tgz",
- "integrity": "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.8.tgz",
+ "integrity": "sha512-ZLrbqOqQ+m+Mpv7zo65XEXkNqVYvgUbY7tIsb9e1zSSmU/4C3D6DjaJvRHqcAdl0mkg8TI/csKooAEa5xcZNwg==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6",
"invariant": "^2.2.4",
- "metro-source-map": "0.83.3",
+ "metro-source-map": "0.83.8",
"nullthrows": "^1.1.1",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
@@ -9441,15 +9432,15 @@
}
},
"node_modules/metro-transform-plugins": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.3.tgz",
- "integrity": "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.8.tgz",
+ "integrity": "sha512-9JRPkvi+m0QH2Y/w5RjCF9mHqOUNFpMFLDDLhKUjhcKESh8Wm3HKDdHXHVldTN1lTToCIabv81nF0zyJzKEJ5g==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.25.2",
- "@babel/generator": "^7.25.0",
- "@babel/template": "^7.25.0",
- "@babel/traverse": "^7.25.3",
+ "@babel/generator": "^7.29.1",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
"flow-enums-runtime": "^0.0.6",
"nullthrows": "^1.1.1"
},
@@ -9458,29 +9449,83 @@
}
},
"node_modules/metro-transform-worker": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.3.tgz",
- "integrity": "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.8.tgz",
+ "integrity": "sha512-Pa2hOfhUmWpI/dmkhsLq8uGyFHK2opoEK7j/YCiRtqNSe0YzzxYguXTNgg8AMiuZfc9LPcB1AhGENS10O5wcIw==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.25.2",
- "@babel/generator": "^7.25.0",
- "@babel/parser": "^7.25.3",
- "@babel/types": "^7.25.2",
+ "@babel/generator": "^7.29.1",
+ "@babel/parser": "^7.29.0",
+ "@babel/types": "^7.29.0",
"flow-enums-runtime": "^0.0.6",
- "metro": "0.83.3",
- "metro-babel-transformer": "0.83.3",
- "metro-cache": "0.83.3",
- "metro-cache-key": "0.83.3",
- "metro-minify-terser": "0.83.3",
- "metro-source-map": "0.83.3",
- "metro-transform-plugins": "0.83.3",
+ "metro": "0.83.8",
+ "metro-babel-transformer": "0.83.8",
+ "metro-cache": "0.83.8",
+ "metro-cache-key": "0.83.8",
+ "metro-minify-terser": "0.83.8",
+ "metro-source-map": "0.83.8",
+ "metro-transform-plugins": "0.83.8",
"nullthrows": "^1.1.1"
},
"engines": {
"node": ">=20.19.4"
}
},
+ "node_modules/metro/node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/metro/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/metro/node_modules/mime-types": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
+ "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/metro/node_modules/negotiator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz",
+ "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
@@ -9537,9 +9582,9 @@
}
},
"node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -9608,9 +9653,9 @@
}
},
"node_modules/nanoid": {
- "version": "3.3.11",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
- "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "version": "3.3.20",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz",
+ "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==",
"funding": [
{
"type": "github",
@@ -9664,9 +9709,9 @@
"license": "MIT"
},
"node_modules/node-forge": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz",
- "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
+ "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==",
"license": "(BSD-3-Clause OR GPL-2.0)",
"engines": {
"node": ">= 6.13.0"
@@ -9679,10 +9724,13 @@
"license": "MIT"
},
"node_modules/node-releases": {
- "version": "2.0.27",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
- "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
- "license": "MIT"
+ "version": "2.0.60",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.60.tgz",
+ "integrity": "sha512-OmO8+GM1JUZqXET720VrJCwkjUCXmCMQm0Z3UDDRbfNLHS4NEAvY60j5jiFv0tkKw2PNNlqOLhahVmwJIOLDIQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/normalize-path": {
"version": "3.0.0",
@@ -9727,9 +9775,9 @@
"license": "MIT"
},
"node_modules/ob1": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.3.tgz",
- "integrity": "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.8.tgz",
+ "integrity": "sha512-pk7el+eTOzfSKMAY4QBiiwKzegXn633JQj13y+pW5E5IdS+yV2CfDJ9Hf20K/LKy8nCrP9dAmd7XOk52OJxifA==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6"
@@ -10205,9 +10253,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -10239,15 +10287,6 @@
"node": ">=10.4.0"
}
},
- "node_modules/plist/node_modules/@xmldom/xmldom": {
- "version": "0.8.11",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
- "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==",
- "license": "MIT",
- "engines": {
- "node": ">=10.0.0"
- }
- },
"node_modules/plist/node_modules/xmlbuilder": {
"version": "15.1.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
@@ -10277,9 +10316,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.49",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
- "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
+ "version": "8.5.32",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.32.tgz",
+ "integrity": "sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==",
"funding": [
{
"type": "opencollective",
@@ -10296,9 +10335,9 @@
],
"license": "MIT",
"dependencies": {
- "nanoid": "^3.3.7",
+ "nanoid": "^3.3.20",
"picocolors": "^1.1.1",
- "source-map-js": "^1.2.1"
+ "source-map-js": "^1.2.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -10428,15 +10467,6 @@
"qrcode-terminal": "bin/qrcode-terminal.js"
}
},
- "node_modules/queue": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
- "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
- "license": "MIT",
- "dependencies": {
- "inherits": "~2.0.3"
- }
- },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -10659,9 +10689,9 @@
}
},
"node_modules/react-native/node_modules/ws": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
- "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
+ "version": "6.2.6",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.6.tgz",
+ "integrity": "sha512-XTrf1gv7kXoVf1hbC3PAyAiPgR8Wz1blcrYIjEsUmr08BLksT41R8KbjmS9408C2ERx7v1JDLD/BkpLEttjfKA==",
"license": "MIT",
"dependencies": {
"async-limiter": "~1.0.0"
@@ -11254,9 +11284,9 @@
}
},
"node_modules/shell-quote": {
- "version": "1.8.3",
- "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
- "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.12.0.tgz",
+ "integrity": "sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -11398,9 +11428,9 @@
}
},
"node_modules/source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
+ "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -11804,9 +11834,9 @@
}
},
"node_modules/tar": {
- "version": "7.5.7",
- "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz",
- "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==",
+ "version": "7.5.22",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz",
+ "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/fs-minipass": "^4.0.0",
@@ -11980,9 +12010,9 @@
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"license": "MIT",
"engines": {
"node": ">=12"
@@ -12219,9 +12249,9 @@
}
},
"node_modules/undici": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz",
- "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==",
+ "version": "6.29.1",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.29.1.tgz",
+ "integrity": "sha512-EvRlUt/QqAEvXdQeRMYUfwOQsfzpDztykrG2owGEE/rBOBoYv9uF39ZzsNDh4lTFHhTr2XOZjKkYgueD12ZmGA==",
"license": "MIT",
"engines": {
"node": ">=18.17"
@@ -12705,9 +12735,9 @@
"license": "ISC"
},
"node_modules/ws": {
- "version": "7.5.10",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
- "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
+ "version": "7.5.13",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz",
+ "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
@@ -12785,9 +12815,9 @@
"license": "ISC"
},
"node_modules/yaml": {
- "version": "2.8.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
- "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz",
+ "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
diff --git a/apps/expo-example/package.json b/apps/expo-example/package.json
index d6a71d7b..41cc574f 100644
--- a/apps/expo-example/package.json
+++ b/apps/expo-example/package.json
@@ -23,5 +23,23 @@
"eslint": "^8.19.0",
"eslint-config-expo": "^10.0.0"
},
+ "overrides": {
+ "@xmldom/xmldom": "^0.8.15",
+ "metro": "0.83.8",
+ "metro-babel-transformer": "0.83.8",
+ "metro-cache": "0.83.8",
+ "metro-cache-key": "0.83.8",
+ "metro-config": "0.83.8",
+ "metro-core": "0.83.8",
+ "metro-file-map": "0.83.8",
+ "metro-minify-terser": "0.83.8",
+ "metro-resolver": "0.83.8",
+ "metro-runtime": "0.83.8",
+ "metro-source-map": "0.83.8",
+ "metro-symbolicate": "0.83.8",
+ "metro-transform-plugins": "0.83.8",
+ "metro-transform-worker": "0.83.8",
+ "postcss": "^8.5.23"
+ },
"private": true
}
diff --git a/docs/UAPP.md b/docs/UAPP.md
new file mode 100644
index 00000000..ffb22dad
--- /dev/null
+++ b/docs/UAPP.md
@@ -0,0 +1,177 @@
+# UAPP (Unified Android Push Provisioning) for Android
+
+## What is UAPP?
+
+UAPP (Unified Android Push Provisioning) is an enhanced security flow for Google Wallet that requires encrypted payment credentials during card provisioning. Instead of providing only the TSP Opaque Payment Card (OPC), your backend must also generate a Google Opaque Payment Card (Google OPC) using Google's encryption keys. It allows users to provision cards to Google Wallet and save their cards to their Google Account.
+
+This library handles the UAPP flow automatically. You just need to set up a handler that communicates with your backend to retrieve the encrypted credentials.
+
+> [!IMPORTANT]
+> Please familiarize yourself with [official Google docs](https://developers.google.com/pay/issuers/apis/push-provisioning/android) before starting the implementation!
+
+## How UAPP Works
+
+1. User initiates card provisioning by calling `addCardToGoogleWallet()`
+2. During provisioning, Google Wallet requests encrypted credentials
+3. The library automatically triggers your registered handler with provisioning details
+4. Your handler calls your backend with the server session ID and OPC
+5. Your backend generates the Google OPC using Google's encryption keys
+6. Your handler returns both the TSP OPC and Google OPC
+7. The library automatically provides these credentials to Google Wallet
+8. Provisioning continues seamlessly
+
+## Setup
+
+UAPP is always enabled on Android, so `addCardToGoogleWallet()` requires a payment credentials handler as its second argument:
+
+```typescript
+import { addCardToGoogleWallet } from '@expensify/react-native-wallet';
+
+// Define your handler function
+const handlePaymentCredentials = async (data) => {
+ const { requestId, serverSessionId, walletId, opaquePaymentCard } = data;
+
+ // Call your backend to get encrypted credentials
+ const response = await fetch('https://your-backend.com/api/wallet/credentials', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ serverSessionId,
+ opaquePaymentCard,
+ walletId,
+ }),
+ });
+
+ const credentials = await response.json();
+
+ // Return the credentials - library will automatically send them to Google Wallet
+ return {
+ opaquePaymentCard: credentials.tspOpc,
+ googleOpaquePaymentCard: credentials.googleOpc,
+ };
+};
+
+// Pass the handler when adding a card
+const status = await addCardToGoogleWallet(cardData, handlePaymentCredentials);
+```
+
+## Backend Implementation
+
+> [!NOTE]
+> Please refer to the [official Google documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/upgrade_to_upp#generate_the_google_opc_from_the_issuers_backend) while implementing the backend for UAPP Push Provisioning.
+
+Your backend needs to:
+
+1. Receive the `serverSessionId`, `opaquePaymentCard`, `walletId`, and `tokenRequestorId`
+2. Call Google's UAPP API with these parameters
+3. Use Google's encryption keys to generate the Google OPC
+4. Return both the TSP OPC and Google OPC to your app. For Visa tokenization on Fitbit, the TSP OPC must include the `tokenRequestorId`, or the request fails
+
+Example backend response:
+```json
+{
+ "tspOpc": "original-opaque-payment-card-from-tsp",
+ "googleOpc": "encrypted-google-opaque-payment-card"
+}
+```
+
+## Related Data Types
+
+### `onPaymentCredentialsRequestPayload`
+
+Payload received when Google Wallet requests payment credentials during UAPP provisioning:
+
+```typescript
+{
+ requestId: string; // Unique identifier for this request
+ serverSessionId: string; // Session ID from Google (crucial for backend)
+ walletId: string; // Google Wallet ID
+ tokenRequestorId: string | null; // Token Requestor ID of the tokenization target (needed for Visa on Fitbit)
+ opaquePaymentCard: string; // Original OPC from TSP
+}
+```
+
+### `AndroidPaymentCredentialsResponse`
+
+Response object containing encrypted payment credentials for UAPP flow:
+
+```typescript
+{
+ opaquePaymentCard: string; // TSP Opaque Payment Card
+ googleOpaquePaymentCard: string; // Encrypted Google OPC
+}
+```
+
+## Required Data Elements
+
+For UAPP provisioning, you need:
+
+- **Opaque Payment Card** (OPC) - a binary blob of information Google Pay receives from the issuer app that could be presented to TSP to receive a token.
+- **Google Opaque Payment Card** (Google OPC) - an encrypted version of the OPC required for UAPP (Unified Android Push Provisioning) flow. This is generated by your backend using Google's encryption keys during the provisioning process.
+
+## API Reference
+
+### `addCardToGoogleWallet()`
+
+Initiates the Google Wallet card provisioning flow with UAPP support.
+
+**Parameters:**
+- `cardData: AndroidCardData` - Card information required for provisioning
+- `handlePaymentCredentialsGeneration: (data: onPaymentCredentialsRequestPayload) => Promise` - Handler function that receives the payment credentials request and returns encrypted credentials from your backend
+
+**Returns:** `Promise` - Status of the tokenization process ('success', 'canceled', or 'error')
+
+The handler is only called when Google Wallet requests a Google OPC, and it must return both `opaquePaymentCard` and `googleOpaquePaymentCard`. If it throws, returns no Google OPC, or does not resolve within 60 seconds, the request is reported to Google Wallet as failed (`GeneratePaymentCredentialsException.UNKNOWN_ERROR`). Google does not guarantee a fallback to TSP-only provisioning in that case, so do not rely on the card being added.
+
+**Platform:** Android only
+
+**Example:**
+```typescript
+const status = await addCardToGoogleWallet(
+ cardData,
+ async (data) => {
+ const credentials = await fetchCredentialsFromBackend(data);
+ return credentials;
+ }
+);
+```
+
+### AndroidCardData Optional Fields
+
+When using UAPP with `addCardToGoogleWallet()`, the `AndroidCardData` object supports two optional boolean fields:
+
+- **`isVirtualCard?: boolean`** - Set to `true` if provisioning a virtual card (digitally-generated card number linked to a physical card account). Virtual cards provide enhanced security for online transactions.
+
+- **`isBounceProvisioned?: boolean`** - Set to `true` if the card was initially provisioned through Google Wallet and is now being completed through your app. This is used in bounce provisioning flows where users start in Google Wallet and are redirected to your app for additional verification.
+
+For more details, see the [AndroidCardData Optional Fields](../README.md#androidcarddata-optional-fields) section in the main documentation.
+
+## Testing
+
+> [!WARNING]
+> **UAPP implementation must be tested before production use.** Failure to provide required test evidence may result in revoking access to your production environment. Please make sure your implementation is thoroughly tested and approved by Google.
+
+When implementing UAPP, ensure your app meets all Google testing criteria:
+
+1. **UAPP Flow Testing** - Verify that payment credentials are correctly generated and transmitted during provisioning
+2. **Backend Integration** - Ensure your backend correctly generates Google OPC using Google's encryption keys
+3. **Error Handling** - Test timeout scenarios and credential validation failures
+4. **Security Compliance** - Verify secure handling of encrypted payment credentials
+
+For comprehensive testing requirements, refer to:
+- [Google Push Provisioning Testing Criteria](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases)
+- [UAPP-specific Testing Guidelines](https://developers.google.com/pay/issuers/apis/push-provisioning/android/upgrade_to_upp#functional_test_cases)
+- Main documentation [Publishing your app](../README.md#publishing-your-app) section
+
+## Troubleshooting
+
+### Provisioning fails with timeout
+
+If the backend request takes too long, Google Wallet may timeout. Ensure your backend responds within a reasonable timeframe (typically < 10 seconds).
+
+### Invalid credentials error
+
+Verify that:
+1. Your backend is correctly generating the Google OPC using Google's encryption keys
+2. Both `opaquePaymentCard` and `googleOpaquePaymentCard` are returned in the response
+3. The credentials match the card being provisioned
diff --git a/ios/RNWallet.mm b/ios/RNWallet.mm
index 4981b78a..a4d43022 100644
--- a/ios/RNWallet.mm
+++ b/ios/RNWallet.mm
@@ -42,27 +42,35 @@ - (instancetype)init {
reject:(RCTPromiseRejectBlock)reject)
{
@try {
- NSDictionary *cardDataDict = nil;
+ NSMutableDictionary *cardDataDict = nil;
+ NSString *primaryAccountIdentifier = nil;
#ifdef RCT_NEW_ARCH_ENABLED
- cardDataDict = @{
+ cardDataDict = [@{
@"network": [self safeString:cardData.network()],
@"cardHolderName": [self safeString:cardData.cardHolderName()],
@"lastDigits": [self safeString:cardData.lastDigits()],
@"cardDescription": [self safeString:cardData.cardDescription()],
- };
+ } mutableCopy];
+ primaryAccountIdentifier = [self safeString:cardData.primaryAccountIdentifier()];
#else
- cardDataDict = @{
+ cardDataDict = [@{
@"network": [self safeString:cardData[@"network"]],
@"cardHolderName": [self safeString:cardData[@"cardHolderName"]],
@"lastDigits": [self safeString:cardData[@"lastDigits"]],
@"cardDescription": [self safeString:cardData[@"cardDescription"]],
- };
+ } mutableCopy];
+ id rawIdentifier = cardData[@"primaryAccountIdentifier"];
+ primaryAccountIdentifier = [self safeString:[rawIdentifier isKindOfClass:[NSString class]] ? rawIdentifier : nil];
#endif
+ if (primaryAccountIdentifier.length > 0) {
+ cardDataDict[@"primaryAccountIdentifier"] = primaryAccountIdentifier;
+ }
+
dispatch_async(dispatch_get_main_queue(), ^{
[self->walletManager IOSPresentAddPaymentPassViewWithCardData:cardDataDict completion:^(OperationResult result, NSDictionary* data) {
- [self handleWalletResponse:result data:data completedBlock:resolve errorPrefix:@"present_payment_pass_view_failed" defaultErrorMessage:@"Failed to present the payment pass view" rejecter:reject];
+ [self handleWalletResponse:result data:data resolveValue:data completedBlock:resolve errorPrefix:@"present_payment_pass_view_failed" defaultErrorMessage:@"Failed to present the payment pass view" rejecter:reject];
}];
});
} @catch (NSException *exception) {
@@ -98,7 +106,7 @@ - (instancetype)init {
dispatch_async(dispatch_get_main_queue(), ^{
[self->walletManager IOSHandleAddPaymentPassResponseWithPayload:payloadDict completion:^(OperationResult result, NSDictionary* data) {
- [self handleWalletResponse:result data:data completedBlock:resolve errorPrefix:@"add_card_failed" defaultErrorMessage:@"Failed to add the card to the wallet" rejecter:reject];
+ [self handleWalletResponse:result data:data resolveValue:data completedBlock:resolve errorPrefix:@"add_card_failed" defaultErrorMessage:@"Failed to add the card to the wallet" rejecter:reject];
}];
});
} @catch (NSException *exception) {
@@ -123,6 +131,64 @@ - (instancetype)init {
resolve([walletManager getCardStatusByIdentifierWithIdentifier:identifier]);
}
+RCT_REMAP_METHOD(listAppleWalletPasses,
+ listAppleWalletPasses:(RCTPromiseResolveBlock)resolve
+ reject:(RCTPromiseRejectBlock)reject)
+{
+ resolve([walletManager listAppleWalletPasses]);
+}
+
+RCT_REMAP_METHOD(activateAppleWalletPass,
+#ifdef RCT_NEW_ARCH_ENABLED
+ activateAppleWalletPass:(JS::NativeWallet::IOSPassActivationData &)passData
+#else
+ activateAppleWalletPass:(NSDictionary *)passData
+#endif
+ resolve:(RCTPromiseResolveBlock)resolve
+ reject:(RCTPromiseRejectBlock)reject)
+{
+ @try {
+ NSMutableDictionary *passDataDict = nil;
+
+#ifdef RCT_NEW_ARCH_ENABLED
+ passDataDict = [@{
+ @"passTypeIdentifier": [self safeString:passData.passTypeIdentifier()],
+ @"serialNumber": [self safeString:passData.serialNumber()],
+ @"activationData": [self safeString:passData.activationData()],
+ } mutableCopy];
+ std::optional isRemote = passData.isRemote();
+ if (isRemote.has_value()) {
+ passDataDict[@"isRemote"] = @(isRemote.value());
+ }
+#else
+ passDataDict = [@{
+ @"passTypeIdentifier": [self safeString:passData[@"passTypeIdentifier"]],
+ @"serialNumber": [self safeString:passData[@"serialNumber"]],
+ @"activationData": [self safeString:passData[@"activationData"]],
+ } mutableCopy];
+ id rawIsRemote = passData[@"isRemote"];
+ if ([rawIsRemote isKindOfClass:[NSNumber class]]) {
+ passDataDict[@"isRemote"] = rawIsRemote;
+ }
+#endif
+
+ [self->walletManager activateAppleWalletPassWithPassData:passDataDict completion:^(OperationResult result, NSDictionary* data) {
+ [self handleWalletResponse:result data:data resolveValue:@([data[@"success"] boolValue]) completedBlock:resolve errorPrefix:@"activate_card_failed" defaultErrorMessage:@"Failed to activate the Apple Wallet pass" rejecter:reject];
+ }];
+ } @catch (NSException *exception) {
+ [self rejectWithErrorType:@"activate_card_failed" code:500 description:exception.reason ?: @"An unexpected error occurred." rejecter:reject];
+ }
+}
+
+RCT_REMAP_METHOD(canAddCardToAppleWallet,
+ canAddCardToAppleWallet:(NSString *)primaryAccountIdentifier
+ lastDigits:(NSString *)lastDigits
+ resolve:(RCTPromiseResolveBlock)resolve
+ reject:(RCTPromiseRejectBlock)reject)
+{
+ resolve(@([walletManager canAddCardToAppleWalletWithPrimaryAccountIdentifier:primaryAccountIdentifier lastDigits:lastDigits]));
+}
+
- (void)addCardToGoogleWallet:
#ifdef RCT_NEW_ARCH_ENABLED
(JS::NativeWallet::AndroidCardData &)cardData
@@ -135,6 +201,36 @@ - (void)addCardToGoogleWallet:
// no-op
}
+- (void)hasEligibleTokenizationTarget:(NSString *)last4Digits
+ network:(NSString *)network
+ issuerName:(NSString *)issuerName
+ resolve:(RCTPromiseResolveBlock)resolve
+ reject:(RCTPromiseRejectBlock)reject
+{
+ // no-op
+}
+
+- (void)AndroidProvidePaymentCredentials:(NSString *)requestId
+ responseData:
+#ifdef RCT_NEW_ARCH_ENABLED
+ (JS::NativeWallet::AndroidPaymentCredentialsResponse &)responseData
+#else
+ (NSDictionary *)responseData
+#endif
+ resolve:(RCTPromiseResolveBlock)resolve
+ reject:(RCTPromiseRejectBlock)reject
+{
+ // no-op
+}
+
+- (void)AndroidRejectPaymentCredentials:(NSString *)requestId
+ errorMessage:(NSString *)errorMessage
+ resolve:(RCTPromiseResolveBlock)resolve
+ reject:(RCTPromiseRejectBlock)reject
+{
+ // no-op
+}
+
- (void)getSecureWalletInfo:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
// no-op
}
@@ -163,12 +259,13 @@ - (void)rejectWithErrorType:(NSString *)type
- (void)handleWalletResponse:(OperationResult)result
data:(NSDictionary *)data
+ resolveValue:(id)resolveValue
completedBlock:(RCTPromiseResolveBlock)resolve
errorPrefix:(NSString *)errorPrefix
defaultErrorMessage:(NSString *)defaultErrorMsg
rejecter:(RCTPromiseRejectBlock)reject {
if (result < 3) {
- resolve(data);
+ resolve(resolveValue);
} else {
NSString *errorMessage = data[@"errorMessage"] ?: defaultErrorMsg ?: @"Operation failed";
[self rejectWithErrorType:errorPrefix code:1001 description:errorMessage rejecter:reject];
diff --git a/ios/WalletManager.swift b/ios/WalletManager.swift
index 6b3e4c35..6e5c8c7e 100644
--- a/ios/WalletManager.swift
+++ b/ios/WalletManager.swift
@@ -21,6 +21,8 @@ open class WalletManager: UIViewController {
private var addPaymentPassCompletionHandler: (CompletionHandler)?
private var addPassHandler: ((PKAddPaymentPassRequest) -> Void)?
+
+ private var addPassPrimaryAccountIdentifier: String?
@objc public var packageName = "react-native-wallet"
@@ -111,10 +113,21 @@ open class WalletManager: UIViewController {
configuration.cardholderName = card.cardHolderName
configuration.primaryAccountSuffix = card.lastDigits
configuration.localizedDescription = String(card.cardDescription)
+ let primaryAccountIdentifier = card.primaryAccountIdentifier.map {
+ resolvedPrimaryAccountIdentifier($0, lastDigits: card.lastDigits)
+ }
+ if let primaryAccountIdentifier = primaryAccountIdentifier {
+ configuration.primaryAccountIdentifier = primaryAccountIdentifier
+ }
guard let enrollViewController = PKAddPaymentPassViewController(requestConfiguration: configuration, delegate: self) else {
+ let alreadyOnEveryDevice = primaryAccountIdentifier.map {
+ !passLibrary.canAddSecureElementPass(primaryAccountIdentifier: $0)
+ } ?? false
completion(.error, [
- "errorMessage": "InApp enrollment controller configuration fails"
+ "errorMessage": alreadyOnEveryDevice
+ ? "This card has already been added to all available devices."
+ : "InApp enrollment controller configuration fails"
])
return
}
@@ -134,6 +147,7 @@ open class WalletManager: UIViewController {
self.presentAddPaymentPassCompletionHandler = nil
self.addPaymentPassCompletionHandler = nil
self.addPassHandler = nil
+ self.addPassPrimaryAccountIdentifier = nil
let errorResponse: NSDictionary = [
"errorMessage": "EnrollViewController is no longer presented."
@@ -150,6 +164,7 @@ open class WalletManager: UIViewController {
self.presentAddPaymentPassCompletionHandler = completion
self.addPassViewController = enrollViewController
+ self.addPassPrimaryAccountIdentifier = primaryAccountIdentifier
presentingViewController.present(enrollViewController, animated: true, completion: nil)
}
}
@@ -212,10 +227,223 @@ open class WalletManager: UIViewController {
return pass.primaryAccountIdentifier == identifier as String
}
}
+
+ @objc public func listAppleWalletPasses() -> [NSDictionary] {
+ let localPasses = passLibrary.passes(of: .secureElement).compactMap { pass -> NSDictionary? in
+ guard pass.isRemotePass == false,
+ let secureElementPass = pass.secureElementPass else {
+ return nil
+ }
+
+ return makeAppleWalletPassDictionary(
+ passTypeIdentifier: pass.passTypeIdentifier,
+ serialNumber: pass.serialNumber,
+ primaryAccountIdentifier: secureElementPass.primaryAccountIdentifier,
+ lastDigits: secureElementPass.primaryAccountNumberSuffix,
+ activationState: secureElementPass.passActivationState.rawValue,
+ isRemote: pass.isRemotePass
+ )
+ }
+
+ let remotePasses = passLibrary.remoteSecureElementPasses.map { pass in
+ makeAppleWalletPassDictionary(
+ passTypeIdentifier: pass.passTypeIdentifier,
+ serialNumber: pass.serialNumber,
+ primaryAccountIdentifier: pass.primaryAccountIdentifier,
+ lastDigits: pass.primaryAccountNumberSuffix,
+ activationState: pass.passActivationState.rawValue,
+ isRemote: true
+ )
+ }
+
+ return localPasses + remotePasses
+ }
+
+ @objc public func activateAppleWalletPass(passData: NSDictionary, completion: @escaping CompletionHandler) {
+ guard passLibrary.isSecureElementPassActivationAvailable else {
+ completion(.error, [
+ "errorMessage": "Secure Element pass activation is not available for this device"
+ ])
+ return
+ }
+
+ guard
+ let passTypeIdentifier = passData["passTypeIdentifier"] as? String,
+ !passTypeIdentifier.isEmpty,
+ let serialNumber = passData["serialNumber"] as? String,
+ !serialNumber.isEmpty,
+ let activationDataString = passData["activationData"] as? String,
+ !activationDataString.isEmpty
+ else {
+ completion(.error, [
+ "errorMessage": "Invalid pass activation data"
+ ])
+ return
+ }
+
+ let isRemote = passData["isRemote"] as? Bool
+
+ guard let activationData = Data(base64Encoded: activationDataString) else {
+ completion(.error, [
+ "errorMessage": "activationData must be a valid base64 encoded string"
+ ])
+ return
+ }
+
+ guard let secureElementPass = findSecureElementPass(
+ passTypeIdentifier: passTypeIdentifier,
+ serialNumber: serialNumber,
+ isRemote: isRemote
+ ) else {
+ completion(.error, [
+ "errorMessage": "Secure Element pass not found"
+ ])
+ return
+ }
+
+ if secureElementPass.passActivationState == .activated {
+ completion(.completed, ["success": true])
+ return
+ }
+
+ guard secureElementPass.passActivationState == .requiresActivation else {
+ completion(.error, [
+ "errorMessage": "Secure Element pass is not eligible for activation. Current state: \(secureElementPass.passActivationState.rawValue)"
+ ])
+ return
+ }
+
+ passLibrary.activate(secureElementPass, activationData: activationData) { success, error in
+ if let error = error {
+ completion(.error, [
+ "errorMessage": error.localizedDescription
+ ])
+ return
+ }
+
+ completion(.completed, ["success": success])
+ }
+ }
+
+ @objc public func canAddCardToAppleWallet(primaryAccountIdentifier: NSString, lastDigits: NSString) -> Bool {
+ let suffix = lastDigits as String
+ let resolved = suffix.isEmpty
+ ? primaryAccountIdentifier as String
+ : resolvedPrimaryAccountIdentifier(primaryAccountIdentifier as String, lastDigits: suffix)
+ return passLibrary.canAddSecureElementPass(primaryAccountIdentifier: resolved)
+ }
+
+ private func provisioningTargetDevice(for primaryAccountIdentifier: String?) -> ProvisioningDeviceType {
+ guard let primaryAccountIdentifier = primaryAccountIdentifier else {
+ return .unknown
+ }
+
+ let onPhone = hasProvisionedPass(identifier: primaryAccountIdentifier, in: passLibrary.passes(of: .secureElement))
+ let onWatch = hasProvisionedPass(identifier: primaryAccountIdentifier, in: passLibrary.remoteSecureElementPasses)
+
+ if onPhone && !onWatch {
+ return .watch
+ }
+ if onWatch && !onPhone {
+ return .phone
+ }
+ return .unknown
+ }
+
+ private func resolvedPrimaryAccountIdentifier(_ identifier: String, lastDigits: String) -> String {
+ let passes = allSecureElementPasses()
+ if passes.contains(where: { $0.primaryAccountIdentifier == identifier }) {
+ return identifier
+ }
+
+ guard !lastDigits.isEmpty else {
+ return identifier
+ }
+
+ let suffixMatches = passes.filter {
+ $0.passActivationState != .deactivated && $0.primaryAccountNumberSuffix.hasSuffix(lastDigits)
+ }
+ let identifiers = Set(suffixMatches.map(\.primaryAccountIdentifier))
+ if identifiers.count == 1, let resolvedIdentifier = identifiers.first {
+ return resolvedIdentifier
+ }
+ return identifier
+ }
+
+ private func allSecureElementPasses() -> [PKSecureElementPass] {
+ let localPasses = passLibrary.passes(of: .secureElement)
+ .filter { !$0.isRemotePass }
+ .compactMap(\.secureElementPass)
+ return localPasses + passLibrary.remoteSecureElementPasses
+ }
+
+ private func hasProvisionedPass(identifier: String, in passes: [PKPass]) -> Bool {
+ passes.contains { pass in
+ guard !pass.isRemotePass, let securePass = pass.secureElementPass else {
+ return false
+ }
+ return isProvisioned(securePass, identifier: identifier)
+ }
+ }
+
+ private func hasProvisionedPass(identifier: String, in passes: [PKSecureElementPass]) -> Bool {
+ passes.contains { isProvisioned($0, identifier: identifier) }
+ }
+
+ private func isProvisioned(_ pass: PKSecureElementPass, identifier: String) -> Bool {
+ pass.primaryAccountIdentifier == identifier && pass.passActivationState != .deactivated
+ }
private func isPassKitAvailable() -> Bool {
return PKAddPaymentPassViewController.canAddPaymentPass()
}
+
+ private func findSecureElementPass(passTypeIdentifier: String, serialNumber: String, isRemote: Bool?) -> PKSecureElementPass? {
+ if isRemote == true {
+ return passLibrary.remoteSecureElementPasses.first { pass in
+ pass.passTypeIdentifier == passTypeIdentifier && pass.serialNumber == serialNumber
+ }
+ }
+
+ if let pass = passLibrary.pass(withPassTypeIdentifier: passTypeIdentifier, serialNumber: serialNumber),
+ pass.isRemotePass == false {
+ return pass.secureElementPass
+ }
+
+ if isRemote == false {
+ return nil
+ }
+
+ return passLibrary.remoteSecureElementPasses.first { pass in
+ pass.passTypeIdentifier == passTypeIdentifier && pass.serialNumber == serialNumber
+ }
+ }
+
+ private func makeAppleWalletPassDictionary(
+ passTypeIdentifier: String,
+ serialNumber: String,
+ primaryAccountIdentifier: String?,
+ lastDigits: String?,
+ activationState: Int,
+ isRemote: Bool
+ ) -> NSDictionary {
+ let result = NSMutableDictionary(dictionary: [
+ "passTypeIdentifier": passTypeIdentifier,
+ "serialNumber": serialNumber,
+ "activationState": activationState,
+ "isRemote": isRemote
+ ])
+
+ if let primaryAccountIdentifier = primaryAccountIdentifier, !primaryAccountIdentifier.isEmpty {
+ result["primaryAccountIdentifier"] = primaryAccountIdentifier
+ }
+
+ if let lastDigits = lastDigits, !lastDigits.isEmpty {
+ result["lastDigits"] = lastDigits
+ }
+
+ return result
+ }
private func hideModal() {
guard let enrollVC = addPassViewController else {
@@ -261,7 +489,8 @@ extension WalletManager: PKAddPaymentPassViewControllerDelegate {
let stringCertificates = certificates.map {
$0.base64EncodedString() as NSString
}
- let reqestCardData = AddPassResponse(status: .completed, nonce: stringNonce, nonceSignature: stringNonceSignature, certificates: stringCertificates)
+ let deviceType = provisioningTargetDevice(for: addPassPrimaryAccountIdentifier)
+ let reqestCardData = AddPassResponse(status: .completed, nonce: stringNonce, nonceSignature: stringNonceSignature, certificates: stringCertificates, deviceType: deviceType)
self.addPassHandler = handler
// Retry the JS issuer callback if the user tries again to add a payment pass
@@ -293,6 +522,7 @@ extension WalletManager: PKAddPaymentPassViewControllerDelegate {
presentAddPaymentPassCompletionHandler = nil
addPaymentPassCompletionHandler = nil
addPassHandler = nil
+ addPassPrimaryAccountIdentifier = nil
let errorMessage = error?.localizedDescription ?? ""
diff --git a/ios/stucts/AddPassResponse.swift b/ios/stucts/AddPassResponse.swift
index 1df45b4b..3512e45d 100644
--- a/ios/stucts/AddPassResponse.swift
+++ b/ios/stucts/AddPassResponse.swift
@@ -1,16 +1,35 @@
import PassKit
+enum ProvisioningDeviceType: String {
+ case phone
+ case watch
+ case unknown
+}
+
struct AddPassResponse {
let status: OperationResult
let nonce: NSString?
let nonceSignature: NSString?
let certificates: [NSString]?
+ let deviceType: ProvisioningDeviceType?
+
+ init(status: OperationResult, nonce: NSString?, nonceSignature: NSString?, certificates: [NSString]?, deviceType: ProvisioningDeviceType? = nil) {
+ self.status = status
+ self.nonce = nonce
+ self.nonceSignature = nonceSignature
+ self.certificates = certificates
+ self.deviceType = deviceType
+ }
func toNSDictionary() -> NSDictionary {
if status.rawValue > 0 {
- return [
+ var response: [String: Any] = [
"status": status.rawValue,
]
+ if let deviceType = deviceType {
+ response["deviceType"] = deviceType.rawValue
+ }
+ return response as NSDictionary
}
guard let nonce = nonce,
@@ -19,12 +38,16 @@ struct AddPassResponse {
return [:]
}
- return [
+ var response: [String: Any] = [
"status": status.rawValue,
"nonce": nonce,
"nonceSignature": nonceSignature,
- "certificates": certificates
+ "certificates": certificates,
]
+ if let deviceType = deviceType {
+ response["deviceType"] = deviceType.rawValue
+ }
+ return response as NSDictionary
}
}
diff --git a/ios/stucts/CardInfo.swift b/ios/stucts/CardInfo.swift
index c02a3c7c..13499153 100644
--- a/ios/stucts/CardInfo.swift
+++ b/ios/stucts/CardInfo.swift
@@ -5,6 +5,7 @@ struct CardInfo {
let cardHolderName: String
let lastDigits: String
let cardDescription: String
+ let primaryAccountIdentifier: String?
init(cardData: NSDictionary) throws {
guard let networkString = cardData["network"] as? String, !networkString.isEmpty,
@@ -19,6 +20,11 @@ struct CardInfo {
self.cardHolderName = cardHolderName
self.lastDigits = lastDigits
self.cardDescription = cardDescription
+ if let identifier = cardData["primaryAccountIdentifier"] as? String, !identifier.isEmpty {
+ self.primaryAccountIdentifier = identifier
+ } else {
+ self.primaryAccountIdentifier = nil
+ }
}
private static func getNetwork(from identifier: String) -> PKPaymentNetwork? {
diff --git a/package-lock.json b/package-lock.json
index 812ab2b3..6a6ad40d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@expensify/react-native-wallet",
- "version": "0.1.41",
+ "version": "0.2.23",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@expensify/react-native-wallet",
- "version": "0.1.41",
+ "version": "0.2.23",
"license": "MIT",
"workspaces": [
"apps/common-app",
@@ -1560,9 +1560,9 @@
}
},
"node_modules/@babel/plugin-transform-modules-systemjs": {
- "version": "7.29.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz",
- "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==",
+ "version": "7.29.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.4.tgz",
+ "integrity": "sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2329,25 +2329,6 @@
"node": ">=6.9.0"
}
},
- "node_modules/@babel/traverse--for-generate-function-map": {
- "name": "@babel/traverse",
- "version": "7.29.0",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
- "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.29.0",
- "@babel/generator": "^7.29.0",
- "@babel/helper-globals": "^7.28.0",
- "@babel/parser": "^7.29.0",
- "@babel/template": "^7.28.6",
- "@babel/types": "^7.29.0",
- "debug": "^4.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
"node_modules/@babel/types": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
@@ -2455,9 +2436,9 @@
"license": "Python-2.0"
},
"node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2466,9 +2447,9 @@
}
},
"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+ "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2479,9 +2460,9 @@
}
},
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -2590,6 +2571,29 @@
"xml2js": "0.6.0"
}
},
+ "node_modules/@expo/config-plugins/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/brace-expansion": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/@expo/config-plugins/node_modules/glob": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.2.tgz",
@@ -2619,16 +2623,16 @@
}
},
"node_modules/@expo/config-plugins/node_modules/minimatch": {
- "version": "10.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
- "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
- "@isaacs/brace-expansion": "^5.0.1"
+ "brace-expansion": "^5.0.8"
},
"engines": {
- "node": "20 || >=22"
+ "node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -2691,6 +2695,29 @@
"@babel/highlight": "^7.10.4"
}
},
+ "node_modules/@expo/config/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@expo/config/node_modules/brace-expansion": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/@expo/config/node_modules/glob": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.2.tgz",
@@ -2720,16 +2747,16 @@
}
},
"node_modules/@expo/config/node_modules/minimatch": {
- "version": "10.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
- "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
- "@isaacs/brace-expansion": "^5.0.1"
+ "brace-expansion": "^5.0.8"
},
"engines": {
- "node": "20 || >=22"
+ "node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -2879,18 +2906,43 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/@expo/fingerprint/node_modules/glob/node_modules/minimatch": {
- "version": "10.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
- "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
+ "node_modules/@expo/fingerprint/node_modules/glob/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"dev": true,
- "license": "BlueOak-1.0.0",
"peer": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@expo/fingerprint/node_modules/glob/node_modules/brace-expansion": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
+ "dev": true,
+ "peer": true,
+ "license": "MIT",
"dependencies": {
- "@isaacs/brace-expansion": "^5.0.1"
+ "balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
+ }
+ },
+ "node_modules/@expo/fingerprint/node_modules/glob/node_modules/minimatch": {
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
+ "dev": true,
+ "peer": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.8"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -3403,9 +3455,9 @@
"peer": true
},
"node_modules/@expo/xcpretty/node_modules/js-yaml": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+ "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -3450,9 +3502,9 @@
}
},
"node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3461,9 +3513,9 @@
}
},
"node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -3512,29 +3564,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/@isaacs/balanced-match": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
- "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "20 || >=22"
- }
- },
- "node_modules/@isaacs/brace-expansion": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz",
- "integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@isaacs/balanced-match": "^4.0.1"
- },
- "engines": {
- "node": "20 || >=22"
- }
- },
"node_modules/@isaacs/fs-minipass": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
@@ -4120,6 +4149,19 @@
"eslint-scope": "5.1.1"
}
},
+ "node_modules/@nodable/entities": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.1.0.tgz",
+ "integrity": "sha512-LsS/DjHr+uDM647Gru/cA8+J3a3HfhttwCKLyuoyN7yXTFCxKBtSgMQBvrW9yNPa2/zDRUNuGPaH5QUFoa4arQ==",
+ "devOptional": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodable"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -5427,6 +5469,13 @@
"node": ">= 10"
}
},
+ "node_modules/@tootallnate/quickjs-emscripten": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
+ "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@tsconfig/node18": {
"version": "18.2.6",
"resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.6.tgz",
@@ -5858,13 +5907,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
- "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true,
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -5998,9 +6047,9 @@
"license": "MIT"
},
"node_modules/@xmldom/xmldom": {
- "version": "0.8.11",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
- "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==",
+ "version": "0.8.15",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz",
+ "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -6031,6 +6080,7 @@
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"mime-types": "~2.1.34",
@@ -6044,6 +6094,7 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -6269,6 +6320,19 @@
"node": ">= 8"
}
},
+ "node_modules/anynum": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz",
+ "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==",
+ "devOptional": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/appdirsjs": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz",
@@ -6746,9 +6810,9 @@
}
},
"node_modules/babel-plugin-module-resolver/node_modules/minimatch": {
- "version": "8.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz",
- "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==",
+ "version": "8.0.7",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.7.tgz",
+ "integrity": "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -6905,18 +6969,21 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
- "version": "2.9.19",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
- "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
+ "version": "2.11.33",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.33.tgz",
+ "integrity": "sha512-yiVKDX+qCMRKBE084lXvq9EcwFUhKZ2nU8TK1EQQuOgPNR/lmbGxXOeDdlGUqC2Zz11Cs9rk1d/8NfgBmlkt0w==",
"license": "Apache-2.0",
"bin": {
- "baseline-browser-mapping": "dist/cli.js"
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
}
},
"node_modules/basic-ftp": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.1.0.tgz",
- "integrity": "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==",
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz",
+ "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -7219,9 +7286,9 @@
}
},
"node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
+ "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7241,9 +7308,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.28.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
- "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+ "version": "4.28.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz",
+ "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==",
"funding": [
{
"type": "opencollective",
@@ -7260,11 +7327,11 @@
],
"license": "MIT",
"dependencies": {
- "baseline-browser-mapping": "^2.9.0",
- "caniuse-lite": "^1.0.30001759",
- "electron-to-chromium": "^1.5.263",
- "node-releases": "^2.0.27",
- "update-browserslist-db": "^1.2.0"
+ "baseline-browser-mapping": "^2.10.44",
+ "caniuse-lite": "^1.0.30001806",
+ "electron-to-chromium": "^1.5.393",
+ "node-releases": "^2.0.51",
+ "update-browserslist-db": "^1.2.3"
},
"bin": {
"browserslist": "cli.js"
@@ -7469,9 +7536,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001769",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz",
- "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==",
+ "version": "1.0.30001819",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001819.tgz",
+ "integrity": "sha512-LFUqIIAwpzsIuevnKnsR9qnStBcgzPShTX61lBwN9uFkkf8o8zLiebEjbW8AYtZiF+1YKDWfdt/pWDtMuG8Xwg==",
"funding": [
{
"type": "opencollective",
@@ -7867,15 +7934,16 @@
}
},
"node_modules/compression": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
- "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.2.tgz",
+ "integrity": "sha512-o8vI5RE5A6EVVOd9o41jKp41aJom+QTEO/Bx8MYNjexMo/Bv2WOjUfZr+aL0WnYSgymUy6zeguqLTsIhV0gMvQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"compressible": "~2.0.18",
"debug": "2.6.9",
+ "destroy": "1.2.0",
"negotiator": "~0.6.4",
"on-headers": "~1.1.0",
"safe-buffer": "5.2.1",
@@ -8367,9 +8435,9 @@
"license": "Python-2.0"
},
"node_modules/cosmiconfig/node_modules/js-yaml": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+ "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -8999,16 +9067,15 @@
}
},
"node_modules/degenerator": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-4.0.4.tgz",
- "integrity": "sha512-MTZdZsuNxSBL92rsjx3VFWe57OpRlikyLbcx2B5Dmdv6oScqpMrvpY7zHLMymrUxo3U5+suPUMsNgW/+SZB1lg==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
+ "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ast-types": "^0.13.4",
- "escodegen": "^1.14.3",
- "esprima": "^4.0.1",
- "vm2": "^3.9.19"
+ "escodegen": "^2.1.0",
+ "esprima": "^4.0.1"
},
"engines": {
"node": ">= 14"
@@ -9459,9 +9526,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.286",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
- "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==",
+ "version": "1.5.464",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.464.tgz",
+ "integrity": "sha512-nRa65aFge40viPAKxMKULIY8tcXKwKboJWNn4RoKwyWXJ6SP7BnrDGKUTzc64818jIciH0PK7LSF8QzZes19GA==",
"license": "ISC"
},
"node_modules/emittery": {
@@ -9847,92 +9914,27 @@
}
},
"node_modules/escodegen": {
- "version": "1.14.3",
- "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
- "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+ "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"esprima": "^4.0.1",
- "estraverse": "^4.2.0",
- "esutils": "^2.0.2",
- "optionator": "^0.8.1"
+ "estraverse": "^5.2.0",
+ "esutils": "^2.0.2"
},
"bin": {
"escodegen": "bin/escodegen.js",
"esgenerate": "bin/esgenerate.js"
},
"engines": {
- "node": ">=4.0"
+ "node": ">=6.0"
},
"optionalDependencies": {
"source-map": "~0.6.1"
}
},
- "node_modules/escodegen/node_modules/estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/escodegen/node_modules/levn": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
- "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/escodegen/node_modules/optionator": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
- "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "deep-is": "~0.1.3",
- "fast-levenshtein": "~2.0.6",
- "levn": "~0.3.0",
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2",
- "word-wrap": "~1.2.3"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/escodegen/node_modules/prelude-ls": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/escodegen/node_modules/type-check": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
- "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "~1.1.2"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/eslint": {
"version": "8.57.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
@@ -10090,9 +10092,9 @@
"license": "Apache-2.0"
},
"node_modules/eslint-config-expensify/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -10460,13 +10462,6 @@
"node": ">=4"
}
},
- "node_modules/eslint-config-expensify/node_modules/flatted": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
- "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/eslint-config-expensify/node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@@ -10646,9 +10641,9 @@
}
},
"node_modules/eslint-config-expensify/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -11062,9 +11057,9 @@
}
},
"node_modules/eslint-plugin-import/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11096,9 +11091,9 @@
}
},
"node_modules/eslint-plugin-import/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -11296,9 +11291,9 @@
}
},
"node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11307,9 +11302,9 @@
}
},
"node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -11424,9 +11419,9 @@
"license": "MIT"
},
"node_modules/eslint-plugin-react/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11448,9 +11443,9 @@
}
},
"node_modules/eslint-plugin-react/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -11567,9 +11562,9 @@
"license": "Python-2.0"
},
"node_modules/eslint/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11618,9 +11613,9 @@
}
},
"node_modules/eslint/node_modules/js-yaml": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+ "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11631,9 +11626,9 @@
}
},
"node_modules/eslint/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -11944,9 +11939,9 @@
}
},
"node_modules/expo-module-scripts/node_modules/@expo/cli/node_modules/ws": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
- "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
+ "version": "8.21.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
+ "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -12174,9 +12169,9 @@
}
},
"node_modules/expo-module-scripts/node_modules/@react-native/codegen/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -12489,9 +12484,9 @@
}
},
"node_modules/expo-module-scripts/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -12758,9 +12753,9 @@
}
},
"node_modules/expo-module-scripts/node_modules/eslint-config-universe/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -12928,17 +12923,40 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/expo-module-scripts/node_modules/glob/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/expo-module-scripts/node_modules/glob/node_modules/brace-expansion": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/expo-module-scripts/node_modules/glob/node_modules/minimatch": {
- "version": "10.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
- "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
- "@isaacs/brace-expansion": "^5.0.1"
+ "brace-expansion": "^5.0.8"
},
"engines": {
- "node": "20 || >=22"
+ "node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -13206,9 +13224,9 @@
}
},
"node_modules/expo-module-scripts/node_modules/picomatch": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz",
- "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.2.tgz",
+ "integrity": "sha512-cfDHL6LStTEKlNilboNtobT/kEa30PtAf2Q1OgszfrG/rpVl1xaFWT9ktfkS306GmHgmnad1Sw4wabhlvFtsTw==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -13463,10 +13481,27 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fast-xml-builder": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.1.tgz",
+ "integrity": "sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==",
+ "devOptional": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "path-expression-matcher": "^1.6.2",
+ "xml-naming": "^0.3.0"
+ }
+ },
"node_modules/fast-xml-parser": {
- "version": "4.5.3",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz",
- "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==",
+ "version": "5.11.2",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.11.2.tgz",
+ "integrity": "sha512-R9iDuNrQYeQut46cn2r2wHKn4HYzVDvDm5J1wW+koZewykv0yuO2HChTYeZtrULyHIDM9cj9TUXloCsueCQUog==",
"devOptional": true,
"funding": [
{
@@ -13476,7 +13511,12 @@
],
"license": "MIT",
"dependencies": {
- "strnum": "^1.1.1"
+ "@nodable/entities": "^3.0.1",
+ "fast-xml-builder": "^1.2.0",
+ "is-unsafe": "^2.0.0",
+ "path-expression-matcher": "^1.6.2",
+ "strnum": "^2.4.2",
+ "xml-naming": "^0.3.0"
},
"bin": {
"fxparser": "src/cli/cli.js"
@@ -13681,9 +13721,9 @@
}
},
"node_modules/flatted": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
- "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz",
+ "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==",
"dev": true,
"license": "ISC"
},
@@ -13718,17 +13758,17 @@
}
},
"node_modules/form-data": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
- "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
+ "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
- "hasown": "^2.0.2",
- "mime-types": "^2.1.12"
+ "hasown": "^2.0.4",
+ "mime-types": "^2.1.35"
},
"engines": {
"node": ">= 6"
@@ -14257,9 +14297,9 @@
}
},
"node_modules/glob/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -14267,9 +14307,9 @@
}
},
"node_modules/glob/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -14418,13 +14458,13 @@
"license": "MIT"
},
"node_modules/handlebars": {
- "version": "4.7.8",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
- "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
+ "version": "4.7.10",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.10.tgz",
+ "integrity": "sha512-P5VJMVM7qgBn6vjXMw8WG9uVI+ncf2pi72j4de4yz5ZULLj2RGqLYaKOYGsgyrViQ0tePOVlN1tDCCXXtFqXKg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "minimist": "^1.2.5",
+ "minimist": "^1.2.8",
"neo-async": "^2.6.2",
"source-map": "^0.6.1",
"wordwrap": "^1.0.0"
@@ -14553,9 +14593,9 @@
}
},
"node_modules/hasown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
- "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
+ "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -14633,9 +14673,9 @@
"license": "MIT"
},
"node_modules/http-cache-semantics": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
- "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz",
+ "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==",
"dev": true,
"license": "BSD-2-Clause"
},
@@ -14776,21 +14816,6 @@
"node": ">= 4"
}
},
- "node_modules/image-size": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
- "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==",
- "license": "MIT",
- "dependencies": {
- "queue": "6.0.2"
- },
- "bin": {
- "image-size": "bin/image-size.js"
- },
- "engines": {
- "node": ">=16.x"
- }
- },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -14968,17 +14993,10 @@
"loose-envify": "^1.0.0"
}
},
- "node_modules/ip": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz",
- "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/ip-address": {
- "version": "10.1.0",
- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
- "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
+ "version": "10.7.5",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.5.tgz",
+ "integrity": "sha512-t2v0rkILYv9WXmSL7TpAaU3HXgaFYOPUcH3QHgwQ++gpJuH3bqyMy4Fvt/DJCTKwzH3Cf+bAp5W/mFL39KPLzA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -15784,6 +15802,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-unsafe": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.2.tgz",
+ "integrity": "sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==",
+ "devOptional": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/is-weakmap": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
@@ -16840,9 +16871,9 @@
"license": "MIT"
},
"node_modules/js-yaml": {
- "version": "3.14.2",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
- "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
+ "version": "3.15.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz",
+ "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==",
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
@@ -16917,28 +16948,6 @@
"node": ">= 6.0.0"
}
},
- "node_modules/jsdom/node_modules/escodegen": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
- "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "esprima": "^4.0.1",
- "estraverse": "^5.2.0",
- "esutils": "^2.0.2"
- },
- "bin": {
- "escodegen": "bin/escodegen.js",
- "esgenerate": "bin/esgenerate.js"
- },
- "engines": {
- "node": ">=6.0"
- },
- "optionalDependencies": {
- "source-map": "~0.6.1"
- }
- },
"node_modules/jsdom/node_modules/http-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
@@ -17006,9 +17015,9 @@
}
},
"node_modules/jsdom/node_modules/ws": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
- "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
+ "version": "8.21.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
+ "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -17224,14 +17233,14 @@
}
},
"node_modules/launch-editor": {
- "version": "2.12.0",
- "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz",
- "integrity": "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==",
+ "version": "2.14.2",
+ "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.2.tgz",
+ "integrity": "sha512-NHJEb30MGBCkmZXLZwz25t37QR4aY03ZzPYUJXOJaOa92uWwExI9SBQUuIznBYc1xkD7cJNGX7oc3Nl3sq2kQQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"picocolors": "^1.1.1",
- "shell-quote": "^1.8.3"
+ "shell-quote": "^1.10.0"
}
},
"node_modules/leven": {
@@ -17629,9 +17638,9 @@
}
},
"node_modules/lodash": {
- "version": "4.17.23",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
- "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"dev": true,
"license": "MIT"
},
@@ -18213,45 +18222,43 @@
}
},
"node_modules/metro": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.3.tgz",
- "integrity": "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.8.tgz",
+ "integrity": "sha512-ZbJDJCDlvv0O3QHVbhZkyP2/DtebfEoDZ3wVyYHgu6Uoy6DmmE/bis6lIDBYh+kWPuaueJDegyutPjkIBLtZDQ==",
"license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.24.7",
+ "@babel/code-frame": "^7.29.0",
"@babel/core": "^7.25.2",
- "@babel/generator": "^7.25.0",
- "@babel/parser": "^7.25.3",
- "@babel/template": "^7.25.0",
- "@babel/traverse": "^7.25.3",
- "@babel/types": "^7.25.2",
- "accepts": "^1.3.7",
- "chalk": "^4.0.0",
+ "@babel/generator": "^7.29.1",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "accepts": "^2.0.0",
"ci-info": "^2.0.0",
"connect": "^3.6.5",
"debug": "^4.4.0",
"error-stack-parser": "^2.0.6",
"flow-enums-runtime": "^0.0.6",
"graceful-fs": "^4.2.4",
- "hermes-parser": "0.32.0",
- "image-size": "^1.0.2",
+ "hermes-parser": "0.35.0",
"invariant": "^2.2.4",
"jest-worker": "^29.7.0",
"jsc-safe-url": "^0.2.2",
"lodash.throttle": "^4.1.1",
- "metro-babel-transformer": "0.83.3",
- "metro-cache": "0.83.3",
- "metro-cache-key": "0.83.3",
- "metro-config": "0.83.3",
- "metro-core": "0.83.3",
- "metro-file-map": "0.83.3",
- "metro-resolver": "0.83.3",
- "metro-runtime": "0.83.3",
- "metro-source-map": "0.83.3",
- "metro-symbolicate": "0.83.3",
- "metro-transform-plugins": "0.83.3",
- "metro-transform-worker": "0.83.3",
- "mime-types": "^2.1.27",
+ "metro-babel-transformer": "0.83.8",
+ "metro-cache": "0.83.8",
+ "metro-cache-key": "0.83.8",
+ "metro-config": "0.83.8",
+ "metro-core": "0.83.8",
+ "metro-file-map": "0.83.8",
+ "metro-resolver": "0.83.8",
+ "metro-runtime": "0.83.8",
+ "metro-source-map": "0.83.8",
+ "metro-symbolicate": "0.83.8",
+ "metro-transform-plugins": "0.83.8",
+ "metro-transform-worker": "0.83.8",
+ "mime-types": "^3.0.1",
"nullthrows": "^1.1.1",
"serialize-error": "^2.1.0",
"source-map": "^0.5.6",
@@ -18267,14 +18274,15 @@
}
},
"node_modules/metro-babel-transformer": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.3.tgz",
- "integrity": "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.8.tgz",
+ "integrity": "sha512-tnn0J5wzgTgTx2OJy3Cwr1y79bJz4eNgFQd+2HENOs5Vz6QOMnt05z7J+BedIo9wIbpEa0iN9U1nerxyvMRE9g==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.25.2",
"flow-enums-runtime": "^0.0.6",
- "hermes-parser": "0.32.0",
+ "hermes-parser": "0.35.0",
+ "metro-cache-key": "0.83.8",
"nullthrows": "^1.1.1"
},
"engines": {
@@ -18282,39 +18290,39 @@
}
},
"node_modules/metro-babel-transformer/node_modules/hermes-estree": {
- "version": "0.32.0",
- "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz",
- "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz",
+ "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==",
"license": "MIT"
},
"node_modules/metro-babel-transformer/node_modules/hermes-parser": {
- "version": "0.32.0",
- "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz",
- "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz",
+ "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==",
"license": "MIT",
"dependencies": {
- "hermes-estree": "0.32.0"
+ "hermes-estree": "0.35.0"
}
},
"node_modules/metro-cache": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.3.tgz",
- "integrity": "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.8.tgz",
+ "integrity": "sha512-aogMG5WbKzW5000otNjYrS9hIoORzkCI1faPJK+vxQLaf2BorJKBBFe/jl2Tfsi1mZUglS2EBuBt8B3JB7MYDQ==",
"license": "MIT",
"dependencies": {
"exponential-backoff": "^3.1.1",
"flow-enums-runtime": "^0.0.6",
"https-proxy-agent": "^7.0.5",
- "metro-core": "0.83.3"
+ "metro-core": "0.83.8"
},
"engines": {
"node": ">=20.19.4"
}
},
"node_modules/metro-cache-key": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.3.tgz",
- "integrity": "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.8.tgz",
+ "integrity": "sha512-I38PtcjT4crS5HY9UQ8i6z8S7tJ2WewtPGr/OwS6FcLKfy5T/1hlTaFw+wozUZkEtNpR6Gc0oJuvuKCbSoSN5A==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6"
@@ -18324,18 +18332,18 @@
}
},
"node_modules/metro-config": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.3.tgz",
- "integrity": "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.8.tgz",
+ "integrity": "sha512-crNbNy+/B4tCne2+HjUshwvC57gNBQj+V9fFSy3lHH2RlKcLHib3Mil/SfTX8Pfh2fCY5pPuSu2OKa7YiadB+Q==",
"license": "MIT",
"dependencies": {
"connect": "^3.6.5",
"flow-enums-runtime": "^0.0.6",
"jest-validate": "^29.7.0",
- "metro": "0.83.3",
- "metro-cache": "0.83.3",
- "metro-core": "0.83.3",
- "metro-runtime": "0.83.3",
+ "metro": "0.83.8",
+ "metro-cache": "0.83.8",
+ "metro-core": "0.83.8",
+ "metro-runtime": "0.83.8",
"yaml": "^2.6.1"
},
"engines": {
@@ -18343,23 +18351,23 @@
}
},
"node_modules/metro-core": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.3.tgz",
- "integrity": "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.8.tgz",
+ "integrity": "sha512-NTyOUOQaQKvQgJG9VI2ymN6KTM7gHEqkVFhkPc9bK4BsHSTz/EaXuFBXtC+wtwINLeH9tbusL/jfsSmdEmuU7A==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6",
"lodash.throttle": "^4.1.1",
- "metro-resolver": "0.83.3"
+ "metro-resolver": "0.83.8"
},
"engines": {
"node": ">=20.19.4"
}
},
"node_modules/metro-file-map": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.3.tgz",
- "integrity": "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.8.tgz",
+ "integrity": "sha512-+W++EUuzEXIfWQEFTWQMVThzhWbnJL4gRNJ9WSHzIAM5pT7gsprUxo9+2hrfirURm/TLvrKwhq37oCECJcDSyQ==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.0",
@@ -18377,9 +18385,9 @@
}
},
"node_modules/metro-minify-terser": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.3.tgz",
- "integrity": "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.8.tgz",
+ "integrity": "sha512-7tU0J5/c7LZaZJwTlOb1xq0NepTFvGzRxigDhZOq4jSE6g0BRHmBqe7XvLH3WcRiJNGy+eshcZr34RpMjb6mmg==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6",
@@ -18390,9 +18398,9 @@
}
},
"node_modules/metro-resolver": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.3.tgz",
- "integrity": "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.8.tgz",
+ "integrity": "sha512-piU0NVTI9i37YztDVF5rtn9uxP3NebVT0xZM9NKJ9z0jbigrctUQksi3NoYIeJMvL6Wn2dgAehpcmmnfn+gUwA==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6"
@@ -18402,9 +18410,9 @@
}
},
"node_modules/metro-runtime": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.3.tgz",
- "integrity": "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.8.tgz",
+ "integrity": "sha512-f7FfeM0pamq8vrvs8aO9KvIUabbUKe0WkHFpLt6Q9yIIIsORqNFwlgJeHGraOFPU7Cxqj5yLXkJu5bT1uwDXvw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.25.0",
@@ -18415,19 +18423,18 @@
}
},
"node_modules/metro-source-map": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.3.tgz",
- "integrity": "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.8.tgz",
+ "integrity": "sha512-60Uor7bM+KsVewLkLCcZfkPFCbqjPDdoSmeBuT3+ye+ac80BuLWbbR8DpyxWpUqQeZPdaAT5ZqFgDIs8BNEcVA==",
"license": "MIT",
"dependencies": {
- "@babel/traverse": "^7.25.3",
- "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3",
- "@babel/types": "^7.25.2",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
"flow-enums-runtime": "^0.0.6",
"invariant": "^2.2.4",
- "metro-symbolicate": "0.83.3",
+ "metro-symbolicate": "0.83.8",
"nullthrows": "^1.1.1",
- "ob1": "0.83.3",
+ "ob1": "0.83.8",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
},
@@ -18445,14 +18452,14 @@
}
},
"node_modules/metro-symbolicate": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.3.tgz",
- "integrity": "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.8.tgz",
+ "integrity": "sha512-ZLrbqOqQ+m+Mpv7zo65XEXkNqVYvgUbY7tIsb9e1zSSmU/4C3D6DjaJvRHqcAdl0mkg8TI/csKooAEa5xcZNwg==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6",
"invariant": "^2.2.4",
- "metro-source-map": "0.83.3",
+ "metro-source-map": "0.83.8",
"nullthrows": "^1.1.1",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
@@ -18474,15 +18481,15 @@
}
},
"node_modules/metro-transform-plugins": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.3.tgz",
- "integrity": "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.8.tgz",
+ "integrity": "sha512-9JRPkvi+m0QH2Y/w5RjCF9mHqOUNFpMFLDDLhKUjhcKESh8Wm3HKDdHXHVldTN1lTToCIabv81nF0zyJzKEJ5g==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.25.2",
- "@babel/generator": "^7.25.0",
- "@babel/template": "^7.25.0",
- "@babel/traverse": "^7.25.3",
+ "@babel/generator": "^7.29.1",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
"flow-enums-runtime": "^0.0.6",
"nullthrows": "^1.1.1"
},
@@ -18491,48 +18498,106 @@
}
},
"node_modules/metro-transform-worker": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.3.tgz",
- "integrity": "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.8.tgz",
+ "integrity": "sha512-Pa2hOfhUmWpI/dmkhsLq8uGyFHK2opoEK7j/YCiRtqNSe0YzzxYguXTNgg8AMiuZfc9LPcB1AhGENS10O5wcIw==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.25.2",
- "@babel/generator": "^7.25.0",
- "@babel/parser": "^7.25.3",
- "@babel/types": "^7.25.2",
+ "@babel/generator": "^7.29.1",
+ "@babel/parser": "^7.29.0",
+ "@babel/types": "^7.29.0",
"flow-enums-runtime": "^0.0.6",
- "metro": "0.83.3",
- "metro-babel-transformer": "0.83.3",
- "metro-cache": "0.83.3",
- "metro-cache-key": "0.83.3",
- "metro-minify-terser": "0.83.3",
- "metro-source-map": "0.83.3",
- "metro-transform-plugins": "0.83.3",
+ "metro": "0.83.8",
+ "metro-babel-transformer": "0.83.8",
+ "metro-cache": "0.83.8",
+ "metro-cache-key": "0.83.8",
+ "metro-minify-terser": "0.83.8",
+ "metro-source-map": "0.83.8",
+ "metro-transform-plugins": "0.83.8",
"nullthrows": "^1.1.1"
},
"engines": {
"node": ">=20.19.4"
}
},
+ "node_modules/metro/node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/metro/node_modules/ci-info": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
"license": "MIT"
},
+ "node_modules/metro/node_modules/content-type": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz",
+ "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/metro/node_modules/hermes-estree": {
- "version": "0.32.0",
- "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz",
- "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz",
+ "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==",
"license": "MIT"
},
"node_modules/metro/node_modules/hermes-parser": {
- "version": "0.32.0",
- "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz",
- "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz",
+ "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==",
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.35.0"
+ }
+ },
+ "node_modules/metro/node_modules/mime-types": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
+ "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/metro/node_modules/negotiator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz",
+ "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==",
"license": "MIT",
"dependencies": {
- "hermes-estree": "0.32.0"
+ "content-type": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
"node_modules/metro/node_modules/source-map": {
@@ -18545,9 +18610,9 @@
}
},
"node_modules/metro/node_modules/ws": {
- "version": "7.5.10",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
- "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
+ "version": "7.5.13",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz",
+ "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
@@ -18595,7 +18660,6 @@
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
- "devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -18605,6 +18669,7 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
@@ -18617,6 +18682,7 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -18656,13 +18722,13 @@
}
},
"node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true,
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -18782,9 +18848,9 @@
}
},
"node_modules/nanoid": {
- "version": "3.3.11",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
- "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "version": "3.3.20",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz",
+ "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==",
"dev": true,
"funding": [
{
@@ -18834,9 +18900,9 @@
"peer": true
},
"node_modules/netmask": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
- "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz",
+ "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -18930,9 +18996,9 @@
}
},
"node_modules/node-forge": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz",
- "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
+ "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==",
"dev": true,
"license": "(BSD-3-Clause OR GPL-2.0)",
"peer": true,
@@ -18947,10 +19013,13 @@
"license": "MIT"
},
"node_modules/node-releases": {
- "version": "2.0.27",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
- "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
- "license": "MIT"
+ "version": "2.0.60",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.60.tgz",
+ "integrity": "sha512-OmO8+GM1JUZqXET720VrJCwkjUCXmCMQm0Z3UDDRbfNLHS4NEAvY60j5jiFv0tkKw2PNNlqOLhahVmwJIOLDIQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/node-stream-zip": {
"version": "1.15.0",
@@ -19097,9 +19166,9 @@
"license": "MIT"
},
"node_modules/ob1": {
- "version": "0.83.3",
- "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.3.tgz",
- "integrity": "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==",
+ "version": "0.83.8",
+ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.8.tgz",
+ "integrity": "sha512-pk7el+eTOzfSKMAY4QBiiwKzegXn633JQj13y+pW5E5IdS+yV2CfDJ9Hf20K/LKy8nCrP9dAmd7XOk52OJxifA==",
"license": "MIT",
"dependencies": {
"flow-enums-runtime": "^0.0.6"
@@ -19350,16 +19419,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/own-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
@@ -19446,33 +19505,33 @@
}
},
"node_modules/pac-proxy-agent": {
- "version": "6.0.4",
- "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-6.0.4.tgz",
- "integrity": "sha512-FbJYeusBOZNe6bmrC2/+r/HljwExryon16lNKEU82gWiwIPMCEktUPSEAcTkO9K3jd/YPGuX/azZel1ltmo6nQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
+ "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "agent-base": "^7.0.2",
+ "@tootallnate/quickjs-emscripten": "^0.23.0",
+ "agent-base": "^7.1.2",
"debug": "^4.3.4",
"get-uri": "^6.0.1",
"http-proxy-agent": "^7.0.0",
- "https-proxy-agent": "^7.0.0",
- "pac-resolver": "^6.0.1",
- "socks-proxy-agent": "^8.0.1"
+ "https-proxy-agent": "^7.0.6",
+ "pac-resolver": "^7.0.1",
+ "socks-proxy-agent": "^8.0.5"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/pac-resolver": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-6.0.2.tgz",
- "integrity": "sha512-EQpuJ2ifOjpZY5sg1Q1ZeAxvtLwR7Mj3RgY8cysPGbsRu3RBXyJFWxnMus9PScjxya/0LzvVDxNh/gl0eXBU4w==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
+ "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "degenerator": "^4.0.4",
- "ip": "^1.1.8",
+ "degenerator": "^5.0.0",
"netmask": "^2.0.2"
},
"engines": {
@@ -19608,6 +19667,22 @@
"node": ">=8"
}
},
+ "node_modules/path-expression-matcher": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz",
+ "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==",
+ "devOptional": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -19684,9 +19759,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -19899,9 +19974,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.49",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
- "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
+ "version": "8.5.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz",
+ "integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==",
"dev": true,
"funding": [
{
@@ -19920,9 +19995,9 @@
"license": "MIT",
"peer": true,
"dependencies": {
- "nanoid": "^3.3.7",
+ "nanoid": "^3.3.20",
"picocolors": "^1.1.1",
- "source-map-js": "^1.2.1"
+ "source-map-js": "^1.2.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -20113,20 +20188,20 @@
"license": "MIT"
},
"node_modules/proxy-agent": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.2.1.tgz",
- "integrity": "sha512-OIbBKlRAT+ycCm6wAYIzMwPejzRtjy8F3QiDX0eKOA3e4pe3U9F/IvzcHP42bmgQxVv97juG+J8/gx+JIeCX/Q==",
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
+ "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "agent-base": "^7.0.2",
+ "agent-base": "^7.1.2",
"debug": "^4.3.4",
- "http-proxy-agent": "^7.0.0",
- "https-proxy-agent": "^7.0.0",
+ "http-proxy-agent": "^7.0.1",
+ "https-proxy-agent": "^7.0.6",
"lru-cache": "^7.14.1",
- "pac-proxy-agent": "^6.0.3",
+ "pac-proxy-agent": "^7.1.0",
"proxy-from-env": "^1.1.0",
- "socks-proxy-agent": "^8.0.1"
+ "socks-proxy-agent": "^8.0.5"
},
"engines": {
"node": ">= 14"
@@ -20261,15 +20336,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/queue": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
- "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
- "license": "MIT",
- "dependencies": {
- "inherits": "~2.0.3"
- }
- },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -20372,9 +20438,9 @@
}
},
"node_modules/react-devtools-core/node_modules/ws": {
- "version": "7.5.10",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
- "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
+ "version": "7.5.13",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz",
+ "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
@@ -20653,9 +20719,9 @@
}
},
"node_modules/react-native-builder-bob/node_modules/minimatch": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
- "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "version": "5.1.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
+ "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -21387,9 +21453,9 @@
}
},
"node_modules/release-it/node_modules/js-yaml": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+ "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -21399,13 +21465,6 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "node_modules/release-it/node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/release-it/node_modules/log-symbols": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz",
@@ -22297,9 +22356,9 @@
}
},
"node_modules/shell-quote": {
- "version": "1.8.3",
- "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
- "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.12.0.tgz",
+ "integrity": "sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -22503,13 +22562,13 @@
}
},
"node_modules/socks": {
- "version": "2.8.7",
- "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
- "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
+ "version": "2.8.10",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.10.tgz",
+ "integrity": "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "ip-address": "^10.0.1",
+ "ip-address": "^10.1.1",
"smart-buffer": "^4.2.0"
},
"engines": {
@@ -22542,9 +22601,9 @@
}
},
"node_modules/source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
+ "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
"dev": true,
"license": "BSD-3-Clause",
"peer": true,
@@ -23037,9 +23096,9 @@
}
},
"node_modules/strnum": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz",
- "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.5.1.tgz",
+ "integrity": "sha512-UM4nTLWzQiDBseVxUGxN0wJzIk0UU89Qi7pKXz9qISo+lhviJikTuikBsK/oFRlpvYHvSdz0TVoLyQ+sEpYwxA==",
"devOptional": true,
"funding": [
{
@@ -23047,7 +23106,10 @@
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "anynum": "^1.0.1"
+ }
},
"node_modules/structured-headers": {
"version": "0.4.1",
@@ -23228,9 +23290,9 @@
}
},
"node_modules/tar": {
- "version": "7.5.7",
- "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz",
- "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==",
+ "version": "7.5.22",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz",
+ "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==",
"dev": true,
"license": "BlueOak-1.0.0",
"peer": true,
@@ -23345,9 +23407,9 @@
}
},
"node_modules/test-exclude/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -23355,9 +23417,9 @@
}
},
"node_modules/test-exclude/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -23465,9 +23527,9 @@
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -23491,16 +23553,13 @@
}
},
"node_modules/tmp": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
- "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz",
+ "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "os-tmpdir": "~1.0.2"
- },
"engines": {
- "node": ">=0.6.0"
+ "node": ">=14.14"
}
},
"node_modules/tmpl": {
@@ -23610,9 +23669,9 @@
}
},
"node_modules/ts-declaration-location/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -24073,9 +24132,9 @@
"license": "MIT"
},
"node_modules/undici": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz",
- "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==",
+ "version": "6.29.1",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.29.1.tgz",
+ "integrity": "sha512-EvRlUt/QqAEvXdQeRMYUfwOQsfzpDztykrG2owGEE/rBOBoYv9uF39ZzsNDh4lTFHhTr2XOZjKkYgueD12ZmGA==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -24394,23 +24453,6 @@
"integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==",
"license": "MIT"
},
- "node_modules/vm2": {
- "version": "3.10.4",
- "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.10.4.tgz",
- "integrity": "sha512-Gl6r7MN3mkawGurFdp467yDJQ7HdragK2QVVWFbOCd3LPJXJLE2xZFwLCNhp04MTkHruPqLIOs3pYbJQJw/1aA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "acorn": "^8.14.1",
- "acorn-walk": "^8.3.4"
- },
- "bin": {
- "vm2": "bin/vm2"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
@@ -24825,9 +24867,9 @@
}
},
"node_modules/ws": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
- "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
+ "version": "6.2.6",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.6.tgz",
+ "integrity": "sha512-XTrf1gv7kXoVf1hbC3PAyAiPgR8Wz1blcrYIjEsUmr08BLksT41R8KbjmS9408C2ERx7v1JDLD/BkpLEttjfKA==",
"license": "MIT",
"dependencies": {
"async-limiter": "~1.0.0"
@@ -24870,6 +24912,22 @@
"node": ">=12"
}
},
+ "node_modules/xml-naming": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz",
+ "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==",
+ "devOptional": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
"node_modules/xml2js": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz",
diff --git a/package.json b/package.json
index 455db5aa..baffbbf7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@expensify/react-native-wallet",
- "version": "0.1.41",
+ "version": "0.2.23",
"description": "A React Native module designed for seamless integration of Card Push Provisioning into Apple Wallet and Google Wallet, enabling easy and secure addition of payment cards directly from your application.",
"source": "./src/index.tsx",
"main": "lib/commonjs/index",
@@ -66,7 +66,7 @@
"devEngines": {
"runtime": {
"name": "node",
- "version": ">=24.19.0",
+ "version": ">=24.22.1",
"onFail": "error"
},
"packageManager": {
@@ -115,6 +115,33 @@
"turbo": "^1.10.7",
"typescript": "^5.8.3"
},
+ "overrides": {
+ "@typescript-eslint/typescript-estree": {
+ "minimatch": "9.0.9"
+ },
+ "fast-xml-parser": "^5.7.0",
+ "flatted": "^3.4.2",
+ "lodash": "^4.18.1",
+ "metro": "0.83.8",
+ "metro-babel-transformer": "0.83.8",
+ "metro-cache": "0.83.8",
+ "metro-cache-key": "0.83.8",
+ "metro-config": "0.83.8",
+ "metro-core": "0.83.8",
+ "metro-file-map": "0.83.8",
+ "metro-minify-terser": "0.83.8",
+ "metro-resolver": "0.83.8",
+ "metro-runtime": "0.83.8",
+ "metro-source-map": "0.83.8",
+ "metro-symbolicate": "0.83.8",
+ "metro-transform-plugins": "0.83.8",
+ "metro-transform-worker": "0.83.8",
+ "postcss": "^8.5.23",
+ "release-it": {
+ "proxy-agent": "^6.5.0"
+ },
+ "tmp": "^0.2.6"
+ },
"peerDependencies": {
"react": "*",
"react-native": "*"
diff --git a/src/NativeWallet.ts b/src/NativeWallet.ts
index f15df6e9..9522e9f6 100644
--- a/src/NativeWallet.ts
+++ b/src/NativeWallet.ts
@@ -27,6 +27,8 @@ type AndroidCardData = {
cardHolderName: string;
lastDigits: string;
userAddress: UserAddress;
+ isVirtualCard?: boolean;
+ isBounceProvisioned?: boolean;
};
type AndroidResumeCardData = {
@@ -41,26 +43,63 @@ type IOSCardData = {
cardHolderName: string;
lastDigits: string;
cardDescription: string;
+ primaryAccountIdentifier?: string;
};
type onCardActivatedPayload = {
- tokenId: string;
+ tokenId?: string | null;
status: 'activated' | 'canceled';
};
+type onPaymentCredentialsRequestPayload = {
+ requestId: string;
+ serverSessionId: string;
+ walletId: string;
+ tokenRequestorId: string | null;
+ opaquePaymentCard: string;
+};
+
type IOSAddPaymentPassData = {
status: number;
nonce: string;
nonceSignature: string;
certificates: string[];
+ deviceType?: string;
};
+type IOSDeviceType = 'phone' | 'watch' | 'unknown';
+
type IOSEncryptPayload = {
encryptedPassData: string;
activationData: string;
ephemeralPublicKey: string;
};
+type IOSPassActivationData = {
+ passTypeIdentifier: string;
+ serialNumber: string;
+ activationData: string;
+ isRemote?: boolean;
+};
+
+type IOSWalletPassNative = {
+ passTypeIdentifier: string;
+ serialNumber: string;
+ primaryAccountIdentifier?: string;
+ lastDigits?: string;
+ activationState: number;
+ isRemote: boolean;
+};
+
+type IOSWalletPass = {
+ passTypeIdentifier: string;
+ serialNumber: string;
+ primaryAccountIdentifier?: string;
+ lastDigits?: string;
+ activationState: CardStatus;
+ isRemote: boolean;
+};
+
type TokenizationStatus = 'canceled' | 'success' | 'error';
type TokenInfo = {
@@ -69,17 +108,28 @@ type TokenInfo = {
tokenState: number;
};
+type AndroidPaymentCredentialsResponse = {
+ opaquePaymentCard: string;
+ googleOpaquePaymentCard: string;
+};
+
export interface Spec extends TurboModule {
checkWalletAvailability(): Promise;
ensureGoogleWalletInitialized(): Promise;
getSecureWalletInfo(): Promise;
getCardStatusBySuffix(last4Digits: string): Promise;
getCardStatusByIdentifier(identifier: string, tsp: string): Promise;
+ hasEligibleTokenizationTarget(last4Digits: string, network: string, issuerName: string): Promise;
addCardToGoogleWallet(cardData: AndroidCardData): Promise;
+ AndroidProvidePaymentCredentials(requestId: string, responseData: AndroidPaymentCredentialsResponse): Promise;
+ AndroidRejectPaymentCredentials(requestId: string, errorMessage: string): Promise;
resumeAddCardToGoogleWallet(cardData: AndroidResumeCardData): Promise;
listTokens(): Promise;
+ listAppleWalletPasses(): Promise;
IOSPresentAddPaymentPassView(cardData: IOSCardData): Promise;
IOSHandleAddPaymentPassResponse(payload: IOSEncryptPayload): Promise;
+ activateAppleWalletPass(passData: IOSPassActivationData): Promise;
+ canAddCardToAppleWallet(primaryAccountIdentifier: string, lastDigits: string): Promise;
addListener: (eventType: string) => void;
removeListeners: (count: number) => void;
}
@@ -107,9 +157,15 @@ export type {
CardStatus,
UserAddress,
onCardActivatedPayload,
+ onPaymentCredentialsRequestPayload,
Platform,
IOSAddPaymentPassData,
+ IOSDeviceType,
IOSEncryptPayload,
+ IOSPassActivationData,
+ IOSWalletPass,
+ IOSWalletPassNative,
TokenizationStatus,
TokenInfo,
+ AndroidPaymentCredentialsResponse,
};
diff --git a/src/index.tsx b/src/index.tsx
index d1801ffc..a08b373f 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable no-console */
/* eslint-disable @lwc/lwc/no-async-await */
import {NativeEventEmitter, Platform} from 'react-native';
import type {EmitterSubscription} from 'react-native';
@@ -11,8 +12,13 @@ import type {
IOSEncryptPayload,
AndroidWalletData,
onCardActivatedPayload,
+ onPaymentCredentialsRequestPayload,
IOSAddPaymentPassData,
+ IOSPassActivationData,
+ IOSWalletPass,
+ IOSDeviceType,
TokenInfo,
+ AndroidPaymentCredentialsResponse,
} from './NativeWallet';
import {getCardState, getTokenizationStatus} from './utils';
import AddToWalletButton from './AddToWalletButton';
@@ -22,6 +28,25 @@ function getModuleLinkingRejection() {
}
let eventEmitter: NativeEventEmitter | undefined;
+let paymentCredentialsHandler: ((data: onPaymentCredentialsRequestPayload) => Promise) | null = null;
+
+if (Platform.OS === 'android' && Wallet) {
+ eventEmitter ??= new NativeEventEmitter(Wallet);
+ eventEmitter.addListener('onPaymentCredentialsRequest', async (data: onPaymentCredentialsRequestPayload) => {
+ if (!paymentCredentialsHandler) {
+ console.warn(`[${PACKAGE_NAME}] Received payment credentials request but no handler is set`);
+ await Wallet?.AndroidRejectPaymentCredentials(data.requestId, 'No payment credentials handler is set').catch(() => undefined);
+ return;
+ }
+ try {
+ const responseData = await paymentCredentialsHandler(data);
+ await Wallet?.AndroidProvidePaymentCredentials(data.requestId, responseData);
+ } catch (error) {
+ console.error(`[${PACKAGE_NAME}] Error handling payment credentials request:`, error);
+ await Wallet?.AndroidRejectPaymentCredentials(data.requestId, error instanceof Error ? error.message : String(error)).catch(() => undefined);
+ }
+ });
+}
function addListener(event: string, callback: (data: onCardActivatedPayload) => void): EmitterSubscription {
if (!Wallet) {
@@ -84,7 +109,30 @@ async function getCardStatusByIdentifier(identifier: string, tsp: string): Promi
return getCardState(tokenState);
}
-async function addCardToGoogleWallet(cardData: AndroidCardData): Promise {
+/**
+ * Checks whether the card can still be added to a Google Wallet target: the phone or a paired wearable.
+ * Use it to decide whether to show the "Add to Google Wallet" button when wearables are supported.
+ * @param last4Digits - The last 4 digits of the card number (FPAN, not the token)
+ * @param network - The card network, e.g. `VISA`, `MASTERCARD`
+ * @param issuerName - The issuer name used for matching, as in the token metadata (not the card display name)
+ * @returns `true` if at least one target can still receive the card
+ */
+async function hasEligibleTokenizationTarget(last4Digits: string, network: string, issuerName: string): Promise {
+ if (Platform.OS === 'ios') {
+ throw new Error('hasEligibleTokenizationTarget is not available on iOS');
+ }
+
+ if (!Wallet) {
+ return getModuleLinkingRejection();
+ }
+
+ return Wallet.hasEligibleTokenizationTarget(last4Digits, network.toUpperCase(), issuerName);
+}
+
+async function addCardToGoogleWallet(
+ cardData: AndroidCardData,
+ handlePaymentCredentialsGeneration: (data: onPaymentCredentialsRequestPayload) => Promise,
+): Promise {
if (Platform.OS === 'ios') {
throw new Error('addCardToGoogleWallet is not available on iOS');
}
@@ -96,8 +144,14 @@ async function addCardToGoogleWallet(cardData: AndroidCardData): Promise {
@@ -131,9 +185,48 @@ async function listTokens(): Promise {
return Wallet.listTokens();
}
+function toIOSDeviceType(deviceType: string | undefined): IOSDeviceType {
+ switch (deviceType) {
+ case 'phone':
+ case 'watch':
+ case 'unknown':
+ return deviceType;
+ default:
+ return 'unknown';
+ }
+}
+
+async function canAddCardToAppleWallet(primaryAccountIdentifier: string, lastDigits?: string): Promise {
+ if (Platform.OS === 'android') {
+ return false;
+ }
+
+ if (!Wallet) {
+ return getModuleLinkingRejection();
+ }
+
+ return Wallet.canAddCardToAppleWallet(primaryAccountIdentifier, lastDigits ?? '');
+}
+
+async function listAppleWalletPasses(): Promise {
+ if (Platform.OS === 'android') {
+ return Promise.resolve([]);
+ }
+
+ if (!Wallet) {
+ return getModuleLinkingRejection();
+ }
+
+ const passes = await Wallet.listAppleWalletPasses();
+ return passes.map((pass) => ({
+ ...pass,
+ activationState: getCardState(pass.activationState),
+ }));
+}
+
async function addCardToAppleWallet(
cardData: IOSCardData,
- issuerEncryptPayloadCallback: (nonce: string, nonceSignature: string, certificate: string[]) => Promise,
+ issuerEncryptPayloadCallback: (nonce: string, nonceSignature: string, certificate: string[], deviceType: IOSDeviceType) => Promise,
): Promise {
if (Platform.OS === 'android') {
throw new Error('addCardToAppleWallet is not available on Android');
@@ -151,7 +244,7 @@ async function addCardToAppleWallet(
}
async function addPaymentPassToWallet(paymentPassData: IOSAddPaymentPassData): Promise {
- const responseData = await issuerEncryptPayloadCallback(paymentPassData.nonce, paymentPassData.nonceSignature, paymentPassData.certificates);
+ const responseData = await issuerEncryptPayloadCallback(paymentPassData.nonce, paymentPassData.nonceSignature, paymentPassData.certificates, toIOSDeviceType(paymentPassData.deviceType));
const response = await wallet.IOSHandleAddPaymentPassResponse(responseData);
// Response is null when a pass is successfully added to the wallet or the user cancels the process
// In case the user presses the `Try again` option, new pass data is returned, and it should reenter the function
@@ -164,17 +257,48 @@ async function addCardToAppleWallet(
return getTokenizationStatus(status);
}
-export type {AndroidCardData, AndroidWalletData, CardStatus, IOSEncryptPayload, IOSCardData, IOSAddPaymentPassData, onCardActivatedPayload, TokenizationStatus, TokenInfo};
+async function activateAppleWalletPass(passData: IOSPassActivationData): Promise {
+ if (Platform.OS === 'android') {
+ throw new Error('activateAppleWalletPass is not available on Android');
+ }
+
+ if (!Wallet) {
+ return getModuleLinkingRejection();
+ }
+
+ return Wallet.activateAppleWalletPass(passData);
+}
+
+export type {
+ AndroidCardData,
+ AndroidWalletData,
+ CardStatus,
+ IOSEncryptPayload,
+ IOSCardData,
+ IOSAddPaymentPassData,
+ IOSPassActivationData,
+ IOSWalletPass,
+ IOSDeviceType,
+ onCardActivatedPayload,
+ onPaymentCredentialsRequestPayload,
+ TokenizationStatus,
+ TokenInfo,
+ AndroidPaymentCredentialsResponse,
+};
export {
AddToWalletButton,
checkWalletAvailability,
getSecureWalletInfo,
getCardStatusBySuffix,
getCardStatusByIdentifier,
+ hasEligibleTokenizationTarget,
addCardToGoogleWallet,
resumeAddCardToGoogleWallet,
listTokens,
+ listAppleWalletPasses,
+ canAddCardToAppleWallet,
addCardToAppleWallet,
+ activateAppleWalletPass,
addListener,
removeListener,
};