feat(paypal)!: migrate to PayPal JavaScript SDK v6#628
Conversation
BREAKING CHANGE: PayPal integration now uses SDK v6 (`/web-sdk/v6/core`) instead of v5 (`/sdk/js`). Key changes: - Script URL changed to `https://www.paypal.com/web-sdk/v6/core` - `useScriptPayPal` options simplified to `clientId`, `clientToken`, `sandbox` - v5 query-param options removed (buyerCountry, commit, components, currency, debug, disableFunding, enableFunding, integrationDate, intent, locale, merchantId, partnerAttributionId, vault) - `ScriptPayPalButtons` now exposes SDK v6 instance via scoped slot instead of rendering PayPal buttons directly — use `paypal.createInstance()` + `findEligibleMethods()` + payment sessions - `ScriptPayPalMarks` removed (no v6 equivalent) - `ScriptPayPalMessages` updated for v6 messages API - Types now from `@paypal/paypal-js/sdk-v6` instead of `@paypal/paypal-js`
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
commit: |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR migrates PayPal integrations from SDK v5 to SDK v6: it updates imports/types to Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/runtime/registry/schemas.ts (1)
587-602:⚠️ Potential issue | 🟠 MajorEnforce the documented
clientId/clientTokenrequirement in schema.Line 589 and Line 594 document “one is required if the other is absent,” but Line 592 and Line 597 allow both to be omitted. That lets invalid config pass validation and fail later at runtime.
💡 Suggested schema guard
-export const PayPalOptions = object({ +export const PayPalOptions = pipe(object({ /** * Your PayPal client ID. Required if `clientToken` is not provided. * `@see` https://developer.paypal.com/sdk/js/reference/ */ clientId: optional(string()), /** * A server-generated client token for authentication. Required if `clientId` is not provided. * `@see` https://docs.paypal.ai/payments/methods/paypal/sdk/js/v6/paypal-checkout */ clientToken: optional(string()), /** * Use the PayPal sandbox environment. Defaults to `true` in development. */ sandbox: optional(boolean()), -}) +}), custom(input => Boolean(input.clientId || input.clientToken)))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/runtime/registry/schemas.ts` around lines 587 - 602, The PayPalOptions schema currently allows both clientId and clientToken to be omitted despite doc comments; update PayPalOptions to enforce that at least one of clientId or clientToken is present by either (a) creating a union type of two schemas (one requiring clientId, one requiring clientToken) or (b) adding a refinement/validation to the existing PayPalOptions object that checks that (clientId || clientToken) is truthy and returns a clear validation error; target the PayPalOptions definition and the clientId/clientToken fields to implement this guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/runtime/components/ScriptPayPalButtons.vue`:
- Around line 96-103: The error path for createInstance in
ScriptPayPalButtons.vue leaves ready false and the component stuck in a loading
state; update the catch block to set a local failure/loading state (e.g., set
ready.value = false and set a new failed/error reactive variable or clear
sdkInstance.value) so the template can render a terminal error UI, then
emit('error', err) as before; ensure you reference sdkInstance, ready, emit and
the createInstance call when adding the failed flag and updating state in the
catch.
In `@src/runtime/components/ScriptPayPalMessages.vue`:
- Around line 101-109: The catch block after paypal.createInstance currently
only emits the error but leaves ready false and messagesSession possibly unset;
update the catch to set a local error/ref (e.g., error.value = err) and clear
any partial session state (e.g., messagesSession.value = null) and explicitly
set ready.value to false before emitting the error so the component can switch
out of its loading/placeholder state; adjust the catch handling around
paypal.createInstance / instance.createPayPalMessages to ensure ready,
messagesSession, and the new error ref are consistently updated on failure.
- Around line 77-81: The call to useScriptPayPal is passing non-schema keys
merchantId and partnerAttributionId; update the call so its input only includes
the PayPalInput schema fields (clientId, clientToken, sandbox and
paypalScriptOptions) and remove the spread entries for merchantId and
partnerAttributionId, leaving those values to be passed later to createInstance
(referenced in createInstance where merchantId and partnerAttributionId are
already handled).
In `@src/runtime/registry/paypal.ts`:
- Around line 2-10: The exported runtime types were updated to use
PayPalV6Namespace (PayPalApi.paypal) but the generated registry-types.json still
references the old PayPalNamespace (v5); regenerate the registry types so the
public API matches the new symbol names: run the repository's type/registry
generation step to refresh src/registry-types.json, confirm PayPalV6Namespace
(not PayPalNamespace) appears in the JSON, and ensure any consumers or exported
declarations reference the PayPalV6Namespace/PayPalApi symbols consistently.
---
Outside diff comments:
In `@src/runtime/registry/schemas.ts`:
- Around line 587-602: The PayPalOptions schema currently allows both clientId
and clientToken to be omitted despite doc comments; update PayPalOptions to
enforce that at least one of clientId or clientToken is present by either (a)
creating a union type of two schemas (one requiring clientId, one requiring
clientToken) or (b) adding a refinement/validation to the existing PayPalOptions
object that checks that (clientId || clientToken) is truthy and returns a clear
validation error; target the PayPalOptions definition and the
clientId/clientToken fields to implement this guard.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9eaea169-c2dc-41e1-9159-929ae78d5717
📒 Files selected for processing (9)
docs/content/scripts/paypal.mdplayground/pages/third-parties/paypal/nuxt-scripts.vuescripts/generate-registry-types.tssrc/runtime/components/ScriptPayPalButtons.vuesrc/runtime/components/ScriptPayPalMarks.vuesrc/runtime/components/ScriptPayPalMessages.vuesrc/runtime/registry/paypal.tssrc/runtime/registry/schemas.tssrc/script-meta.ts
💤 Files with no reviewable changes (2)
- src/runtime/components/ScriptPayPalMarks.vue
- scripts/generate-registry-types.ts
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/script-sizes.json (1)
55-55: Normalize non-script resource URLs before persisting snapshots.Line 55 stores a beacon URL with volatile query params (
h,sid,cid), which can create noisy diffs and leak run-specific identifiers into git history. Recommend sanitizing query/hash for non-script resources inscripts/generate-sizes.tsbefore writingurl.♻️ Proposed generator hardening
+function sanitizeResourceUrl(rawUrl: string, initiatorType: string): string { + if (initiatorType === 'script') + return rawUrl + try { + const u = new URL(rawUrl) + u.search = '' + u.hash = '' + return u.toString() + } + catch { + return rawUrl + } +} ... - const detail: ScriptSizeDetail = { - url: entry.name, + const detail: ScriptSizeDetail = { + url: sanitizeResourceUrl(entry.name, entry.initiatorType), transferKb: round(transferBytes), decodedKb: round(decodedBytes), encoding, durationMs: Math.round(entry.duration), initiatorType: entry.initiatorType, protocol: entry.nextHopProtocol || 'unknown', }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/script-sizes.json` at line 55, The stored beacon URL includes volatile query parameters and should be sanitized before persisting; update the generator in scripts/generate-sizes.ts (the function that builds/writes the snapshot entries, e.g., generateSizes or the writeSnapshot flow) to detect non-script resources (by MIME/content-type or by file extension) and normalize their URLs by removing query string and hash or stripping known volatile params such as h, sid, cid before assigning to the url property; implement a small normalizeUrl helper used where snapshot objects are created so persisted src/script-sizes.json contains stable, query-free URLs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/script-sizes.json`:
- Line 55: The stored beacon URL includes volatile query parameters and should
be sanitized before persisting; update the generator in
scripts/generate-sizes.ts (the function that builds/writes the snapshot entries,
e.g., generateSizes or the writeSnapshot flow) to detect non-script resources
(by MIME/content-type or by file extension) and normalize their URLs by removing
query string and hash or stripping known volatile params such as h, sid, cid
before assigning to the url property; implement a small normalizeUrl helper used
where snapshot objects are created so persisted src/script-sizes.json contains
stable, query-free URLs.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8289def1-7a80-45df-a2fb-46fb3f202666
📒 Files selected for processing (1)
src/script-sizes.json
- Add `failed` state to Buttons/Messages so error slot renders on createInstance failure instead of stuck loading - Remove non-schema keys (merchantId, partnerAttributionId) from useScriptPayPal call in Messages (they're createInstance options) - Enforce at least one of clientId/clientToken in PayPalOptions via union
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/runtime/components/ScriptPayPalButtons.vue`:
- Around line 143-150: The placeholder/loading slots can still render when
status === 'error' because their v-if conditions don't exclude the error state;
update the gating so placeholder and loading only render when status is not
'error' (e.g., add status !== 'error' to the v-if expressions or short-circuit
render the error slot first), ensuring the error slot (name="error") exclusively
shows when status === 'error' or failed is true; adjust conditions referencing
status, ready, and failed in the ScriptPayPalButtons component to prevent
overlap between placeholder/loading and the error state.
In `@src/runtime/components/ScriptPayPalMessages.vue`:
- Around line 146-153: The placeholder and loading slots can render alongside
the error slot because their v-if checks don't exclude status === 'error';
update the slot predicates in ScriptPayPalMessages.vue so both the placeholder
(currently using !ready && !failed) and loading (currently using status !==
'awaitingLoad' && !ready && !failed) also require status !== 'error' (or
equivalently ensure status === 'error' is the exclusive branch for the error
slot). Concretely, tighten the conditions for the placeholder and loading slots
to include a check against status === 'error' (or add status !== 'error') while
leaving the error slot (status === 'error' || failed) as the exclusive branch.
In `@src/runtime/registry/schemas.ts`:
- Around line 587-612: The PayPalOptions union currently allows a clientId-only
branch which will break PayPal SDK v6 (its createInstance() requires
clientToken); update the PayPalOptions schema so clientToken is required and
clientId is optional (remove the branch that mandates clientId-only and ensure
the schema reflects clientToken as required), then verify usages such as
createInstance() calls in ScriptPayPalButtons.vue and ScriptPayPalMessages.vue
rely on clientToken being present.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5ca780b9-601c-40a3-8084-cd70d0be858d
📒 Files selected for processing (3)
src/runtime/components/ScriptPayPalButtons.vuesrc/runtime/components/ScriptPayPalMessages.vuesrc/runtime/registry/schemas.ts
| export const PayPalOptions = union([ | ||
| object({ | ||
| /** | ||
| * Your PayPal client ID. | ||
| * @see https://developer.paypal.com/sdk/js/reference/ | ||
| */ | ||
| clientId: string(), | ||
| clientToken: optional(string()), | ||
| /** | ||
| * Use the PayPal sandbox environment. Defaults to `true` in development. | ||
| */ | ||
| sandbox: optional(boolean()), | ||
| }), | ||
| object({ | ||
| clientId: optional(string()), | ||
| /** | ||
| * A server-generated client token for authentication. | ||
| * @see https://docs.paypal.ai/payments/methods/paypal/sdk/js/v6/paypal-checkout | ||
| */ | ||
| clientToken: string(), | ||
| /** | ||
| * Use the PayPal sandbox environment. Defaults to `true` in development. | ||
| */ | ||
| sandbox: optional(boolean()), | ||
| }), | ||
| ]) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check the current schema implementation
cat -n src/runtime/registry/schemas.ts | sed -n '587,612p'Repository: nuxt/scripts
Length of output: 954
🏁 Script executed:
# Find where PayPalOptions is imported/used
rg "PayPalOptions" --type ts --type vue -A 2 -B 2Repository: nuxt/scripts
Length of output: 83
🏁 Script executed:
# Check the PayPal components to see how they use the config
cat -n src/runtime/components/ScriptPayPalButtons.vue | head -100Repository: nuxt/scripts
Length of output: 3686
🏁 Script executed:
# Look for any type definitions or imports related to PayPal
rg "paypal|PayPal" --type ts --type vue -l | head -20Repository: nuxt/scripts
Length of output: 83
🏁 Script executed:
# Search for CreateInstanceOptions references and usage
rg "CreateInstanceOptions" -A 5 -B 5Repository: nuxt/scripts
Length of output: 3646
🏁 Script executed:
# Check the paypal registry implementation
cat -n src/runtime/registry/paypal.ts | head -80Repository: nuxt/scripts
Length of output: 1416
🏁 Script executed:
# Look for any type definitions or comments about CreateInstanceOptions
rg "clientToken|clientId" src/runtime/registry/ -A 3 -B 1Repository: nuxt/scripts
Length of output: 2500
🌐 Web query:
PayPal SDK v6 CreateInstanceOptions clientToken required vs clientId
💡 Result:
In PayPal JavaScript SDK v6, CreateInstanceOptions requires clientToken and does not take clientId.
clientToken(required): You must callwindow.paypal.createInstance({ clientToken, ... })with a browser-safe, short‑lived token generated on your server. PayPal documents it as generated using your PayPal client ID + secret, expiring in ~15 minutes. [1]clientId(not used increateInstance): In v6, the browser fetches a client token from your server before creating the SDK instance; the client ID is part of your server credentials used to mint that token, not something you pass tocreateInstance. [2]- The official TypeScript typings/example for v6 likewise show
createInstance({ clientToken: "..." })(noclientId). [3]
So: use clientId (and secret) on the server to generate a clientToken, then pass only clientToken into createInstance in the browser.
Sources: [1] [2] [3]
🏁 Script executed:
# Check if there are any tests or other usages that show clientId-only configs working
rg "createInstance" -A 3 -B 3Repository: nuxt/scripts
Length of output: 1238
🏁 Script executed:
# Look at ScriptPayPalMessages.vue to confirm similar issue
cat -n src/runtime/components/ScriptPayPalMessages.vue | sed -n '75,110p'Repository: nuxt/scripts
Length of output: 1618
PayPalOptions schema allows clientId-only configuration that will fail at SDK v6 runtime.
The first union branch permits clientId without clientToken, but PayPal SDK v6's createInstance() method requires only clientToken—clientId is not accepted as a parameter. The components (ScriptPayPalButtons.vue and ScriptPayPalMessages.vue) conditionally pass either one to createInstance(), meaning a clientId-only config will fail when the SDK is initialized.
Require clientToken and make clientId optional in the schema to enforce the SDK v6 contract:
Suggested fix
-export const PayPalOptions = union([
- object({
- clientId: string(),
- clientToken: optional(string()),
- sandbox: optional(boolean()),
- }),
- object({
- clientId: optional(string()),
- clientToken: string(),
- sandbox: optional(boolean()),
- }),
-])
+export const PayPalOptions = object({
+ /**
+ * A server-generated client token for SDK v6 initialization.
+ */
+ clientToken: string(),
+ /**
+ * Optional merchant app identifier kept for upstream integrations/telemetry.
+ */
+ clientId: optional(string()),
+ sandbox: optional(boolean()),
+})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const PayPalOptions = union([ | |
| object({ | |
| /** | |
| * Your PayPal client ID. | |
| * @see https://developer.paypal.com/sdk/js/reference/ | |
| */ | |
| clientId: string(), | |
| clientToken: optional(string()), | |
| /** | |
| * Use the PayPal sandbox environment. Defaults to `true` in development. | |
| */ | |
| sandbox: optional(boolean()), | |
| }), | |
| object({ | |
| clientId: optional(string()), | |
| /** | |
| * A server-generated client token for authentication. | |
| * @see https://docs.paypal.ai/payments/methods/paypal/sdk/js/v6/paypal-checkout | |
| */ | |
| clientToken: string(), | |
| /** | |
| * Use the PayPal sandbox environment. Defaults to `true` in development. | |
| */ | |
| sandbox: optional(boolean()), | |
| }), | |
| ]) | |
| export const PayPalOptions = object({ | |
| /** | |
| * A server-generated client token for SDK v6 initialization. | |
| */ | |
| clientToken: string(), | |
| /** | |
| * Optional merchant app identifier kept for upstream integrations/telemetry. | |
| */ | |
| clientId: optional(string()), | |
| /** | |
| * Use the PayPal sandbox environment. Defaults to `true` in development. | |
| */ | |
| sandbox: optional(boolean()), | |
| }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/registry/schemas.ts` around lines 587 - 612, The PayPalOptions
union currently allows a clientId-only branch which will break PayPal SDK v6
(its createInstance() requires clientToken); update the PayPalOptions schema so
clientToken is required and clientId is optional (remove the branch that
mandates clientId-only and ensure the schema reflects clientToken as required),
then verify usages such as createInstance() calls in ScriptPayPalButtons.vue and
ScriptPayPalMessages.vue rely on clientToken being present.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/runtime/components/ScriptPayPalButtons.vue`:
- Line 139: The root container in ScriptPayPalButtons.vue is missing the ref
that useScriptTriggerElement expects; update the element that currently has
v-bind="rootAttrs" to also include ref="rootEl" so the root trigger ref from
useScriptTriggerElement (rootEl) is bound to the DOM node (ensure the component
still spreads rootAttrs and keeps the same element). This ties the rootEl used
by useScriptTriggerElement to the template and enables the trigger logic to
work.
- Around line 140-142: The default scoped slot is currently rendered with v-show
and receives undefined sdkInstance when ready is false; keep the container div
with ref="el" mounted but move the readiness check onto the slot so the slot is
only mounted when ready is true (e.g., use a template or v-if on the <slot
name="default" :sdk-instance="sdkInstance" /> itself), ensuring the slot only
renders when the component's ready state provides a defined sdkInstance in
ScriptPayPalButtons.vue.
In `@src/runtime/components/ScriptPayPalMessages.vue`:
- Line 142: The root DOM element isn't attaching the ref created as rootEl and
passed into useScriptTriggerElement, so trigger-based loading (e.g., trigger:
'visible') won't work; update the root node that currently spreads rootAttrs
(rootAttrs) to also attach the ref by binding rootEl (e.g., add a ref binding
referencing the rootEl used with useScriptTriggerElement) so the hook can
observe the actual element.
- Around line 143-154: The default slot is being rendered twice and mounted
before readiness; change the default slot to render only when ready and remove
the stray unnamed slot. Specifically, replace the v-show usage on the named
default slot (the element passing :messages-session) with v-if="ready" so it
only mounts when ready, keep the named slot signature
(:messages-session="messagesSession"), and delete the trailing unnamed <slot />
at the end; ensure other conditional slots (loading/awaitingLoad/error) remain
unchanged and continue to reference status and failed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0c635a5a-c499-4d4c-8cb9-b6cd4dfe741a
📒 Files selected for processing (2)
src/runtime/components/ScriptPayPalButtons.vuesrc/runtime/components/ScriptPayPalMessages.vue
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/registry-types.json`:
- Line 798: The registry-types.json contains outdated PayPal v5 typings (e.g.,
PayPalNamespace and ScriptPayPalMarksProps) that must be updated to match the
PayPal v6 runtime API; regenerate the file by rerunning the project's registry
type generation script/command (the same tool you used to produce
src/registry-types.json originally) so that PayPalNamespace and
ScriptPayPalMarksProps are removed/replaced with the v6 types and the published
types align with the runtime API.
In `@src/runtime/components/ScriptPayPalButtons.vue`:
- Around line 58-59: The auth resolution is inconsistent between useScriptPayPal
and createInstance: ensure both use the same resolved credentials by extracting
a single auth-resolver that merges props and paypalScriptOptions (preserve
explicit props over paypalScriptOptions or vice versa as intended) and use that
resolved auth when initializing the SDK and when calling createInstance; update
useScriptPayPal to call the shared resolver (referencing paypalScriptOptions and
props) and pass the resolved auth into createInstance (or have createInstance
accept the resolved auth) so initialization and instance creation always use
identical credentials.
In `@src/runtime/components/ScriptPayPalMessages.vue`:
- Around line 59-60: The loader input and createInstance are using different
credential sources which can cause mismatched clientId/clientToken
(paypalScriptOptions vs top-level props); to fix, compute a single resolved auth
object (merge top-level props' clientId/clientToken with
paypalScriptOptions.clientId/clientToken, preferring explicit
paypalScriptOptions values) inside the ScriptPayPalMessages setup, then pass
that resolvedAuth to both the loader input and createInstance calls so both use
the same credentials and avoid default 'test' mismatches.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 728e1e94-6d73-40a3-a20a-3e409d16e514
📒 Files selected for processing (3)
src/registry-types.jsonsrc/runtime/components/ScriptPayPalButtons.vuesrc/runtime/components/ScriptPayPalMessages.vue
| paypalScriptOptions?: Partial<PayPalInput> | ||
| }>(), { |
There was a problem hiding this comment.
Auth resolution is inconsistent between useScriptPayPal and createInstance.
Line 78 allows credentials from paypalScriptOptions, but Line 87-89 rebuilds auth only from props. This can initialize the SDK with one credential source and create the instance with another.
🔧 Suggested fix
- paypalScriptOptions?: Partial<PayPalInput>
+ paypalScriptOptions?: Partial<Pick<PayPalInput, 'sandbox' | 'clientId' | 'clientToken'>>
@@
+const resolvedAuth = computed(() => {
+ const clientToken = props.clientToken ?? props.paypalScriptOptions?.clientToken
+ if (clientToken)
+ return { clientToken }
+ return { clientId: props.paypalScriptOptions?.clientId ?? props.clientId }
+})
+
const { onLoaded, status } = useScriptPayPal({
- ...(props.clientToken ? { clientToken: props.clientToken } : { clientId: props.clientId }),
...props.paypalScriptOptions,
+ ...resolvedAuth.value,
})
@@
const instanceOptions = {
- ...(props.clientToken
- ? { clientToken: props.clientToken }
- : { clientId: props.clientId }),
+ ...resolvedAuth.value,
components: props.components,
...(props.pageType && { pageType: props.pageType }),Also applies to: 77-80, 86-95
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/components/ScriptPayPalButtons.vue` around lines 58 - 59, The
auth resolution is inconsistent between useScriptPayPal and createInstance:
ensure both use the same resolved credentials by extracting a single
auth-resolver that merges props and paypalScriptOptions (preserve explicit props
over paypalScriptOptions or vice versa as intended) and use that resolved auth
when initializing the SDK and when calling createInstance; update
useScriptPayPal to call the shared resolver (referencing paypalScriptOptions and
props) and pass the resolved auth into createInstance (or have createInstance
accept the resolved auth) so initialization and instance creation always use
identical credentials.
| paypalScriptOptions?: Partial<PayPalInput> | ||
| }>(), { |
There was a problem hiding this comment.
Use one resolved auth source for both loader input and createInstance.
Line 78 can be overridden by paypalScriptOptions.clientId/clientToken, but Line 90 still uses only top-level props. This can produce mismatched credentials and runtime init failures (especially with default clientId: 'test').
🔧 Suggested fix
- paypalScriptOptions?: Partial<PayPalInput>
+ paypalScriptOptions?: Partial<Pick<PayPalInput, 'sandbox' | 'clientId' | 'clientToken'>>
@@
+const resolvedAuth = computed(() => {
+ const clientToken = props.clientToken ?? props.paypalScriptOptions?.clientToken
+ if (clientToken)
+ return { clientToken }
+ return { clientId: props.paypalScriptOptions?.clientId ?? props.clientId }
+})
+
const { onLoaded, status } = useScriptPayPal({
- ...(props.clientToken ? { clientToken: props.clientToken } : { clientId: props.clientId }),
...props.paypalScriptOptions,
+ ...resolvedAuth.value,
})
@@
const instanceOptions = {
- ...(props.clientToken
- ? { clientToken: props.clientToken }
- : { clientId: props.clientId }),
+ ...resolvedAuth.value,
components,
...(props.pageType && { pageType: props.pageType }),
...(props.locale && { locale: props.locale }),Also applies to: 78-80, 89-98
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/components/ScriptPayPalMessages.vue` around lines 59 - 60, The
loader input and createInstance are using different credential sources which can
cause mismatched clientId/clientToken (paypalScriptOptions vs top-level props);
to fix, compute a single resolved auth object (merge top-level props'
clientId/clientToken with paypalScriptOptions.clientId/clientToken, preferring
explicit paypalScriptOptions values) inside the ScriptPayPalMessages setup, then
pass that resolvedAuth to both the loader input and createInstance calls so both
use the same credentials and avoid default 'test' mismatches.
❓ Type of change
📚 Description
PayPal released JS SDK v6 with a completely new architecture — instance-based initialization via
createInstance(), eligibility-first rendering, and session-based payment flows replacing the oldButtons()/Marks()/Messages()API. This migrates the integration from v5 (/sdk/js) to v6 (/web-sdk/v6/core).Types come from
@paypal/paypal-js/sdk-v6(already shipped in@paypal/paypal-js@9.4.0).PayPalOptionsschema reduced toclientId?,clientToken?,sandbox?— v6 config happens atcreateInstance()time, not via URL query paramsScriptPayPalButtonsno longer renders buttons directly — exposes the v6 SDK instance via#default="{ sdkInstance }"scoped slotScriptPayPalMarkscomponent removed (no v6 equivalent — replaced byfindEligibleMethods())ScriptPayPalMessagesupdated for v6createPayPalMessages()APIPayPalNamespacetype replaced withPayPalV6Namespace📝 Migration
ScriptPayPalButtonsnow provides the SDK instance via scoped slot:Payment flow uses sessions instead of button callbacks: