@rovela-ai/sdk 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/api/payment-methods.d.ts.map +1 -1
- package/dist/admin/api/payment-methods.js +8 -0
- package/dist/admin/api/payment-methods.js.map +1 -1
- package/dist/admin/api/shipping.d.ts.map +1 -1
- package/dist/admin/api/shipping.js +15 -0
- package/dist/admin/api/shipping.js.map +1 -1
- package/dist/admin/api/tax-zones.d.ts.map +1 -1
- package/dist/admin/api/tax-zones.js +17 -0
- package/dist/admin/api/tax-zones.js.map +1 -1
- package/dist/admin/components/GroupVisibilityPicker.d.ts +10 -0
- package/dist/admin/components/GroupVisibilityPicker.d.ts.map +1 -0
- package/dist/admin/components/GroupVisibilityPicker.js +30 -0
- package/dist/admin/components/GroupVisibilityPicker.js.map +1 -0
- package/dist/admin/components/PaymentMethodsManager.d.ts.map +1 -1
- package/dist/admin/components/PaymentMethodsManager.js +7 -3
- package/dist/admin/components/PaymentMethodsManager.js.map +1 -1
- package/dist/admin/components/ShippingSettings.d.ts.map +1 -1
- package/dist/admin/components/ShippingSettings.js +4 -1
- package/dist/admin/components/ShippingSettings.js.map +1 -1
- package/dist/admin/components/TaxSettings.d.ts.map +1 -1
- package/dist/admin/components/TaxSettings.js +5 -1
- package/dist/admin/components/TaxSettings.js.map +1 -1
- package/dist/admin/components/index.d.ts +2 -0
- package/dist/admin/components/index.d.ts.map +1 -1
- package/dist/admin/components/index.js +1 -0
- package/dist/admin/components/index.js.map +1 -1
- package/dist/admin/types.d.ts +11 -0
- package/dist/admin/types.d.ts.map +1 -1
- package/dist/checkout/api/manual.d.ts.map +1 -1
- package/dist/checkout/api/manual.js +8 -1
- package/dist/checkout/api/manual.js.map +1 -1
- package/dist/checkout/api/payment-methods.d.ts.map +1 -1
- package/dist/checkout/api/payment-methods.js +5 -1
- package/dist/checkout/api/payment-methods.js.map +1 -1
- package/dist/checkout/api/shipping.d.ts.map +1 -1
- package/dist/checkout/api/shipping.js +8 -1
- package/dist/checkout/api/shipping.js.map +1 -1
- package/dist/checkout/index.d.ts +1 -1
- package/dist/checkout/index.d.ts.map +1 -1
- package/dist/checkout/index.js.map +1 -1
- package/dist/checkout/server/create-checkout-session.d.ts.map +1 -1
- package/dist/checkout/server/create-checkout-session.js +2 -1
- package/dist/checkout/server/create-checkout-session.js.map +1 -1
- package/dist/checkout/server/handle-webhook.js +1 -0
- package/dist/checkout/server/handle-webhook.js.map +1 -1
- package/dist/checkout/server/pricing.d.ts +4 -0
- package/dist/checkout/server/pricing.d.ts.map +1 -1
- package/dist/checkout/server/pricing.js +7 -4
- package/dist/checkout/server/pricing.js.map +1 -1
- package/dist/core/db/index.d.ts +1 -1
- package/dist/core/db/index.d.ts.map +1 -1
- package/dist/core/db/index.js +2 -0
- package/dist/core/db/index.js.map +1 -1
- package/dist/core/db/queries.d.ts +36 -5
- package/dist/core/db/queries.d.ts.map +1 -1
- package/dist/core/db/queries.js +87 -7
- package/dist/core/db/queries.js.map +1 -1
- package/dist/core/db/schema.d.ts +57 -0
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +15 -0
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/server/index.d.ts +1 -1
- package/dist/core/server/index.d.ts.map +1 -1
- package/dist/core/server/index.js +2 -0
- package/dist/core/server/index.js.map +1 -1
- package/dist/emails/send/orders.d.ts +2 -0
- package/dist/emails/send/orders.d.ts.map +1 -1
- package/dist/emails/send/orders.js +18 -12
- package/dist/emails/send/orders.js.map +1 -1
- package/dist/emails/templates/order-confirmation.d.ts.map +1 -1
- package/dist/emails/templates/order-confirmation.js +4 -2
- package/dist/emails/templates/order-confirmation.js.map +1 -1
- package/dist/emails/types.d.ts +2 -0
- package/dist/emails/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/core/db/queries.js
CHANGED
|
@@ -1644,6 +1644,51 @@ export async function setCustomerGroup(customerId, groupId) {
|
|
|
1644
1644
|
// =============================================================================
|
|
1645
1645
|
// Payment Methods (merchant-managed payment options beyond native Stripe)
|
|
1646
1646
|
// =============================================================================
|
|
1647
|
+
// =============================================================================
|
|
1648
|
+
// Group gating (Phase 4) — visible_to_groups on payment methods / shipping
|
|
1649
|
+
// rates / tax zones. Empty array = visible to everyone (opt-in gating).
|
|
1650
|
+
// =============================================================================
|
|
1651
|
+
let visibilityColumnsEnsured = false;
|
|
1652
|
+
/**
|
|
1653
|
+
* Self-heal the `visible_to_groups` column on the three gateable tables.
|
|
1654
|
+
* Empty-array default keeps every existing row visible to everyone.
|
|
1655
|
+
* Idempotent + module-cached.
|
|
1656
|
+
*/
|
|
1657
|
+
export async function ensureVisibilityColumns() {
|
|
1658
|
+
if (visibilityColumnsEnsured)
|
|
1659
|
+
return;
|
|
1660
|
+
const db = getDb();
|
|
1661
|
+
try {
|
|
1662
|
+
await db.execute(sql `ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS visible_to_groups jsonb NOT NULL DEFAULT '[]'::jsonb`);
|
|
1663
|
+
await db.execute(sql `ALTER TABLE shipping_rates ADD COLUMN IF NOT EXISTS visible_to_groups jsonb NOT NULL DEFAULT '[]'::jsonb`);
|
|
1664
|
+
await db.execute(sql `ALTER TABLE tax_zones ADD COLUMN IF NOT EXISTS visible_to_groups jsonb NOT NULL DEFAULT '[]'::jsonb`);
|
|
1665
|
+
visibilityColumnsEnsured = true;
|
|
1666
|
+
}
|
|
1667
|
+
catch (err) {
|
|
1668
|
+
console.error('[ensureVisibilityColumns] migration failed:', err);
|
|
1669
|
+
throw err;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
/** Best-effort variant for hot read paths. */
|
|
1673
|
+
async function ensureVisibilityColumnsSafe() {
|
|
1674
|
+
try {
|
|
1675
|
+
await ensureVisibilityColumns();
|
|
1676
|
+
}
|
|
1677
|
+
catch {
|
|
1678
|
+
// logged inside ensureVisibilityColumns
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* The single gating predicate: an entry with an empty `visibleToGroups` list
|
|
1683
|
+
* is visible to EVERYONE (guests included); a non-empty list requires the
|
|
1684
|
+
* trusted customer's group to be in it.
|
|
1685
|
+
*/
|
|
1686
|
+
export function isVisibleToGroup(visibleToGroups, groupId) {
|
|
1687
|
+
const groups = Array.isArray(visibleToGroups) ? visibleToGroups : [];
|
|
1688
|
+
if (groups.length === 0)
|
|
1689
|
+
return true;
|
|
1690
|
+
return !!groupId && groups.includes(groupId);
|
|
1691
|
+
}
|
|
1647
1692
|
let paymentMethodsSchemaEnsured = false;
|
|
1648
1693
|
/**
|
|
1649
1694
|
* Self-heal the payment-methods schema on stores provisioned before this
|
|
@@ -1682,6 +1727,8 @@ export async function ensurePaymentMethodsSchema() {
|
|
|
1682
1727
|
// FK-free (soft reference, like orders.customer_id) so this ALTER never
|
|
1683
1728
|
// depends on the store_locations table existing first.
|
|
1684
1729
|
await db.execute(sql `ALTER TABLE orders ADD COLUMN IF NOT EXISTS pickup_location_id uuid`);
|
|
1730
|
+
// Group gating (Phase 4) — payment_methods reads all pass through here.
|
|
1731
|
+
await ensureVisibilityColumns();
|
|
1685
1732
|
paymentMethodsSchemaEnsured = true;
|
|
1686
1733
|
}
|
|
1687
1734
|
catch (err) {
|
|
@@ -1707,15 +1754,20 @@ export async function findPaymentMethods() {
|
|
|
1707
1754
|
.from(schema.paymentMethods)
|
|
1708
1755
|
.orderBy(asc(schema.paymentMethods.sortOrder), asc(schema.paymentMethods.createdAt));
|
|
1709
1756
|
}
|
|
1710
|
-
/**
|
|
1711
|
-
|
|
1757
|
+
/**
|
|
1758
|
+
* Enabled methods only — what checkout offers alongside native Stripe.
|
|
1759
|
+
* `groupId` is the TRUSTED customer group (resolveCheckoutCustomer);
|
|
1760
|
+
* group-gated methods are hidden from guests and non-members.
|
|
1761
|
+
*/
|
|
1762
|
+
export async function findEnabledPaymentMethods(groupId) {
|
|
1712
1763
|
await ensurePaymentMethodsSchema();
|
|
1713
1764
|
const db = getDb();
|
|
1714
|
-
|
|
1765
|
+
const methods = await db
|
|
1715
1766
|
.select()
|
|
1716
1767
|
.from(schema.paymentMethods)
|
|
1717
1768
|
.where(eq(schema.paymentMethods.enabled, true))
|
|
1718
1769
|
.orderBy(asc(schema.paymentMethods.sortOrder), asc(schema.paymentMethods.createdAt));
|
|
1770
|
+
return methods.filter((m) => isVisibleToGroup(m.visibleToGroups, groupId));
|
|
1719
1771
|
}
|
|
1720
1772
|
export async function findPaymentMethodById(id) {
|
|
1721
1773
|
await ensurePaymentMethodsSchema();
|
|
@@ -1739,6 +1791,7 @@ export async function createPaymentMethod(data) {
|
|
|
1739
1791
|
enabled: data.enabled ?? true,
|
|
1740
1792
|
sortOrder: data.sortOrder ?? 0,
|
|
1741
1793
|
config: data.config ?? {},
|
|
1794
|
+
visibleToGroups: data.visibleToGroups ?? [],
|
|
1742
1795
|
})
|
|
1743
1796
|
.returning();
|
|
1744
1797
|
return method;
|
|
@@ -1759,6 +1812,8 @@ export async function updatePaymentMethod(id, data) {
|
|
|
1759
1812
|
set.sortOrder = data.sortOrder;
|
|
1760
1813
|
if (data.config !== undefined)
|
|
1761
1814
|
set.config = data.config;
|
|
1815
|
+
if (data.visibleToGroups !== undefined)
|
|
1816
|
+
set.visibleToGroups = data.visibleToGroups;
|
|
1762
1817
|
const [method] = await db
|
|
1763
1818
|
.update(schema.paymentMethods)
|
|
1764
1819
|
.set(set)
|
|
@@ -2574,6 +2629,8 @@ export async function findCarriersWithZonesAndRates() {
|
|
|
2574
2629
|
* Find all shipping zones with their rates and carrier info
|
|
2575
2630
|
*/
|
|
2576
2631
|
export async function findShippingZones() {
|
|
2632
|
+
// Rate SELECTs enumerate visible_to_groups — self-heal older stores first.
|
|
2633
|
+
await ensureVisibilityColumnsSafe();
|
|
2577
2634
|
const db = getDb();
|
|
2578
2635
|
// Get all zones with carrier info via join
|
|
2579
2636
|
const zonesWithCarriers = await db
|
|
@@ -2625,6 +2682,7 @@ export async function findShippingZones() {
|
|
|
2625
2682
|
estimatedDays: rate.estimatedDays,
|
|
2626
2683
|
isActive: rate.isActive,
|
|
2627
2684
|
sortOrder: rate.sortOrder,
|
|
2685
|
+
visibleToGroups: Array.isArray(rate.visibleToGroups) ? rate.visibleToGroups : [],
|
|
2628
2686
|
})),
|
|
2629
2687
|
}));
|
|
2630
2688
|
}
|
|
@@ -2686,6 +2744,7 @@ export async function deleteShippingZone(id) {
|
|
|
2686
2744
|
* Create a shipping rate for a zone
|
|
2687
2745
|
*/
|
|
2688
2746
|
export async function createShippingRate(data) {
|
|
2747
|
+
await ensureVisibilityColumnsSafe();
|
|
2689
2748
|
const db = getDb();
|
|
2690
2749
|
const [rate] = await db
|
|
2691
2750
|
.insert(schema.shippingRates)
|
|
@@ -2699,6 +2758,7 @@ export async function createShippingRate(data) {
|
|
|
2699
2758
|
estimatedDays: data.estimatedDays || null,
|
|
2700
2759
|
isActive: data.isActive ?? true,
|
|
2701
2760
|
sortOrder: data.sortOrder ?? 0,
|
|
2761
|
+
visibleToGroups: data.visibleToGroups ?? [],
|
|
2702
2762
|
})
|
|
2703
2763
|
.returning();
|
|
2704
2764
|
return rate;
|
|
@@ -2707,6 +2767,7 @@ export async function createShippingRate(data) {
|
|
|
2707
2767
|
* Update a shipping rate
|
|
2708
2768
|
*/
|
|
2709
2769
|
export async function updateShippingRate(id, data) {
|
|
2770
|
+
await ensureVisibilityColumnsSafe();
|
|
2710
2771
|
const db = getDb();
|
|
2711
2772
|
const updateData = {};
|
|
2712
2773
|
if (data.name !== undefined)
|
|
@@ -2725,6 +2786,8 @@ export async function updateShippingRate(id, data) {
|
|
|
2725
2786
|
updateData.isActive = data.isActive;
|
|
2726
2787
|
if (data.sortOrder !== undefined)
|
|
2727
2788
|
updateData.sortOrder = data.sortOrder;
|
|
2789
|
+
if (data.visibleToGroups !== undefined)
|
|
2790
|
+
updateData.visibleToGroups = data.visibleToGroups;
|
|
2728
2791
|
const [rate] = await db
|
|
2729
2792
|
.update(schema.shippingRates)
|
|
2730
2793
|
.set(updateData)
|
|
@@ -2751,7 +2814,7 @@ export async function deleteShippingRate(id) {
|
|
|
2751
2814
|
* @param orderAmount - Order subtotal in dollars
|
|
2752
2815
|
* @returns Array of applicable shipping rates with carrier info
|
|
2753
2816
|
*/
|
|
2754
|
-
export async function findShippingRatesForCountry(country, orderAmount) {
|
|
2817
|
+
export async function findShippingRatesForCountry(country, orderAmount, groupId) {
|
|
2755
2818
|
const zones = await findActiveShippingZones();
|
|
2756
2819
|
const applicableRates = [];
|
|
2757
2820
|
for (const zone of zones) {
|
|
@@ -2767,6 +2830,10 @@ export async function findShippingRatesForCountry(country, orderAmount) {
|
|
|
2767
2830
|
for (const rate of zone.rates) {
|
|
2768
2831
|
if (!rate.isActive)
|
|
2769
2832
|
continue;
|
|
2833
|
+
// Group gating: a rate restricted to groups the customer isn't in is
|
|
2834
|
+
// simply not offered (guests see only unrestricted rates).
|
|
2835
|
+
if (!isVisibleToGroup(rate.visibleToGroups, groupId))
|
|
2836
|
+
continue;
|
|
2770
2837
|
// Check min/max order amount constraints
|
|
2771
2838
|
if (rate.minOrderAmount !== null && orderAmount < rate.minOrderAmount)
|
|
2772
2839
|
continue;
|
|
@@ -2795,8 +2862,8 @@ export async function findShippingRatesForCountry(country, orderAmount) {
|
|
|
2795
2862
|
* @param orderAmount - Order subtotal in dollars
|
|
2796
2863
|
* @returns Shipping options grouped by carrier
|
|
2797
2864
|
*/
|
|
2798
|
-
export async function findShippingOptionsForCountry(country, orderAmount) {
|
|
2799
|
-
const rates = await findShippingRatesForCountry(country, orderAmount);
|
|
2865
|
+
export async function findShippingOptionsForCountry(country, orderAmount, groupId) {
|
|
2866
|
+
const rates = await findShippingRatesForCountry(country, orderAmount, groupId);
|
|
2800
2867
|
// Group by carrier
|
|
2801
2868
|
const carrierMap = new Map();
|
|
2802
2869
|
for (const rate of rates) {
|
|
@@ -2831,6 +2898,8 @@ export async function findShippingOptionsForCountry(country, orderAmount) {
|
|
|
2831
2898
|
* Find all tax zones ordered by priority (sortOrder ascending)
|
|
2832
2899
|
*/
|
|
2833
2900
|
export async function findTaxZones() {
|
|
2901
|
+
// The SELECT enumerates visible_to_groups — self-heal older stores first.
|
|
2902
|
+
await ensureVisibilityColumnsSafe();
|
|
2834
2903
|
const db = getDb();
|
|
2835
2904
|
const zones = await db
|
|
2836
2905
|
.select()
|
|
@@ -2844,6 +2913,7 @@ export async function findTaxZones() {
|
|
|
2844
2913
|
taxRate: Number(zone.taxRate),
|
|
2845
2914
|
isActive: zone.isActive,
|
|
2846
2915
|
sortOrder: zone.sortOrder,
|
|
2916
|
+
visibleToGroups: Array.isArray(zone.visibleToGroups) ? zone.visibleToGroups : [],
|
|
2847
2917
|
createdAt: zone.createdAt,
|
|
2848
2918
|
updatedAt: zone.updatedAt,
|
|
2849
2919
|
}));
|
|
@@ -2866,6 +2936,7 @@ export async function findTaxZoneById(id) {
|
|
|
2866
2936
|
* Create a new tax zone
|
|
2867
2937
|
*/
|
|
2868
2938
|
export async function createTaxZone(data) {
|
|
2939
|
+
await ensureVisibilityColumnsSafe();
|
|
2869
2940
|
const db = getDb();
|
|
2870
2941
|
const [zone] = await db
|
|
2871
2942
|
.insert(schema.taxZones)
|
|
@@ -2876,6 +2947,7 @@ export async function createTaxZone(data) {
|
|
|
2876
2947
|
taxRate: String(data.taxRate),
|
|
2877
2948
|
isActive: data.isActive ?? true,
|
|
2878
2949
|
sortOrder: data.sortOrder ?? 0,
|
|
2950
|
+
visibleToGroups: data.visibleToGroups ?? [],
|
|
2879
2951
|
})
|
|
2880
2952
|
.returning();
|
|
2881
2953
|
return zone;
|
|
@@ -2884,6 +2956,7 @@ export async function createTaxZone(data) {
|
|
|
2884
2956
|
* Update a tax zone
|
|
2885
2957
|
*/
|
|
2886
2958
|
export async function updateTaxZone(id, data) {
|
|
2959
|
+
await ensureVisibilityColumnsSafe();
|
|
2887
2960
|
const db = getDb();
|
|
2888
2961
|
const updateData = { updatedAt: new Date() };
|
|
2889
2962
|
if (data.name !== undefined)
|
|
@@ -2898,6 +2971,8 @@ export async function updateTaxZone(id, data) {
|
|
|
2898
2971
|
updateData.isActive = data.isActive;
|
|
2899
2972
|
if (data.sortOrder !== undefined)
|
|
2900
2973
|
updateData.sortOrder = data.sortOrder;
|
|
2974
|
+
if (data.visibleToGroups !== undefined)
|
|
2975
|
+
updateData.visibleToGroups = data.visibleToGroups;
|
|
2901
2976
|
const [zone] = await db
|
|
2902
2977
|
.update(schema.taxZones)
|
|
2903
2978
|
.set(updateData)
|
|
@@ -2929,11 +3004,16 @@ export async function deleteTaxZone(id) {
|
|
|
2929
3004
|
* @param state - State/province code for US (e.g., 'CA', 'NY')
|
|
2930
3005
|
* @returns Tax rate info or null if no matching zone
|
|
2931
3006
|
*/
|
|
2932
|
-
export async function findTaxRateForAddress(country, state) {
|
|
3007
|
+
export async function findTaxRateForAddress(country, state, groupId) {
|
|
2933
3008
|
const zones = await findActiveTaxZones();
|
|
2934
3009
|
const upperCountry = country.toUpperCase();
|
|
2935
3010
|
const upperState = state?.toUpperCase() || '';
|
|
2936
3011
|
for (const zone of zones) {
|
|
3012
|
+
// Group gating: a gated zone is SKIPPED for non-members, who fall
|
|
3013
|
+
// through to the next matching zone by priority (e.g. a pro-only 0%
|
|
3014
|
+
// zone listed above the standard rate).
|
|
3015
|
+
if (!isVisibleToGroup(zone.visibleToGroups, groupId))
|
|
3016
|
+
continue;
|
|
2937
3017
|
// Check if zone covers this country
|
|
2938
3018
|
const hasWildcard = zone.countries.includes('*');
|
|
2939
3019
|
const hasCountry = zone.countries.includes(upperCountry);
|