@cedros/pay-react 1.1.26 → 1.1.27

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.
Files changed (2) hide show
  1. package/README.md +163 -13
  2. package/package.json +14 -1
package/README.md CHANGED
@@ -370,6 +370,8 @@ cargo install cedros-pay-server
370
370
  - `POST /paywall/v1/stripe-session` - Create Stripe checkout (single item)
371
371
  - `GET /paywall/v1/stripe-session/verify` - Verify Stripe payment session (security-critical)
372
372
  - `POST /paywall/v1/cart/checkout` - Create Stripe checkout (cart)
373
+ - `POST /paywall/v1/subscription/stripe-session` - Create Stripe subscription checkout
374
+ - `POST /paywall/v1/subscription/stripe-mobile-session` - Create Stripe-native mobile subscription session
373
375
  - `POST /paywall/v1/cart/quote` - Get x402 quote for cart items
374
376
  - `POST /paywall/v1/gasless-transaction` - Build gasless transaction (optional)
375
377
  - `POST /paywall/v1/nonce` - Generate nonce for admin authentication
@@ -378,6 +380,34 @@ cargo install cedros-pay-server
378
380
  - `POST /paywall/v1/refunds/approve` - Get fresh quote for pending refund (admin-only)
379
381
  - `POST /paywall/v1/refunds/deny` - Deny pending refund (admin-only)
380
382
 
383
+ **Turnkey cross-channel setup**
384
+
385
+ Cedros is designed so you create the product once in the admin dashboard and then let the packages choose the right payment rail for web, Apple App Store, and Google Play at runtime.
386
+
387
+ For the full operator runbook, see [`ui/docs/cross-channel-setup.md`](./docs/cross-channel-setup.md).
388
+
389
+ 1. In **Admin → Products**, create the product and set:
390
+ - the normal commerce fields such as title, price, fulfillment, and checkout requirements
391
+ - the **Store policy classification** such as `digital_in_app`, `physical_goods`, `real_world_service`, or `reader_content`
392
+ - the **store-managed product kind** plus any Apple product ID or Google Play product/base-plan mapping when the product is sold inside app-store builds
393
+ 2. In **Admin → Payment Options → Stripe**, add your Stripe API keys, webhook secret, and any mobile redirect URI schemes you use.
394
+ 3. In **Admin → Payment Options → App Stores**, add:
395
+ - Apple issuer ID, key ID, private key, and bundle ID
396
+ - Google service-account credentials, package name, RTDN push identity, and push audience
397
+ 4. In Stripe, App Store Connect, and Google Play Console, create the matching products and point their webhooks / notifications at your Cedros server endpoints.
398
+ 5. In your React Native app, set Cedros provider config once for the build, especially `distributionChannel`, and Cedros will hydrate the product catalog from `/paywall/v1/products` automatically unless you disable catalog sync.
399
+
400
+ **Manual setup that still matters**
401
+
402
+ - Stripe:
403
+ Use the Cedros Stripe webhook endpoint so subscription and Checkout lifecycle events reach Cedros.
404
+ - Apple:
405
+ Create matching App Store Connect products and configure App Store Server Notifications to your tenant-scoped Cedros Apple notification URL.
406
+ - Google:
407
+ Create matching Play Console products and configure Real-time developer notifications to your tenant-scoped Cedros Google notification URL.
408
+ - Store policy exceptions:
409
+ Only enable reader-app, external-link, User Choice Billing, Alternative Billing Only, or external-offers behavior when your app is actually approved for those storefront programs.
410
+
381
411
  **Example - Quote Request:**
382
412
 
383
413
  ```bash
@@ -424,6 +454,44 @@ X-Signer: <wallet-address>
424
454
  # Only one refund allowed per transaction signature
425
455
  ```
426
456
 
457
+ **React Native Stripe subscriptions**
458
+
459
+ - Cedros now supports two explicit Stripe subscription flows on mobile.
460
+ - Hosted redirect checkout remains the stock default:
461
+
462
+ ```json
463
+ {
464
+ "flow": "redirect_checkout",
465
+ "sessionId": "cs_test_123",
466
+ "url": "https://checkout.stripe.com/c/pay/cs_test_123"
467
+ }
468
+ ```
469
+
470
+ - `@cedros/pay-react-native` opens `url` automatically in the device browser for this flow.
471
+ - Native mobile subscriptions use a dedicated PaymentSheet contract from `POST /paywall/v1/subscription/stripe-mobile-session`:
472
+
473
+ ```json
474
+ {
475
+ "flow": "payment_sheet",
476
+ "subscriptionId": "sub_123",
477
+ "customerId": "cus_123",
478
+ "customerEphemeralKeySecret": "ephkey_123",
479
+ "paymentIntentClientSecret": "pi_123_secret_abc"
480
+ }
481
+ ```
482
+
483
+ - In React Native, use `SubscribeButton` with `flow="payment_sheet"` or call `subscriptionManager.processMobileSubscription(...)` directly when you want the native Stripe sheet.
484
+ - Set `stripeReturnUrl` in `CedrosProvider` for PaymentSheet app return handling on iOS, for example `covenant://stripe-return`.
485
+ - If Stripe should return to your app via a custom deep link such as `covenant://subscription/success`, allowlist the URI scheme on the server with `stripe.allowed_redirect_schemes` or `CEDROS_STRIPE_ALLOWED_REDIRECT_SCHEMES=covenant`.
486
+ - Universal links such as `https://app.example.com/subscription/success` do not need to be allowlisted.
487
+
488
+ **React Native store-aware product sync**
489
+
490
+ - `@cedros/pay-react-native` can now hydrate its provider-level store policy catalog from `GET /paywall/v1/products`.
491
+ - By default, Cedros merges the server catalog with any manually supplied `paymentPolicy.productCatalog`, with manual entries taking precedence.
492
+ - This means the host app can usually pass just the product id to `CedrosPay` while keeping the canonical fulfillment and store-product mapping in the Cedros admin dashboard.
493
+ - If you need to disable that behavior, set `paymentPolicy.productCatalogSync.enabled` to `false`.
494
+
427
495
  **Example - Get Pending Refunds (Admin - Nonce Required):**
428
496
 
429
497
  ```bash
@@ -1473,24 +1541,30 @@ function AdminPage() {
1473
1541
 
1474
1542
  ### Unified Dashboard with Plugin System
1475
1543
 
1476
- For apps using both **cedros-login** and **cedros-pay**, use cedros-login's `AdminShell` component with the `cedrosPayPlugin` to create a combined admin interface:
1544
+ For apps using both **cedros-login** and **cedros-pay**, use `AdminShell` from `@cedros/admin-react` with both plugins to create a combined admin interface:
1477
1545
 
1478
1546
  ```tsx
1479
- import { AdminShell, cedrosLoginPlugin, useCedrosLogin } from "@cedros/login-react";
1480
- import { cedrosPayPlugin } from "@cedros/pay-react";
1547
+ import { AdminShell, HOST_SERVICE_IDS } from "@cedros/admin-react";
1548
+ import {
1549
+ cedrosLoginPlugin,
1550
+ useCedrosLogin,
1551
+ } from "@cedros/login-react/admin-only";
1552
+ import { cedrosPayPlugin } from "@cedros/pay-react/admin";
1481
1553
 
1482
1554
  function UnifiedAdmin() {
1483
1555
  const { user, getAccessToken, serverUrl } = useCedrosLogin();
1484
1556
 
1485
1557
  // Build host context from your auth providers
1486
1558
  const hostContext = {
1487
- cedrosLogin: {
1488
- user,
1489
- getAccessToken,
1490
- serverUrl,
1491
- },
1492
- cedrosPay: {
1493
- serverUrl: "https://api.example.com",
1559
+ services: {
1560
+ [HOST_SERVICE_IDS.cedrosLogin]: {
1561
+ user,
1562
+ getAccessToken,
1563
+ serverUrl,
1564
+ },
1565
+ [HOST_SERVICE_IDS.cedrosPay]: {
1566
+ serverUrl: "https://api.example.com",
1567
+ },
1494
1568
  },
1495
1569
  };
1496
1570
 
@@ -1505,7 +1579,7 @@ function UnifiedAdmin() {
1505
1579
  }
1506
1580
  ```
1507
1581
 
1508
- > **Note:** The `AdminShell` component is provided by `@cedros/login-react`. This package only exports the `cedrosPayPlugin` for use with their shell.
1582
+ > **Note:** The shared admin standard is the shell + plugin contract. `cedros-pay` exports `cedrosPayPlugin` for composition under a single `/admin` dashboard.
1509
1583
 
1510
1584
  ### cedrosPayPlugin Sections
1511
1585
 
@@ -1554,8 +1628,84 @@ See the [cedros-login documentation](https://github.com/cedros-dev/cedros-login)
1554
1628
  | `solanaEndpoint` | `string` | Custom Solana RPC endpoint |
1555
1629
  | `tokenMint` | `string` | SPL token mint address (default: USDC) - see [Token Mint Validation](#-token-mint-validation) |
1556
1630
  | `dangerouslyAllowUnknownMint` | `boolean` | Allow unknown token mints (default: false) - ⚠️ WARNING: Only enable after triple-checking mint address - see [Token Mint Validation](#-token-mint-validation) |
1631
+ | `featureFlags` | `Partial<Record<FeatureFlagName, boolean>>` | Explicit feature flag overrides. Precedence is `config.featureFlags` > environment variable > registry default. |
1557
1632
  | `logLevel` | `LogLevel` | Logging verbosity (default: `LogLevel.WARN` in production, `LogLevel.DEBUG` in development) - see [Logging](#-logging) |
1558
1633
 
1634
+ ### Feature Flags
1635
+
1636
+ Cedros Pay uses a central feature flag registry in [`src/featureFlags.ts`](./src/featureFlags.ts). Each flag has one stable positive name, a description, a default value, and a rollout stage. Call sites should read flags through the resolved helper instead of hard-coding boolean checks.
1637
+
1638
+ #### Consumer overrides
1639
+
1640
+ Package consumers can opt into or out of flags in provider config:
1641
+
1642
+ ```tsx
1643
+ <CedrosProvider
1644
+ config={{
1645
+ stripePublicKey: "pk_test_...",
1646
+ serverUrl: "https://api.example.com",
1647
+ solanaCluster: "devnet",
1648
+ featureFlags: {
1649
+ complianceCheck: true
1650
+ }
1651
+ }}
1652
+ >
1653
+ <App />
1654
+ </CedrosProvider>
1655
+ ```
1656
+
1657
+ Environment variable overrides are also supported when your runtime or bundler exposes `process.env` values to the package:
1658
+
1659
+ ```bash
1660
+ CEDROS_FEATURE_COMPLIANCE_CHECK=true
1661
+ ```
1662
+
1663
+ Supported boolean env values are `1`, `true`, `yes`, `on`, `0`, `false`, `no`, and `off`.
1664
+
1665
+ #### Adding a new flag
1666
+
1667
+ Define the flag once in [`src/featureFlags.ts`](./src/featureFlags.ts):
1668
+
1669
+ ```ts
1670
+ export const FEATURE_FLAG_REGISTRY = defineFeatureFlagRegistry({
1671
+ complianceCheck: {
1672
+ description: 'Enable pre-flight compliance checks before Stripe checkout.',
1673
+ default: false,
1674
+ stage: 'stable',
1675
+ },
1676
+ newParser: {
1677
+ description: 'Use the new parser implementation.',
1678
+ default: false,
1679
+ stage: 'experimental',
1680
+ },
1681
+ });
1682
+ ```
1683
+
1684
+ Then resolve it where needed:
1685
+
1686
+ ```ts
1687
+ const enabled = isFeatureEnabled('newParser', {
1688
+ featureFlags: config.featureFlags,
1689
+ });
1690
+ ```
1691
+
1692
+ #### Flipping the default later
1693
+
1694
+ Use positive names such as `newParser`, not negative names such as `disableNewParser`. That keeps the flag name stable across rollout:
1695
+
1696
+ 1. Ship it disabled by default with `default: false`.
1697
+ 2. Let consumers opt in with `featureFlags.newParser = true` or `CEDROS_FEATURE_NEW_PARSER=true`.
1698
+ 3. When the feature is ready, change only the registry entry to `default: true`.
1699
+ 4. Consumers can still opt out temporarily with `false` if they need a rollback window.
1700
+
1701
+ Precedence is always:
1702
+
1703
+ 1. Explicit runtime config in `featureFlags`
1704
+ 2. Environment variable override
1705
+ 3. Registry default
1706
+
1707
+ The existing top-level `complianceCheck` config field is still accepted for backward compatibility, but new integrations should prefer `featureFlags.complianceCheck`.
1708
+
1559
1709
  ### CedrosPay Component
1560
1710
 
1561
1711
  | Prop | Type | Description |
@@ -1573,8 +1723,8 @@ See the [cedros-login documentation](https://github.com/cedros-dev/cedros-login)
1573
1723
  | --------------- | ------------------------ | ---------------------------------- |
1574
1724
  | `customerEmail` | `string` | Pre-fill email for Stripe checkout |
1575
1725
  | `couponCode` | `string` | Coupon code to apply |
1576
- | `successUrl` | `string` | Stripe redirect URL on success |
1577
- | `cancelUrl` | `string` | Stripe redirect URL on cancel |
1726
+ | `successUrl` | `string` | Stripe redirect URL on success. React Native may use an allowlisted app deep link or universal link. |
1727
+ | `cancelUrl` | `string` | Stripe redirect URL on cancel. React Native may use an allowlisted app deep link or universal link. |
1578
1728
  | `metadata` | `Record<string, string>` | Custom tracking data |
1579
1729
 
1580
1730
  #### Display Options
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedros/pay-react",
3
- "version": "1.1.26",
3
+ "version": "1.1.27",
4
4
  "description": "React frontend library for Cedros Pay - unified Stripe and Solana x402 payments",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -12,6 +12,12 @@
12
12
  "import": "./dist/index.mjs",
13
13
  "require": "./dist/index.js"
14
14
  },
15
+ "./admin": {
16
+ "react-native": "./src/admin.ts",
17
+ "types": "./dist/admin.d.ts",
18
+ "import": "./dist/admin.mjs",
19
+ "require": "./dist/admin.js"
20
+ },
15
21
  "./stripe-only": {
16
22
  "react-native": "./src/stripe-only.ts",
17
23
  "types": "./dist/stripe-only.d.ts",
@@ -65,6 +71,7 @@
65
71
  },
66
72
  "homepage": "https://github.com/conorholds/cedros-pay/tree/main/ui#readme",
67
73
  "peerDependencies": {
74
+ "@cedros/admin-react": "^0.1.0",
68
75
  "@cedros/login-react": ">=0.0.4",
69
76
  "@solana/spl-token": "^0.4.14",
70
77
  "@solana/wallet-adapter-base": "^0.9.23",
@@ -77,6 +84,9 @@
77
84
  "react-dom": "^18.0.0 || ^19.0.0"
78
85
  },
79
86
  "peerDependenciesMeta": {
87
+ "@cedros/admin-react": {
88
+ "optional": true
89
+ },
80
90
  "@cedros/login-react": {
81
91
  "optional": true
82
92
  },
@@ -120,6 +130,8 @@
120
130
  "zod": "^4.1.5"
121
131
  },
122
132
  "devDependencies": {
133
+ "@cedros/admin-react": "file:../../cedros-admin/ui",
134
+ "@cedros/data-react": "file:../../cedros-data/ui",
123
135
  "@cedros/login-react": "^0.0.4",
124
136
  "@solana/spl-token": "^0.4.14",
125
137
  "@solana/wallet-adapter-base": "^0.9.23",
@@ -171,6 +183,7 @@
171
183
  "storybook": "storybook dev -p 6006",
172
184
  "build-storybook": "storybook build",
173
185
  "prepublishOnly": "npm run lint && npm run type-check && npm test && npm run build",
186
+ "prepack": "npm run build",
174
187
  "prepare": "husky"
175
188
  },
176
189
  "overrides": {