@alphawebai/hs-prism 0.1.0-rc.46 → 0.1.0-rc.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  export declare const ALPHAWEB_STRIPE_WEBHOOK_EVENTS: readonly ["charge.dispute.closed", "charge.dispute.created", "charge.dispute.funds_reinstated", "charge.dispute.funds_withdrawn", "charge.dispute.updated", "mandate.updated", "payment_intent.amount_capturable_updated", "payment_intent.canceled", "payment_intent.payment_failed", "payment_intent.processing", "payment_intent.requires_action", "payment_intent.succeeded", "payment_method.attached", "payment_method.automatically_updated", "payment_method.detached", "payment_method.updated", "refund.created", "refund.failed", "refund.updated", "setup_intent.canceled", "setup_intent.requires_action", "setup_intent.setup_failed", "setup_intent.succeeded"];
2
2
  export declare const ALPHAWEB_PAYPAL_WEBHOOK_EVENTS: readonly ["CHECKOUT.ORDER.APPROVED", "CHECKOUT.ORDER.COMPLETED", "CHECKOUT.ORDER.PROCESSED", "CHECKOUT.PAYMENT-APPROVAL.REVERSED", "CUSTOMER.DISPUTE.CREATED", "CUSTOMER.DISPUTE.RESOLVED", "CUSTOMER.DISPUTE.UPDATED", "PAYMENT.AUTHORIZATION.CREATED", "PAYMENT.AUTHORIZATION.VOIDED", "PAYMENT.CAPTURE.COMPLETED", "PAYMENT.CAPTURE.DECLINED", "PAYMENT.CAPTURE.PENDING", "PAYMENT.CAPTURE.REFUNDED", "PAYMENT.CAPTURE.REVERSED", "PAYMENT.REFUND.FAILED", "PAYMENT.REFUND.PENDING", "RISK.DISPUTE.CREATED", "VAULT.PAYMENT-TOKEN.CREATED", "VAULT.PAYMENT-TOKEN.DELETED", "VAULT.PAYMENT-TOKEN.DELETION-INITIATED"];
3
3
  export declare const ALPHAWEB_PRISM_COMPATIBILITY_MANIFEST: Readonly<{
4
- readonly release: "0.1.0-rc.46";
4
+ readonly release: "0.1.0-rc.48";
5
5
  readonly upstreamCommit: "b07af7d9dac271de729548e74217ddcf895c602b";
6
6
  readonly medusaRange: ">=2.17.2 <2.18.0";
7
7
  readonly stripeApiVersion: "2026-06-24.dahlia";
@@ -49,7 +49,7 @@ exports.ALPHAWEB_PAYPAL_WEBHOOK_EVENTS = Object.freeze([
49
49
  'VAULT.PAYMENT-TOKEN.DELETION-INITIATED',
50
50
  ]);
51
51
  exports.ALPHAWEB_PRISM_COMPATIBILITY_MANIFEST = Object.freeze({
52
- release: '0.1.0-rc.46',
52
+ release: '0.1.0-rc.48',
53
53
  upstreamCommit: 'b07af7d9dac271de729548e74217ddcf895c602b',
54
54
  medusaRange: '>=2.17.2 <2.18.0',
55
55
  stripeApiVersion: '2026-06-24.dahlia',
@@ -705,7 +705,7 @@ function normalizePayPalWebhook(input, binding) {
705
705
  const invoiceId = objectKind === 'dispute'
706
706
  ? consistentString(disputeTransactions.map((transaction) => stringOf(transaction.invoice_number)))
707
707
  : stringOf(resource.invoice_id) ?? stringOf(purchaseUnit.invoice_id);
708
- const medusaPaymentSessionId = objectKind === 'dispute'
708
+ const customId = objectKind === 'dispute'
709
709
  ? consistentString(disputeTransactions.map((transaction) => stringOf(transaction.custom)))
710
710
  : stringOf(resource.custom_id) ?? stringOf(purchaseUnit.custom_id);
711
711
  const connectorPaymentId = stringOf(related.order_id) ??
@@ -742,7 +742,14 @@ function normalizePayPalWebhook(input, binding) {
742
742
  const vaultDetails = type.startsWith('VAULT.PAYMENT-TOKEN.')
743
743
  ? resource
744
744
  : paymentSourceVault;
745
- const merchantOperationId = invoiceId;
745
+ // A repeat charge uses its idempotency key as PayPal's invoice ID, while the
746
+ // order's custom ID retains the payment operation owner. Checkout invoices
747
+ // continue to identify the operation and custom IDs may identify a session.
748
+ const repeatCharge = invoiceId?.startsWith('aw:') && customId?.startsWith('payop_');
749
+ const merchantOperationId = repeatCharge
750
+ ? customId
751
+ : invoiceId;
752
+ const medusaPaymentSessionId = repeatCharge ? null : customId;
746
753
  const normalized = {
747
754
  ...envelope,
748
755
  customerId: stringOf(recordOf(vaultDetails.customer).id) ??
@@ -1103,7 +1110,25 @@ class PrismPayPalConnector {
1103
1110
  });
1104
1111
  const responseOperationId = stringOf(response.merchantTransactionId);
1105
1112
  if (responseOperationId && responseOperationId !== input.operationId) {
1106
- throw configurationError('PayPal payment ownership does not match the payment operation.', 'PRISM_PAYMENT_OWNERSHIP');
1113
+ // PayPal repeat charges return their merchant charge/invoice reference
1114
+ // through PSync. Verify the order's distinct custom ID and exact amount
1115
+ // before accepting that reference for the saved payment operation.
1116
+ const order = recordOf(await this.paypalRequest('GET', `/v2/checkout/orders/${encodeURIComponent(input.connectorPaymentId)}`));
1117
+ const units = Array.isArray(order.purchase_units) ? order.purchase_units : [];
1118
+ const unit = units.length === 1 ? recordOf(units[0]) : {};
1119
+ const orderAmount = recordOf(unit.amount);
1120
+ const currency = stringOf(orderAmount.currency_code)?.toLowerCase();
1121
+ const value = stringOf(orderAmount.value);
1122
+ const ownedAmount = currency && value
1123
+ ? (0, money_1.toProviderMinorAmount)({ medusaAmount: value, currency })
1124
+ : null;
1125
+ if (stringOf(order.id) !== input.connectorPaymentId ||
1126
+ stringOf(unit.custom_id) !== input.operationId ||
1127
+ stringOf(unit.invoice_id) !== responseOperationId ||
1128
+ currency !== input.money.currency.toLowerCase() ||
1129
+ ownedAmount !== BigInt(input.money.amountMinor)) {
1130
+ throw configurationError('PayPal payment ownership does not match the payment operation.', 'PRISM_PAYMENT_OWNERSHIP');
1131
+ }
1107
1132
  }
1108
1133
  const responseAmount = recordOf(response.amount);
1109
1134
  const amountMinor = integerOf(responseAmount.minorAmount);
@@ -1,5 +1,5 @@
1
1
  import { types } from '../payments/generated/proto';
2
- import type { PrismCancelInput, PrismCaptureInput, PrismCreateWebhookEndpointInput, PrismDeleteWebhookEndpointInput, PrismDisputeResult, PrismEstablishReusableReferenceInput, PrismFindPaymentInput, PrismFindRefundInput, PrismMerchantOperation, PrismPaymentResult, PrismRefundInput, PrismRefundResult, PrismRetrieveDisputeInput, PrismRetrieveRefundInput, PrismRetryPaymentInput, PrismReusableReferenceDerivation, PrismRetrieveWebhookEndpointInput, PrismRetrievePaymentInput, PrismStripeConnectorOptions, PrismStripeConnectorV1, PrismStripeRuntimeVerification, PrismStripeRuntimeVerificationInput, PrismUpdateWebhookEndpointInput, PrismWebhookEndpoint, PrismWebhookEndpointCreated, PrismWebhookParseInput, PrismWebhookParseResult } from './types';
2
+ import type { PrismCancelInput, PrismCaptureInput, PrismCreateWebhookEndpointInput, PrismDeleteWebhookEndpointInput, PrismDisputeResult, PrismEstablishReusableReferenceInput, PrismFindPaymentInput, PrismFindRefundInput, PrismFutureUsePurpose, PrismMerchantOperation, PrismPaymentResult, PrismRefundInput, PrismRefundResult, PrismRetrieveDisputeInput, PrismRetrieveRefundInput, PrismRetryPaymentInput, PrismReusableReferenceDerivation, PrismRetrieveWebhookEndpointInput, PrismRetrievePaymentInput, PrismStripeConnectorOptions, PrismStripeConnectorV1, PrismStripeRuntimeVerification, PrismStripeRuntimeVerificationInput, PrismUpdateWebhookEndpointInput, PrismWebhookEndpoint, PrismWebhookEndpointCreated, PrismWebhookParseInput, PrismWebhookParseResult } from './types';
3
3
  interface MerchantAuthenticationPort {
4
4
  createClientAuthenticationToken(input: types.IMerchantAuthenticationServiceCreateClientAuthenticationTokenRequest): Promise<types.MerchantAuthenticationServiceCreateClientAuthenticationTokenResponse>;
5
5
  }
@@ -30,7 +30,15 @@ export declare class PrismStripeConnector implements PrismStripeConnectorV1 {
30
30
  private assertOperation;
31
31
  private recoverRepeatPayment;
32
32
  private stripeRequest;
33
- private checkoutPaymentMethodSelection;
33
+ /** Read-only selection shared by deferred Elements and PaymentIntent creation. */
34
+ checkoutPaymentMethodSelection(input: {
35
+ purposes: readonly PrismFutureUsePurpose[];
36
+ paymentMethodConfigurationId?: string;
37
+ captureMethod?: 'automatic' | 'manual';
38
+ }): Promise<{
39
+ paymentMethodConfigurationId: string;
40
+ excludedPaymentMethodTypes: string[];
41
+ } | undefined>;
34
42
  createPayment(input: PrismMerchantOperation): Promise<PrismPaymentResult>;
35
43
  repeatPayment(input: PrismMerchantOperation): Promise<PrismPaymentResult>;
36
44
  retryPayment(input: PrismRetryPaymentInput): Promise<PrismPaymentResult>;
@@ -761,13 +761,12 @@ class PrismStripeConnector {
761
761
  clearTimeout(timeout);
762
762
  }
763
763
  }
764
+ /** Read-only selection shared by deferred Elements and PaymentIntent creation. */
764
765
  async checkoutPaymentMethodSelection(input) {
765
- const purposes = input.futureUse?.purposes ??
766
- (input.metadata.alphaweb_setup_future_usage === 'off_session' ? ['post_purchase'] : []);
766
+ const purposes = input.purposes;
767
767
  if (purposes.length === 0)
768
768
  return undefined;
769
- const configurationId = input.methodSelection.kind === 'interactive_dynamic'
770
- ? input.methodSelection.paymentMethodConfigurationId : undefined;
769
+ const configurationId = input.paymentMethodConfigurationId;
771
770
  let configuration;
772
771
  if (configurationId) {
773
772
  configuration = recordOf(await this.stripeRequest('GET', `/payment_method_configurations/${encodeURIComponent(configurationId)}`));
@@ -796,7 +795,7 @@ class PrismStripeConnector {
796
795
  const method = ['apple_pay', 'google_pay', 'cartes_bancaires'].includes(type) ? 'card' : type;
797
796
  const profile = STRIPE_REUSABLE_PAYMENT_METHOD_PROFILES[method];
798
797
  return !profile || !supportsStripeFutureUse(profile, purposes) || profile.requiresGeneratedDebit ||
799
- (input.metadata.alphaweb_capture_method === 'manual' && !profile.supportsManualCapture);
798
+ (input.captureMethod === 'manual' && !profile.supportsManualCapture);
800
799
  }).map(([type]) => type);
801
800
  if (!methods.some(([type, value]) => !excludedPaymentMethodTypes.includes(type) &&
802
801
  recordOf(value).available === true && recordOf(recordOf(value).display_preference).value === 'on')) {
@@ -813,7 +812,12 @@ class PrismStripeConnector {
813
812
  throw configurationError('Interactive Stripe checkout requires a publishable key.', 'PRISM_PUBLISHABLE_KEY_REQUIRED');
814
813
  }
815
814
  try {
816
- const methodSelection = await this.checkoutPaymentMethodSelection(input);
815
+ const methodSelection = await this.checkoutPaymentMethodSelection({
816
+ purposes: input.futureUse?.purposes ??
817
+ (input.metadata.alphaweb_setup_future_usage === 'off_session' ? ['post_purchase'] : []),
818
+ paymentMethodConfigurationId: input.methodSelection.paymentMethodConfigurationId,
819
+ captureMethod: input.metadata.alphaweb_capture_method === 'manual' ? 'manual' : 'automatic',
820
+ });
817
821
  const response = await this.dependencies.merchantAuthentication.createClientAuthenticationToken({
818
822
  merchantClientSessionId: input.idempotencyKey,
819
823
  testMode: this.options.environment === 'test',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alphawebai/hs-prism",
3
- "version": "0.1.0-rc.46",
3
+ "version": "0.1.0-rc.48",
4
4
  "description": "Hyperswitch Payments SDK — Node.js client for connector integrations via UniFFI FFI",
5
5
  "main": "dist/src/index.js",
6
6
  "exports": {