omni-sync-sdk 0.14.2 → 0.15.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/README.md +9 -7
- package/dist/index.d.mts +201 -12
- package/dist/index.d.ts +201 -12
- package/dist/index.js +108 -5
- package/dist/index.mjs +108 -5
- package/package.json +76 -76
package/README.md
CHANGED
|
@@ -479,7 +479,7 @@ function SearchInput() {
|
|
|
479
479
|
{suggestions && (
|
|
480
480
|
<div className="suggestions">
|
|
481
481
|
{suggestions.products.map((product) => (
|
|
482
|
-
<a key={product.id} href={`/products/${product.
|
|
482
|
+
<a key={product.id} href={`/products/${product.slug}`}>
|
|
483
483
|
<img src={product.image || '/placeholder.png'} alt={product.name} />
|
|
484
484
|
<span>{product.name}</span>
|
|
485
485
|
<span>${product.basePrice}</span>
|
|
@@ -2128,7 +2128,7 @@ export default function HomePage() {
|
|
|
2128
2128
|
return (
|
|
2129
2129
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
|
2130
2130
|
{products.map((product) => (
|
|
2131
|
-
<a key={product.id} href={`/products/${product.
|
|
2131
|
+
<a key={product.id} href={`/products/${product.slug}`} className="group">
|
|
2132
2132
|
<img
|
|
2133
2133
|
src={product.images?.[0]?.url || '/placeholder.jpg'}
|
|
2134
2134
|
alt={product.name}
|
|
@@ -2185,7 +2185,7 @@ export default function ProductsPage() {
|
|
|
2185
2185
|
<div>
|
|
2186
2186
|
<div className="grid grid-cols-3 gap-6">
|
|
2187
2187
|
{data.data.map((product) => (
|
|
2188
|
-
<a key={product.id} href={`/products/${product.
|
|
2188
|
+
<a key={product.id} href={`/products/${product.slug}`}>
|
|
2189
2189
|
<img src={product.images?.[0]?.url} alt={product.name} />
|
|
2190
2190
|
<h3>{product.name}</h3>
|
|
2191
2191
|
<p>${product.salePrice || product.basePrice}</p>
|
|
@@ -2217,7 +2217,8 @@ import { omni } from '@/lib/omni-sync';
|
|
|
2217
2217
|
import { isHtmlDescription } from 'omni-sync-sdk';
|
|
2218
2218
|
import type { Product } from 'omni-sync-sdk';
|
|
2219
2219
|
|
|
2220
|
-
|
|
2220
|
+
// Route: /products/[slug]/page.tsx - uses URL-friendly slug instead of ID
|
|
2221
|
+
export default function ProductPage({ params }: { params: { slug: string } }) {
|
|
2221
2222
|
const [product, setProduct] = useState<Product | null>(null);
|
|
2222
2223
|
const [selectedVariant, setSelectedVariant] = useState<string | null>(null);
|
|
2223
2224
|
const [quantity, setQuantity] = useState(1);
|
|
@@ -2226,7 +2227,8 @@ export default function ProductPage({ params }: { params: { id: string } }) {
|
|
|
2226
2227
|
useEffect(() => {
|
|
2227
2228
|
async function load() {
|
|
2228
2229
|
try {
|
|
2229
|
-
|
|
2230
|
+
// Use getProductBySlug for SEO-friendly URLs
|
|
2231
|
+
const p = await omni.getProductBySlug(params.slug);
|
|
2230
2232
|
setProduct(p);
|
|
2231
2233
|
if (p.variants && p.variants.length > 0) {
|
|
2232
2234
|
setSelectedVariant(p.variants[0].id);
|
|
@@ -2236,7 +2238,7 @@ export default function ProductPage({ params }: { params: { id: string } }) {
|
|
|
2236
2238
|
}
|
|
2237
2239
|
}
|
|
2238
2240
|
load();
|
|
2239
|
-
}, [params.
|
|
2241
|
+
}, [params.slug]);
|
|
2240
2242
|
|
|
2241
2243
|
const handleAddToCart = () => {
|
|
2242
2244
|
if (!product) return;
|
|
@@ -3336,7 +3338,7 @@ When building a store, implement these pages:
|
|
|
3336
3338
|
|
|
3337
3339
|
- [ ] **Home** (`/`) - Product grid
|
|
3338
3340
|
- [ ] **Products** (`/products`) - Product list with pagination
|
|
3339
|
-
- [ ] **Product Detail** (`/products/[
|
|
3341
|
+
- [ ] **Product Detail** (`/products/[slug]`) - Single product with Add to Cart (use `getProductBySlug(slug)`)
|
|
3340
3342
|
- [ ] **Cart** (`/cart`) - Cart items, update quantity, remove
|
|
3341
3343
|
- [ ] **Checkout** (`/checkout`) - Multi-step checkout flow
|
|
3342
3344
|
- [ ] **⚠️ Payment** (`/checkout/payment`) - **REQUIRED!** Use `getPaymentProviders()` to show Stripe/PayPal forms
|
package/dist/index.d.mts
CHANGED
|
@@ -349,6 +349,7 @@ interface ProductQueryParams {
|
|
|
349
349
|
interface ProductSuggestion {
|
|
350
350
|
id: string;
|
|
351
351
|
name: string;
|
|
352
|
+
slug: string | null;
|
|
352
353
|
image: string | null;
|
|
353
354
|
basePrice: number;
|
|
354
355
|
salePrice?: number | null;
|
|
@@ -914,6 +915,12 @@ interface Cart {
|
|
|
914
915
|
createdAt: string;
|
|
915
916
|
/** ISO timestamp when cart was last updated */
|
|
916
917
|
updatedAt: string;
|
|
918
|
+
/**
|
|
919
|
+
* Reservation information (only present when reservation strategy is ON_CART).
|
|
920
|
+
* Use this to display countdown timer to customers.
|
|
921
|
+
* @see ReservationInfo
|
|
922
|
+
*/
|
|
923
|
+
reservation?: ReservationInfo;
|
|
917
924
|
}
|
|
918
925
|
interface AddToCartDto {
|
|
919
926
|
productId: string;
|
|
@@ -1256,12 +1263,13 @@ interface ShippingRate {
|
|
|
1256
1263
|
/**
|
|
1257
1264
|
* Represents a checkout session for completing a purchase.
|
|
1258
1265
|
*
|
|
1259
|
-
* **Checkout Flow:**
|
|
1260
|
-
* 1.
|
|
1261
|
-
* 2.
|
|
1262
|
-
* 3.
|
|
1263
|
-
*
|
|
1264
|
-
*
|
|
1266
|
+
* **Simplified Checkout Flow (3 steps):**
|
|
1267
|
+
* 1. Set shipping address (includes email): `setShippingAddress(id, { email, ...address })` - returns rates
|
|
1268
|
+
* 2. Select shipping method: `selectShippingMethod(id, rateId)`
|
|
1269
|
+
* 3. Pay with Stripe: `createPaymentIntent(id)` → `stripe.confirmPayment()` → Order created automatically!
|
|
1270
|
+
*
|
|
1271
|
+
* **Note:** Order is created automatically via webhook when payment succeeds.
|
|
1272
|
+
* No need to call `completeCheckout()` - it happens automatically.
|
|
1265
1273
|
*
|
|
1266
1274
|
* **IMPORTANT: Price fields are strings**
|
|
1267
1275
|
* All monetary fields (subtotal, discountAmount, shippingAmount, taxAmount, total)
|
|
@@ -1342,6 +1350,12 @@ interface Checkout {
|
|
|
1342
1350
|
createdAt: string;
|
|
1343
1351
|
/** Last update timestamp */
|
|
1344
1352
|
updatedAt: string;
|
|
1353
|
+
/**
|
|
1354
|
+
* Reservation information (present when reservation strategy is ON_CHECKOUT or ON_CART).
|
|
1355
|
+
* Use this to display countdown timer to customers.
|
|
1356
|
+
* @see ReservationInfo
|
|
1357
|
+
*/
|
|
1358
|
+
reservation?: ReservationInfo;
|
|
1345
1359
|
}
|
|
1346
1360
|
interface CreateCheckoutDto {
|
|
1347
1361
|
cartId: string;
|
|
@@ -1354,7 +1368,13 @@ interface SetCheckoutCustomerDto {
|
|
|
1354
1368
|
phone?: string;
|
|
1355
1369
|
acceptsMarketing?: boolean;
|
|
1356
1370
|
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Shipping address with customer email (required for checkout).
|
|
1373
|
+
* Email is included here to simplify the checkout flow - no need for separate setCheckoutCustomer call.
|
|
1374
|
+
*/
|
|
1357
1375
|
interface SetShippingAddressDto {
|
|
1376
|
+
/** Customer email (required) - used for order confirmation */
|
|
1377
|
+
email: string;
|
|
1358
1378
|
firstName: string;
|
|
1359
1379
|
lastName: string;
|
|
1360
1380
|
company?: string;
|
|
@@ -1365,8 +1385,23 @@ interface SetShippingAddressDto {
|
|
|
1365
1385
|
postalCode: string;
|
|
1366
1386
|
country: string;
|
|
1367
1387
|
phone?: string;
|
|
1388
|
+
/** Whether customer accepts marketing emails */
|
|
1389
|
+
acceptsMarketing?: boolean;
|
|
1368
1390
|
}
|
|
1369
|
-
|
|
1391
|
+
/**
|
|
1392
|
+
* Billing address (email not required - already set in shipping address)
|
|
1393
|
+
*/
|
|
1394
|
+
interface SetBillingAddressDto {
|
|
1395
|
+
firstName: string;
|
|
1396
|
+
lastName: string;
|
|
1397
|
+
company?: string;
|
|
1398
|
+
line1: string;
|
|
1399
|
+
line2?: string;
|
|
1400
|
+
city: string;
|
|
1401
|
+
region?: string;
|
|
1402
|
+
postalCode: string;
|
|
1403
|
+
country: string;
|
|
1404
|
+
phone?: string;
|
|
1370
1405
|
sameAsShipping?: boolean;
|
|
1371
1406
|
}
|
|
1372
1407
|
interface SelectShippingMethodDto {
|
|
@@ -1667,6 +1702,8 @@ interface PaymentProviderConfig {
|
|
|
1667
1702
|
name: string;
|
|
1668
1703
|
/** Public/publishable key (safe to expose) */
|
|
1669
1704
|
publicKey: string;
|
|
1705
|
+
/** Stripe Connect account ID (for OAuth-connected accounts) */
|
|
1706
|
+
stripeAccountId?: string;
|
|
1670
1707
|
/** Supported payment methods: ['card', 'ideal', 'bancontact'] */
|
|
1671
1708
|
supportedMethods: string[];
|
|
1672
1709
|
/** Whether this is test/sandbox mode */
|
|
@@ -1692,7 +1729,10 @@ interface PaymentProviderConfig {
|
|
|
1692
1729
|
* const paypalProvider = providers.find(p => p.provider === 'paypal');
|
|
1693
1730
|
*
|
|
1694
1731
|
* if (stripeProvider) {
|
|
1695
|
-
* // Initialize Stripe.js with
|
|
1732
|
+
* // Initialize Stripe.js with options for Connect
|
|
1733
|
+
* const stripe = await loadStripe(stripeProvider.publicKey, {
|
|
1734
|
+
* stripeAccount: stripeProvider.stripeAccountId, // For Stripe Connect
|
|
1735
|
+
* });
|
|
1696
1736
|
* }
|
|
1697
1737
|
* if (paypalProvider) {
|
|
1698
1738
|
* // Initialize PayPal SDK with paypalProvider.publicKey as clientId
|
|
@@ -1756,6 +1796,83 @@ interface PaymentStatus {
|
|
|
1756
1796
|
/** Payment intent ID from provider */
|
|
1757
1797
|
paymentIntentId?: string;
|
|
1758
1798
|
}
|
|
1799
|
+
/**
|
|
1800
|
+
* When inventory is reserved for customers.
|
|
1801
|
+
* Configured per vibe-coded connection by the store owner.
|
|
1802
|
+
*
|
|
1803
|
+
* - ON_PAYMENT: Stock is only reserved when payment is completed (default, safest)
|
|
1804
|
+
* - ON_CHECKOUT: Stock is reserved when checkout is created
|
|
1805
|
+
* - ON_CART: Stock is reserved immediately when added to cart (most aggressive)
|
|
1806
|
+
*/
|
|
1807
|
+
type InventoryReservationStrategy = 'ON_PAYMENT' | 'ON_CHECKOUT' | 'ON_CART';
|
|
1808
|
+
/**
|
|
1809
|
+
* Information about a customer's inventory reservation.
|
|
1810
|
+
* Included in cart/checkout responses when reservations are active.
|
|
1811
|
+
*
|
|
1812
|
+
* @example
|
|
1813
|
+
* ```typescript
|
|
1814
|
+
* const cart = await omni.getCart(cartId);
|
|
1815
|
+
* if (cart.reservation?.hasReservation) {
|
|
1816
|
+
* const remaining = cart.reservation.remainingSeconds;
|
|
1817
|
+
* console.log(`Items reserved for ${remaining} seconds`);
|
|
1818
|
+
* }
|
|
1819
|
+
* ```
|
|
1820
|
+
*/
|
|
1821
|
+
interface ReservationInfo {
|
|
1822
|
+
/** Whether there is an active reservation */
|
|
1823
|
+
hasReservation: boolean;
|
|
1824
|
+
/** ISO timestamp when reservation expires */
|
|
1825
|
+
expiresAt?: string;
|
|
1826
|
+
/** Remaining time in seconds before reservation expires */
|
|
1827
|
+
remainingSeconds?: number;
|
|
1828
|
+
/** The reservation strategy in use */
|
|
1829
|
+
strategy: InventoryReservationStrategy;
|
|
1830
|
+
/** Custom message from store owner (supports {time} placeholder) */
|
|
1831
|
+
countdownMessage?: string;
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Product availability including reserved quantities.
|
|
1835
|
+
* Use this to show accurate stock to customers when reservations are enabled.
|
|
1836
|
+
*
|
|
1837
|
+
* @example
|
|
1838
|
+
* ```typescript
|
|
1839
|
+
* const availability = await omni.getAvailability(['prod_123', 'prod_456']);
|
|
1840
|
+
* availability.forEach(item => {
|
|
1841
|
+
* if (!item.canPurchase) {
|
|
1842
|
+
* console.log(`${item.productId}: Cannot purchase`);
|
|
1843
|
+
* } else if (item.lowStock) {
|
|
1844
|
+
* console.log(`${item.productId}: Only ${item.available} left!`);
|
|
1845
|
+
* }
|
|
1846
|
+
* });
|
|
1847
|
+
* ```
|
|
1848
|
+
*/
|
|
1849
|
+
interface ProductAvailability {
|
|
1850
|
+
/** Product ID */
|
|
1851
|
+
productId: string;
|
|
1852
|
+
/** Variant ID (null for simple products) */
|
|
1853
|
+
variantId?: string | null;
|
|
1854
|
+
/** Inventory tracking mode */
|
|
1855
|
+
trackingMode: InventoryTrackingMode;
|
|
1856
|
+
/** Total stock quantity */
|
|
1857
|
+
total: number;
|
|
1858
|
+
/** Quantity currently reserved by other customers */
|
|
1859
|
+
reserved: number;
|
|
1860
|
+
/** Available for purchase (total - reserved) */
|
|
1861
|
+
available: number;
|
|
1862
|
+
/** Whether the product can be purchased */
|
|
1863
|
+
canPurchase: boolean;
|
|
1864
|
+
/** Whether stock is below low stock threshold */
|
|
1865
|
+
lowStock?: boolean;
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* Response from extending a reservation
|
|
1869
|
+
*/
|
|
1870
|
+
interface ExtendReservationResponse {
|
|
1871
|
+
/** Whether the extension was successful */
|
|
1872
|
+
success: boolean;
|
|
1873
|
+
/** Updated reservation info */
|
|
1874
|
+
reservation: ReservationInfo;
|
|
1875
|
+
}
|
|
1759
1876
|
interface OmniSyncApiError {
|
|
1760
1877
|
statusCode: number;
|
|
1761
1878
|
message: string;
|
|
@@ -2870,12 +2987,16 @@ declare class OmniSyncClient {
|
|
|
2870
2987
|
*/
|
|
2871
2988
|
setCheckoutCustomer(checkoutId: string, data: SetCheckoutCustomerDto): Promise<Checkout>;
|
|
2872
2989
|
/**
|
|
2873
|
-
* Set shipping address on checkout
|
|
2874
|
-
* Returns the checkout and available shipping rates for the address
|
|
2990
|
+
* Set shipping address on checkout (includes customer email).
|
|
2991
|
+
* Returns the checkout and available shipping rates for the address.
|
|
2992
|
+
*
|
|
2993
|
+
* **This is the first step of the simplified checkout flow.**
|
|
2994
|
+
* Email is required and will be used for order confirmation.
|
|
2875
2995
|
*
|
|
2876
2996
|
* @example
|
|
2877
2997
|
* ```typescript
|
|
2878
2998
|
* const { checkout, rates } = await omni.setShippingAddress('checkout_123', {
|
|
2999
|
+
* email: 'customer@example.com', // Required!
|
|
2879
3000
|
* firstName: 'John',
|
|
2880
3001
|
* lastName: 'Doe',
|
|
2881
3002
|
* line1: '123 Main St',
|
|
@@ -2992,9 +3113,11 @@ declare class OmniSyncClient {
|
|
|
2992
3113
|
* const stripeProvider = providers.find(p => p.provider === 'stripe');
|
|
2993
3114
|
* const paypalProvider = providers.find(p => p.provider === 'paypal');
|
|
2994
3115
|
*
|
|
2995
|
-
* // Initialize Stripe if available
|
|
3116
|
+
* // Initialize Stripe if available (with Connect account support)
|
|
2996
3117
|
* if (stripeProvider) {
|
|
2997
|
-
* const stripe = await loadStripe(stripeProvider.publicKey
|
|
3118
|
+
* const stripe = await loadStripe(stripeProvider.publicKey, {
|
|
3119
|
+
* stripeAccount: stripeProvider.stripeAccountId, // For Stripe Connect
|
|
3120
|
+
* });
|
|
2998
3121
|
* // Show Stripe payment form
|
|
2999
3122
|
* }
|
|
3000
3123
|
*
|
|
@@ -3398,6 +3521,72 @@ declare class OmniSyncClient {
|
|
|
3398
3521
|
* ```
|
|
3399
3522
|
*/
|
|
3400
3523
|
testCustomApiConnection(integrationId: string): Promise<CustomApiTestResult>;
|
|
3524
|
+
/**
|
|
3525
|
+
* Get product availability including reserved quantities.
|
|
3526
|
+
* Use this to show accurate stock to customers when reservations are enabled.
|
|
3527
|
+
*
|
|
3528
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
3529
|
+
*
|
|
3530
|
+
* @param productIds - Array of product IDs to check availability for
|
|
3531
|
+
* @returns Array of availability info for each product
|
|
3532
|
+
*
|
|
3533
|
+
* @example
|
|
3534
|
+
* ```typescript
|
|
3535
|
+
* const availability = await omni.getAvailability(['prod_123', 'prod_456']);
|
|
3536
|
+
* availability.forEach(item => {
|
|
3537
|
+
* if (!item.canPurchase) {
|
|
3538
|
+
* console.log(`${item.productId}: Cannot purchase`);
|
|
3539
|
+
* } else if (item.lowStock) {
|
|
3540
|
+
* console.log(`${item.productId}: Only ${item.available} left!`);
|
|
3541
|
+
* } else {
|
|
3542
|
+
* console.log(`${item.productId}: ${item.available} available`);
|
|
3543
|
+
* }
|
|
3544
|
+
* });
|
|
3545
|
+
* ```
|
|
3546
|
+
*/
|
|
3547
|
+
getAvailability(productIds: string[]): Promise<ProductAvailability[]>;
|
|
3548
|
+
/**
|
|
3549
|
+
* Extend an active reservation to prevent it from expiring.
|
|
3550
|
+
* Call this when a customer is still active in checkout to keep their items reserved.
|
|
3551
|
+
*
|
|
3552
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
3553
|
+
* Only works when reservation strategy is ON_CART or ON_CHECKOUT
|
|
3554
|
+
*
|
|
3555
|
+
* @param options - Either cartId or checkoutId to identify the reservation
|
|
3556
|
+
* @returns Updated reservation info
|
|
3557
|
+
*
|
|
3558
|
+
* @example
|
|
3559
|
+
* ```typescript
|
|
3560
|
+
* // Extend reservation when customer shows activity
|
|
3561
|
+
* const result = await omni.extendReservation({ checkoutId: 'chk_123' });
|
|
3562
|
+
* if (result.success) {
|
|
3563
|
+
* console.log(`Reservation extended until ${result.reservation.expiresAt}`);
|
|
3564
|
+
* }
|
|
3565
|
+
* ```
|
|
3566
|
+
*/
|
|
3567
|
+
extendReservation(options: {
|
|
3568
|
+
cartId?: string;
|
|
3569
|
+
checkoutId?: string;
|
|
3570
|
+
}): Promise<ExtendReservationResponse>;
|
|
3571
|
+
/**
|
|
3572
|
+
* Release an active reservation, returning items to available stock.
|
|
3573
|
+
* Call this when a customer abandons their cart/checkout.
|
|
3574
|
+
*
|
|
3575
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
3576
|
+
* Only works when reservation strategy is ON_CART or ON_CHECKOUT
|
|
3577
|
+
*
|
|
3578
|
+
* @param options - Either cartId or checkoutId to identify the reservation
|
|
3579
|
+
*
|
|
3580
|
+
* @example
|
|
3581
|
+
* ```typescript
|
|
3582
|
+
* // Release reservation when customer abandons checkout
|
|
3583
|
+
* await omni.releaseReservation({ checkoutId: 'chk_123' });
|
|
3584
|
+
* ```
|
|
3585
|
+
*/
|
|
3586
|
+
releaseReservation(options: {
|
|
3587
|
+
cartId?: string;
|
|
3588
|
+
checkoutId?: string;
|
|
3589
|
+
}): Promise<void>;
|
|
3401
3590
|
}
|
|
3402
3591
|
/**
|
|
3403
3592
|
* Custom error class for Omni-Sync API errors
|
package/dist/index.d.ts
CHANGED
|
@@ -349,6 +349,7 @@ interface ProductQueryParams {
|
|
|
349
349
|
interface ProductSuggestion {
|
|
350
350
|
id: string;
|
|
351
351
|
name: string;
|
|
352
|
+
slug: string | null;
|
|
352
353
|
image: string | null;
|
|
353
354
|
basePrice: number;
|
|
354
355
|
salePrice?: number | null;
|
|
@@ -914,6 +915,12 @@ interface Cart {
|
|
|
914
915
|
createdAt: string;
|
|
915
916
|
/** ISO timestamp when cart was last updated */
|
|
916
917
|
updatedAt: string;
|
|
918
|
+
/**
|
|
919
|
+
* Reservation information (only present when reservation strategy is ON_CART).
|
|
920
|
+
* Use this to display countdown timer to customers.
|
|
921
|
+
* @see ReservationInfo
|
|
922
|
+
*/
|
|
923
|
+
reservation?: ReservationInfo;
|
|
917
924
|
}
|
|
918
925
|
interface AddToCartDto {
|
|
919
926
|
productId: string;
|
|
@@ -1256,12 +1263,13 @@ interface ShippingRate {
|
|
|
1256
1263
|
/**
|
|
1257
1264
|
* Represents a checkout session for completing a purchase.
|
|
1258
1265
|
*
|
|
1259
|
-
* **Checkout Flow:**
|
|
1260
|
-
* 1.
|
|
1261
|
-
* 2.
|
|
1262
|
-
* 3.
|
|
1263
|
-
*
|
|
1264
|
-
*
|
|
1266
|
+
* **Simplified Checkout Flow (3 steps):**
|
|
1267
|
+
* 1. Set shipping address (includes email): `setShippingAddress(id, { email, ...address })` - returns rates
|
|
1268
|
+
* 2. Select shipping method: `selectShippingMethod(id, rateId)`
|
|
1269
|
+
* 3. Pay with Stripe: `createPaymentIntent(id)` → `stripe.confirmPayment()` → Order created automatically!
|
|
1270
|
+
*
|
|
1271
|
+
* **Note:** Order is created automatically via webhook when payment succeeds.
|
|
1272
|
+
* No need to call `completeCheckout()` - it happens automatically.
|
|
1265
1273
|
*
|
|
1266
1274
|
* **IMPORTANT: Price fields are strings**
|
|
1267
1275
|
* All monetary fields (subtotal, discountAmount, shippingAmount, taxAmount, total)
|
|
@@ -1342,6 +1350,12 @@ interface Checkout {
|
|
|
1342
1350
|
createdAt: string;
|
|
1343
1351
|
/** Last update timestamp */
|
|
1344
1352
|
updatedAt: string;
|
|
1353
|
+
/**
|
|
1354
|
+
* Reservation information (present when reservation strategy is ON_CHECKOUT or ON_CART).
|
|
1355
|
+
* Use this to display countdown timer to customers.
|
|
1356
|
+
* @see ReservationInfo
|
|
1357
|
+
*/
|
|
1358
|
+
reservation?: ReservationInfo;
|
|
1345
1359
|
}
|
|
1346
1360
|
interface CreateCheckoutDto {
|
|
1347
1361
|
cartId: string;
|
|
@@ -1354,7 +1368,13 @@ interface SetCheckoutCustomerDto {
|
|
|
1354
1368
|
phone?: string;
|
|
1355
1369
|
acceptsMarketing?: boolean;
|
|
1356
1370
|
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Shipping address with customer email (required for checkout).
|
|
1373
|
+
* Email is included here to simplify the checkout flow - no need for separate setCheckoutCustomer call.
|
|
1374
|
+
*/
|
|
1357
1375
|
interface SetShippingAddressDto {
|
|
1376
|
+
/** Customer email (required) - used for order confirmation */
|
|
1377
|
+
email: string;
|
|
1358
1378
|
firstName: string;
|
|
1359
1379
|
lastName: string;
|
|
1360
1380
|
company?: string;
|
|
@@ -1365,8 +1385,23 @@ interface SetShippingAddressDto {
|
|
|
1365
1385
|
postalCode: string;
|
|
1366
1386
|
country: string;
|
|
1367
1387
|
phone?: string;
|
|
1388
|
+
/** Whether customer accepts marketing emails */
|
|
1389
|
+
acceptsMarketing?: boolean;
|
|
1368
1390
|
}
|
|
1369
|
-
|
|
1391
|
+
/**
|
|
1392
|
+
* Billing address (email not required - already set in shipping address)
|
|
1393
|
+
*/
|
|
1394
|
+
interface SetBillingAddressDto {
|
|
1395
|
+
firstName: string;
|
|
1396
|
+
lastName: string;
|
|
1397
|
+
company?: string;
|
|
1398
|
+
line1: string;
|
|
1399
|
+
line2?: string;
|
|
1400
|
+
city: string;
|
|
1401
|
+
region?: string;
|
|
1402
|
+
postalCode: string;
|
|
1403
|
+
country: string;
|
|
1404
|
+
phone?: string;
|
|
1370
1405
|
sameAsShipping?: boolean;
|
|
1371
1406
|
}
|
|
1372
1407
|
interface SelectShippingMethodDto {
|
|
@@ -1667,6 +1702,8 @@ interface PaymentProviderConfig {
|
|
|
1667
1702
|
name: string;
|
|
1668
1703
|
/** Public/publishable key (safe to expose) */
|
|
1669
1704
|
publicKey: string;
|
|
1705
|
+
/** Stripe Connect account ID (for OAuth-connected accounts) */
|
|
1706
|
+
stripeAccountId?: string;
|
|
1670
1707
|
/** Supported payment methods: ['card', 'ideal', 'bancontact'] */
|
|
1671
1708
|
supportedMethods: string[];
|
|
1672
1709
|
/** Whether this is test/sandbox mode */
|
|
@@ -1692,7 +1729,10 @@ interface PaymentProviderConfig {
|
|
|
1692
1729
|
* const paypalProvider = providers.find(p => p.provider === 'paypal');
|
|
1693
1730
|
*
|
|
1694
1731
|
* if (stripeProvider) {
|
|
1695
|
-
* // Initialize Stripe.js with
|
|
1732
|
+
* // Initialize Stripe.js with options for Connect
|
|
1733
|
+
* const stripe = await loadStripe(stripeProvider.publicKey, {
|
|
1734
|
+
* stripeAccount: stripeProvider.stripeAccountId, // For Stripe Connect
|
|
1735
|
+
* });
|
|
1696
1736
|
* }
|
|
1697
1737
|
* if (paypalProvider) {
|
|
1698
1738
|
* // Initialize PayPal SDK with paypalProvider.publicKey as clientId
|
|
@@ -1756,6 +1796,83 @@ interface PaymentStatus {
|
|
|
1756
1796
|
/** Payment intent ID from provider */
|
|
1757
1797
|
paymentIntentId?: string;
|
|
1758
1798
|
}
|
|
1799
|
+
/**
|
|
1800
|
+
* When inventory is reserved for customers.
|
|
1801
|
+
* Configured per vibe-coded connection by the store owner.
|
|
1802
|
+
*
|
|
1803
|
+
* - ON_PAYMENT: Stock is only reserved when payment is completed (default, safest)
|
|
1804
|
+
* - ON_CHECKOUT: Stock is reserved when checkout is created
|
|
1805
|
+
* - ON_CART: Stock is reserved immediately when added to cart (most aggressive)
|
|
1806
|
+
*/
|
|
1807
|
+
type InventoryReservationStrategy = 'ON_PAYMENT' | 'ON_CHECKOUT' | 'ON_CART';
|
|
1808
|
+
/**
|
|
1809
|
+
* Information about a customer's inventory reservation.
|
|
1810
|
+
* Included in cart/checkout responses when reservations are active.
|
|
1811
|
+
*
|
|
1812
|
+
* @example
|
|
1813
|
+
* ```typescript
|
|
1814
|
+
* const cart = await omni.getCart(cartId);
|
|
1815
|
+
* if (cart.reservation?.hasReservation) {
|
|
1816
|
+
* const remaining = cart.reservation.remainingSeconds;
|
|
1817
|
+
* console.log(`Items reserved for ${remaining} seconds`);
|
|
1818
|
+
* }
|
|
1819
|
+
* ```
|
|
1820
|
+
*/
|
|
1821
|
+
interface ReservationInfo {
|
|
1822
|
+
/** Whether there is an active reservation */
|
|
1823
|
+
hasReservation: boolean;
|
|
1824
|
+
/** ISO timestamp when reservation expires */
|
|
1825
|
+
expiresAt?: string;
|
|
1826
|
+
/** Remaining time in seconds before reservation expires */
|
|
1827
|
+
remainingSeconds?: number;
|
|
1828
|
+
/** The reservation strategy in use */
|
|
1829
|
+
strategy: InventoryReservationStrategy;
|
|
1830
|
+
/** Custom message from store owner (supports {time} placeholder) */
|
|
1831
|
+
countdownMessage?: string;
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Product availability including reserved quantities.
|
|
1835
|
+
* Use this to show accurate stock to customers when reservations are enabled.
|
|
1836
|
+
*
|
|
1837
|
+
* @example
|
|
1838
|
+
* ```typescript
|
|
1839
|
+
* const availability = await omni.getAvailability(['prod_123', 'prod_456']);
|
|
1840
|
+
* availability.forEach(item => {
|
|
1841
|
+
* if (!item.canPurchase) {
|
|
1842
|
+
* console.log(`${item.productId}: Cannot purchase`);
|
|
1843
|
+
* } else if (item.lowStock) {
|
|
1844
|
+
* console.log(`${item.productId}: Only ${item.available} left!`);
|
|
1845
|
+
* }
|
|
1846
|
+
* });
|
|
1847
|
+
* ```
|
|
1848
|
+
*/
|
|
1849
|
+
interface ProductAvailability {
|
|
1850
|
+
/** Product ID */
|
|
1851
|
+
productId: string;
|
|
1852
|
+
/** Variant ID (null for simple products) */
|
|
1853
|
+
variantId?: string | null;
|
|
1854
|
+
/** Inventory tracking mode */
|
|
1855
|
+
trackingMode: InventoryTrackingMode;
|
|
1856
|
+
/** Total stock quantity */
|
|
1857
|
+
total: number;
|
|
1858
|
+
/** Quantity currently reserved by other customers */
|
|
1859
|
+
reserved: number;
|
|
1860
|
+
/** Available for purchase (total - reserved) */
|
|
1861
|
+
available: number;
|
|
1862
|
+
/** Whether the product can be purchased */
|
|
1863
|
+
canPurchase: boolean;
|
|
1864
|
+
/** Whether stock is below low stock threshold */
|
|
1865
|
+
lowStock?: boolean;
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* Response from extending a reservation
|
|
1869
|
+
*/
|
|
1870
|
+
interface ExtendReservationResponse {
|
|
1871
|
+
/** Whether the extension was successful */
|
|
1872
|
+
success: boolean;
|
|
1873
|
+
/** Updated reservation info */
|
|
1874
|
+
reservation: ReservationInfo;
|
|
1875
|
+
}
|
|
1759
1876
|
interface OmniSyncApiError {
|
|
1760
1877
|
statusCode: number;
|
|
1761
1878
|
message: string;
|
|
@@ -2870,12 +2987,16 @@ declare class OmniSyncClient {
|
|
|
2870
2987
|
*/
|
|
2871
2988
|
setCheckoutCustomer(checkoutId: string, data: SetCheckoutCustomerDto): Promise<Checkout>;
|
|
2872
2989
|
/**
|
|
2873
|
-
* Set shipping address on checkout
|
|
2874
|
-
* Returns the checkout and available shipping rates for the address
|
|
2990
|
+
* Set shipping address on checkout (includes customer email).
|
|
2991
|
+
* Returns the checkout and available shipping rates for the address.
|
|
2992
|
+
*
|
|
2993
|
+
* **This is the first step of the simplified checkout flow.**
|
|
2994
|
+
* Email is required and will be used for order confirmation.
|
|
2875
2995
|
*
|
|
2876
2996
|
* @example
|
|
2877
2997
|
* ```typescript
|
|
2878
2998
|
* const { checkout, rates } = await omni.setShippingAddress('checkout_123', {
|
|
2999
|
+
* email: 'customer@example.com', // Required!
|
|
2879
3000
|
* firstName: 'John',
|
|
2880
3001
|
* lastName: 'Doe',
|
|
2881
3002
|
* line1: '123 Main St',
|
|
@@ -2992,9 +3113,11 @@ declare class OmniSyncClient {
|
|
|
2992
3113
|
* const stripeProvider = providers.find(p => p.provider === 'stripe');
|
|
2993
3114
|
* const paypalProvider = providers.find(p => p.provider === 'paypal');
|
|
2994
3115
|
*
|
|
2995
|
-
* // Initialize Stripe if available
|
|
3116
|
+
* // Initialize Stripe if available (with Connect account support)
|
|
2996
3117
|
* if (stripeProvider) {
|
|
2997
|
-
* const stripe = await loadStripe(stripeProvider.publicKey
|
|
3118
|
+
* const stripe = await loadStripe(stripeProvider.publicKey, {
|
|
3119
|
+
* stripeAccount: stripeProvider.stripeAccountId, // For Stripe Connect
|
|
3120
|
+
* });
|
|
2998
3121
|
* // Show Stripe payment form
|
|
2999
3122
|
* }
|
|
3000
3123
|
*
|
|
@@ -3398,6 +3521,72 @@ declare class OmniSyncClient {
|
|
|
3398
3521
|
* ```
|
|
3399
3522
|
*/
|
|
3400
3523
|
testCustomApiConnection(integrationId: string): Promise<CustomApiTestResult>;
|
|
3524
|
+
/**
|
|
3525
|
+
* Get product availability including reserved quantities.
|
|
3526
|
+
* Use this to show accurate stock to customers when reservations are enabled.
|
|
3527
|
+
*
|
|
3528
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
3529
|
+
*
|
|
3530
|
+
* @param productIds - Array of product IDs to check availability for
|
|
3531
|
+
* @returns Array of availability info for each product
|
|
3532
|
+
*
|
|
3533
|
+
* @example
|
|
3534
|
+
* ```typescript
|
|
3535
|
+
* const availability = await omni.getAvailability(['prod_123', 'prod_456']);
|
|
3536
|
+
* availability.forEach(item => {
|
|
3537
|
+
* if (!item.canPurchase) {
|
|
3538
|
+
* console.log(`${item.productId}: Cannot purchase`);
|
|
3539
|
+
* } else if (item.lowStock) {
|
|
3540
|
+
* console.log(`${item.productId}: Only ${item.available} left!`);
|
|
3541
|
+
* } else {
|
|
3542
|
+
* console.log(`${item.productId}: ${item.available} available`);
|
|
3543
|
+
* }
|
|
3544
|
+
* });
|
|
3545
|
+
* ```
|
|
3546
|
+
*/
|
|
3547
|
+
getAvailability(productIds: string[]): Promise<ProductAvailability[]>;
|
|
3548
|
+
/**
|
|
3549
|
+
* Extend an active reservation to prevent it from expiring.
|
|
3550
|
+
* Call this when a customer is still active in checkout to keep their items reserved.
|
|
3551
|
+
*
|
|
3552
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
3553
|
+
* Only works when reservation strategy is ON_CART or ON_CHECKOUT
|
|
3554
|
+
*
|
|
3555
|
+
* @param options - Either cartId or checkoutId to identify the reservation
|
|
3556
|
+
* @returns Updated reservation info
|
|
3557
|
+
*
|
|
3558
|
+
* @example
|
|
3559
|
+
* ```typescript
|
|
3560
|
+
* // Extend reservation when customer shows activity
|
|
3561
|
+
* const result = await omni.extendReservation({ checkoutId: 'chk_123' });
|
|
3562
|
+
* if (result.success) {
|
|
3563
|
+
* console.log(`Reservation extended until ${result.reservation.expiresAt}`);
|
|
3564
|
+
* }
|
|
3565
|
+
* ```
|
|
3566
|
+
*/
|
|
3567
|
+
extendReservation(options: {
|
|
3568
|
+
cartId?: string;
|
|
3569
|
+
checkoutId?: string;
|
|
3570
|
+
}): Promise<ExtendReservationResponse>;
|
|
3571
|
+
/**
|
|
3572
|
+
* Release an active reservation, returning items to available stock.
|
|
3573
|
+
* Call this when a customer abandons their cart/checkout.
|
|
3574
|
+
*
|
|
3575
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
3576
|
+
* Only works when reservation strategy is ON_CART or ON_CHECKOUT
|
|
3577
|
+
*
|
|
3578
|
+
* @param options - Either cartId or checkoutId to identify the reservation
|
|
3579
|
+
*
|
|
3580
|
+
* @example
|
|
3581
|
+
* ```typescript
|
|
3582
|
+
* // Release reservation when customer abandons checkout
|
|
3583
|
+
* await omni.releaseReservation({ checkoutId: 'chk_123' });
|
|
3584
|
+
* ```
|
|
3585
|
+
*/
|
|
3586
|
+
releaseReservation(options: {
|
|
3587
|
+
cartId?: string;
|
|
3588
|
+
checkoutId?: string;
|
|
3589
|
+
}): Promise<void>;
|
|
3401
3590
|
}
|
|
3402
3591
|
/**
|
|
3403
3592
|
* Custom error class for Omni-Sync API errors
|
package/dist/index.js
CHANGED
|
@@ -1897,12 +1897,16 @@ var OmniSyncClient = class {
|
|
|
1897
1897
|
return this.adminRequest("PATCH", `/api/v1/checkout/${checkoutId}/customer`, data);
|
|
1898
1898
|
}
|
|
1899
1899
|
/**
|
|
1900
|
-
* Set shipping address on checkout
|
|
1901
|
-
* Returns the checkout and available shipping rates for the address
|
|
1900
|
+
* Set shipping address on checkout (includes customer email).
|
|
1901
|
+
* Returns the checkout and available shipping rates for the address.
|
|
1902
|
+
*
|
|
1903
|
+
* **This is the first step of the simplified checkout flow.**
|
|
1904
|
+
* Email is required and will be used for order confirmation.
|
|
1902
1905
|
*
|
|
1903
1906
|
* @example
|
|
1904
1907
|
* ```typescript
|
|
1905
1908
|
* const { checkout, rates } = await omni.setShippingAddress('checkout_123', {
|
|
1909
|
+
* email: 'customer@example.com', // Required!
|
|
1906
1910
|
* firstName: 'John',
|
|
1907
1911
|
* lastName: 'Doe',
|
|
1908
1912
|
* line1: '123 Main St',
|
|
@@ -2117,9 +2121,11 @@ var OmniSyncClient = class {
|
|
|
2117
2121
|
* const stripeProvider = providers.find(p => p.provider === 'stripe');
|
|
2118
2122
|
* const paypalProvider = providers.find(p => p.provider === 'paypal');
|
|
2119
2123
|
*
|
|
2120
|
-
* // Initialize Stripe if available
|
|
2124
|
+
* // Initialize Stripe if available (with Connect account support)
|
|
2121
2125
|
* if (stripeProvider) {
|
|
2122
|
-
* const stripe = await loadStripe(stripeProvider.publicKey
|
|
2126
|
+
* const stripe = await loadStripe(stripeProvider.publicKey, {
|
|
2127
|
+
* stripeAccount: stripeProvider.stripeAccountId, // For Stripe Connect
|
|
2128
|
+
* });
|
|
2123
2129
|
* // Show Stripe payment form
|
|
2124
2130
|
* }
|
|
2125
2131
|
*
|
|
@@ -2447,7 +2453,11 @@ var OmniSyncClient = class {
|
|
|
2447
2453
|
const trackingResult = await this.startGuestCheckout();
|
|
2448
2454
|
if (trackingResult.tracked) {
|
|
2449
2455
|
await this.updateGuestCheckoutAddress(trackingResult.checkoutId, {
|
|
2450
|
-
shippingAddress:
|
|
2456
|
+
shippingAddress: {
|
|
2457
|
+
...cart.shippingAddress,
|
|
2458
|
+
email: cart.customer.email
|
|
2459
|
+
// Already validated above
|
|
2460
|
+
},
|
|
2451
2461
|
billingAddress: cart.billingAddress
|
|
2452
2462
|
});
|
|
2453
2463
|
const orderResult = await this.completeGuestCheckout(trackingResult.checkoutId, {
|
|
@@ -2866,6 +2876,99 @@ var OmniSyncClient = class {
|
|
|
2866
2876
|
`/api/v1/custom-api/${integrationId}/test`
|
|
2867
2877
|
);
|
|
2868
2878
|
}
|
|
2879
|
+
// -------------------- Inventory Reservations --------------------
|
|
2880
|
+
// These methods are only available in vibe-coded mode when reservation strategy
|
|
2881
|
+
// is set to ON_CART or ON_CHECKOUT
|
|
2882
|
+
/**
|
|
2883
|
+
* Get product availability including reserved quantities.
|
|
2884
|
+
* Use this to show accurate stock to customers when reservations are enabled.
|
|
2885
|
+
*
|
|
2886
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
2887
|
+
*
|
|
2888
|
+
* @param productIds - Array of product IDs to check availability for
|
|
2889
|
+
* @returns Array of availability info for each product
|
|
2890
|
+
*
|
|
2891
|
+
* @example
|
|
2892
|
+
* ```typescript
|
|
2893
|
+
* const availability = await omni.getAvailability(['prod_123', 'prod_456']);
|
|
2894
|
+
* availability.forEach(item => {
|
|
2895
|
+
* if (!item.canPurchase) {
|
|
2896
|
+
* console.log(`${item.productId}: Cannot purchase`);
|
|
2897
|
+
* } else if (item.lowStock) {
|
|
2898
|
+
* console.log(`${item.productId}: Only ${item.available} left!`);
|
|
2899
|
+
* } else {
|
|
2900
|
+
* console.log(`${item.productId}: ${item.available} available`);
|
|
2901
|
+
* }
|
|
2902
|
+
* });
|
|
2903
|
+
* ```
|
|
2904
|
+
*/
|
|
2905
|
+
async getAvailability(productIds) {
|
|
2906
|
+
if (!this.isVibeCodedMode()) {
|
|
2907
|
+
throw new OmniSyncError(
|
|
2908
|
+
"getAvailability is only available in vibe-coded mode (use connectionId)",
|
|
2909
|
+
400
|
|
2910
|
+
);
|
|
2911
|
+
}
|
|
2912
|
+
return this.vibeCodedRequest("POST", "/availability", { productIds });
|
|
2913
|
+
}
|
|
2914
|
+
/**
|
|
2915
|
+
* Extend an active reservation to prevent it from expiring.
|
|
2916
|
+
* Call this when a customer is still active in checkout to keep their items reserved.
|
|
2917
|
+
*
|
|
2918
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
2919
|
+
* Only works when reservation strategy is ON_CART or ON_CHECKOUT
|
|
2920
|
+
*
|
|
2921
|
+
* @param options - Either cartId or checkoutId to identify the reservation
|
|
2922
|
+
* @returns Updated reservation info
|
|
2923
|
+
*
|
|
2924
|
+
* @example
|
|
2925
|
+
* ```typescript
|
|
2926
|
+
* // Extend reservation when customer shows activity
|
|
2927
|
+
* const result = await omni.extendReservation({ checkoutId: 'chk_123' });
|
|
2928
|
+
* if (result.success) {
|
|
2929
|
+
* console.log(`Reservation extended until ${result.reservation.expiresAt}`);
|
|
2930
|
+
* }
|
|
2931
|
+
* ```
|
|
2932
|
+
*/
|
|
2933
|
+
async extendReservation(options) {
|
|
2934
|
+
if (!this.isVibeCodedMode()) {
|
|
2935
|
+
throw new OmniSyncError(
|
|
2936
|
+
"extendReservation is only available in vibe-coded mode (use connectionId)",
|
|
2937
|
+
400
|
|
2938
|
+
);
|
|
2939
|
+
}
|
|
2940
|
+
if (!options.cartId && !options.checkoutId) {
|
|
2941
|
+
throw new OmniSyncError("Either cartId or checkoutId is required", 400);
|
|
2942
|
+
}
|
|
2943
|
+
return this.vibeCodedRequest("POST", "/reservation/extend", options);
|
|
2944
|
+
}
|
|
2945
|
+
/**
|
|
2946
|
+
* Release an active reservation, returning items to available stock.
|
|
2947
|
+
* Call this when a customer abandons their cart/checkout.
|
|
2948
|
+
*
|
|
2949
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
2950
|
+
* Only works when reservation strategy is ON_CART or ON_CHECKOUT
|
|
2951
|
+
*
|
|
2952
|
+
* @param options - Either cartId or checkoutId to identify the reservation
|
|
2953
|
+
*
|
|
2954
|
+
* @example
|
|
2955
|
+
* ```typescript
|
|
2956
|
+
* // Release reservation when customer abandons checkout
|
|
2957
|
+
* await omni.releaseReservation({ checkoutId: 'chk_123' });
|
|
2958
|
+
* ```
|
|
2959
|
+
*/
|
|
2960
|
+
async releaseReservation(options) {
|
|
2961
|
+
if (!this.isVibeCodedMode()) {
|
|
2962
|
+
throw new OmniSyncError(
|
|
2963
|
+
"releaseReservation is only available in vibe-coded mode (use connectionId)",
|
|
2964
|
+
400
|
|
2965
|
+
);
|
|
2966
|
+
}
|
|
2967
|
+
if (!options.cartId && !options.checkoutId) {
|
|
2968
|
+
throw new OmniSyncError("Either cartId or checkoutId is required", 400);
|
|
2969
|
+
}
|
|
2970
|
+
await this.vibeCodedRequest("POST", "/reservation/release", options);
|
|
2971
|
+
}
|
|
2869
2972
|
};
|
|
2870
2973
|
var OmniSyncError = class extends Error {
|
|
2871
2974
|
constructor(message, statusCode, details) {
|
package/dist/index.mjs
CHANGED
|
@@ -1868,12 +1868,16 @@ var OmniSyncClient = class {
|
|
|
1868
1868
|
return this.adminRequest("PATCH", `/api/v1/checkout/${checkoutId}/customer`, data);
|
|
1869
1869
|
}
|
|
1870
1870
|
/**
|
|
1871
|
-
* Set shipping address on checkout
|
|
1872
|
-
* Returns the checkout and available shipping rates for the address
|
|
1871
|
+
* Set shipping address on checkout (includes customer email).
|
|
1872
|
+
* Returns the checkout and available shipping rates for the address.
|
|
1873
|
+
*
|
|
1874
|
+
* **This is the first step of the simplified checkout flow.**
|
|
1875
|
+
* Email is required and will be used for order confirmation.
|
|
1873
1876
|
*
|
|
1874
1877
|
* @example
|
|
1875
1878
|
* ```typescript
|
|
1876
1879
|
* const { checkout, rates } = await omni.setShippingAddress('checkout_123', {
|
|
1880
|
+
* email: 'customer@example.com', // Required!
|
|
1877
1881
|
* firstName: 'John',
|
|
1878
1882
|
* lastName: 'Doe',
|
|
1879
1883
|
* line1: '123 Main St',
|
|
@@ -2088,9 +2092,11 @@ var OmniSyncClient = class {
|
|
|
2088
2092
|
* const stripeProvider = providers.find(p => p.provider === 'stripe');
|
|
2089
2093
|
* const paypalProvider = providers.find(p => p.provider === 'paypal');
|
|
2090
2094
|
*
|
|
2091
|
-
* // Initialize Stripe if available
|
|
2095
|
+
* // Initialize Stripe if available (with Connect account support)
|
|
2092
2096
|
* if (stripeProvider) {
|
|
2093
|
-
* const stripe = await loadStripe(stripeProvider.publicKey
|
|
2097
|
+
* const stripe = await loadStripe(stripeProvider.publicKey, {
|
|
2098
|
+
* stripeAccount: stripeProvider.stripeAccountId, // For Stripe Connect
|
|
2099
|
+
* });
|
|
2094
2100
|
* // Show Stripe payment form
|
|
2095
2101
|
* }
|
|
2096
2102
|
*
|
|
@@ -2418,7 +2424,11 @@ var OmniSyncClient = class {
|
|
|
2418
2424
|
const trackingResult = await this.startGuestCheckout();
|
|
2419
2425
|
if (trackingResult.tracked) {
|
|
2420
2426
|
await this.updateGuestCheckoutAddress(trackingResult.checkoutId, {
|
|
2421
|
-
shippingAddress:
|
|
2427
|
+
shippingAddress: {
|
|
2428
|
+
...cart.shippingAddress,
|
|
2429
|
+
email: cart.customer.email
|
|
2430
|
+
// Already validated above
|
|
2431
|
+
},
|
|
2422
2432
|
billingAddress: cart.billingAddress
|
|
2423
2433
|
});
|
|
2424
2434
|
const orderResult = await this.completeGuestCheckout(trackingResult.checkoutId, {
|
|
@@ -2837,6 +2847,99 @@ var OmniSyncClient = class {
|
|
|
2837
2847
|
`/api/v1/custom-api/${integrationId}/test`
|
|
2838
2848
|
);
|
|
2839
2849
|
}
|
|
2850
|
+
// -------------------- Inventory Reservations --------------------
|
|
2851
|
+
// These methods are only available in vibe-coded mode when reservation strategy
|
|
2852
|
+
// is set to ON_CART or ON_CHECKOUT
|
|
2853
|
+
/**
|
|
2854
|
+
* Get product availability including reserved quantities.
|
|
2855
|
+
* Use this to show accurate stock to customers when reservations are enabled.
|
|
2856
|
+
*
|
|
2857
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
2858
|
+
*
|
|
2859
|
+
* @param productIds - Array of product IDs to check availability for
|
|
2860
|
+
* @returns Array of availability info for each product
|
|
2861
|
+
*
|
|
2862
|
+
* @example
|
|
2863
|
+
* ```typescript
|
|
2864
|
+
* const availability = await omni.getAvailability(['prod_123', 'prod_456']);
|
|
2865
|
+
* availability.forEach(item => {
|
|
2866
|
+
* if (!item.canPurchase) {
|
|
2867
|
+
* console.log(`${item.productId}: Cannot purchase`);
|
|
2868
|
+
* } else if (item.lowStock) {
|
|
2869
|
+
* console.log(`${item.productId}: Only ${item.available} left!`);
|
|
2870
|
+
* } else {
|
|
2871
|
+
* console.log(`${item.productId}: ${item.available} available`);
|
|
2872
|
+
* }
|
|
2873
|
+
* });
|
|
2874
|
+
* ```
|
|
2875
|
+
*/
|
|
2876
|
+
async getAvailability(productIds) {
|
|
2877
|
+
if (!this.isVibeCodedMode()) {
|
|
2878
|
+
throw new OmniSyncError(
|
|
2879
|
+
"getAvailability is only available in vibe-coded mode (use connectionId)",
|
|
2880
|
+
400
|
|
2881
|
+
);
|
|
2882
|
+
}
|
|
2883
|
+
return this.vibeCodedRequest("POST", "/availability", { productIds });
|
|
2884
|
+
}
|
|
2885
|
+
/**
|
|
2886
|
+
* Extend an active reservation to prevent it from expiring.
|
|
2887
|
+
* Call this when a customer is still active in checkout to keep their items reserved.
|
|
2888
|
+
*
|
|
2889
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
2890
|
+
* Only works when reservation strategy is ON_CART or ON_CHECKOUT
|
|
2891
|
+
*
|
|
2892
|
+
* @param options - Either cartId or checkoutId to identify the reservation
|
|
2893
|
+
* @returns Updated reservation info
|
|
2894
|
+
*
|
|
2895
|
+
* @example
|
|
2896
|
+
* ```typescript
|
|
2897
|
+
* // Extend reservation when customer shows activity
|
|
2898
|
+
* const result = await omni.extendReservation({ checkoutId: 'chk_123' });
|
|
2899
|
+
* if (result.success) {
|
|
2900
|
+
* console.log(`Reservation extended until ${result.reservation.expiresAt}`);
|
|
2901
|
+
* }
|
|
2902
|
+
* ```
|
|
2903
|
+
*/
|
|
2904
|
+
async extendReservation(options) {
|
|
2905
|
+
if (!this.isVibeCodedMode()) {
|
|
2906
|
+
throw new OmniSyncError(
|
|
2907
|
+
"extendReservation is only available in vibe-coded mode (use connectionId)",
|
|
2908
|
+
400
|
|
2909
|
+
);
|
|
2910
|
+
}
|
|
2911
|
+
if (!options.cartId && !options.checkoutId) {
|
|
2912
|
+
throw new OmniSyncError("Either cartId or checkoutId is required", 400);
|
|
2913
|
+
}
|
|
2914
|
+
return this.vibeCodedRequest("POST", "/reservation/extend", options);
|
|
2915
|
+
}
|
|
2916
|
+
/**
|
|
2917
|
+
* Release an active reservation, returning items to available stock.
|
|
2918
|
+
* Call this when a customer abandons their cart/checkout.
|
|
2919
|
+
*
|
|
2920
|
+
* **Vibe-coded mode only** - requires connectionId
|
|
2921
|
+
* Only works when reservation strategy is ON_CART or ON_CHECKOUT
|
|
2922
|
+
*
|
|
2923
|
+
* @param options - Either cartId or checkoutId to identify the reservation
|
|
2924
|
+
*
|
|
2925
|
+
* @example
|
|
2926
|
+
* ```typescript
|
|
2927
|
+
* // Release reservation when customer abandons checkout
|
|
2928
|
+
* await omni.releaseReservation({ checkoutId: 'chk_123' });
|
|
2929
|
+
* ```
|
|
2930
|
+
*/
|
|
2931
|
+
async releaseReservation(options) {
|
|
2932
|
+
if (!this.isVibeCodedMode()) {
|
|
2933
|
+
throw new OmniSyncError(
|
|
2934
|
+
"releaseReservation is only available in vibe-coded mode (use connectionId)",
|
|
2935
|
+
400
|
|
2936
|
+
);
|
|
2937
|
+
}
|
|
2938
|
+
if (!options.cartId && !options.checkoutId) {
|
|
2939
|
+
throw new OmniSyncError("Either cartId or checkoutId is required", 400);
|
|
2940
|
+
}
|
|
2941
|
+
await this.vibeCodedRequest("POST", "/reservation/release", options);
|
|
2942
|
+
}
|
|
2840
2943
|
};
|
|
2841
2944
|
var OmniSyncError = class extends Error {
|
|
2842
2945
|
constructor(message, statusCode, details) {
|
package/package.json
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "omni-sync-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Official SDK for building e-commerce storefronts with OmniSync Platform. Perfect for vibe-coded sites, AI-built stores (Cursor, Lovable, v0), and custom storefronts.",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"module": "dist/index.mjs",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"require": "./dist/index.js",
|
|
12
|
-
"import": "./dist/index.mjs"
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"files": [
|
|
16
|
-
"dist",
|
|
17
|
-
"README.md"
|
|
18
|
-
],
|
|
19
|
-
"scripts": {
|
|
20
|
-
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
21
|
-
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
22
|
-
"lint": "eslint \"src/**/*.ts\"",
|
|
23
|
-
"test": "vitest run",
|
|
24
|
-
"test:watch": "vitest",
|
|
25
|
-
"prepublishOnly": "pnpm build"
|
|
26
|
-
},
|
|
27
|
-
"keywords": [
|
|
28
|
-
"omni-sync",
|
|
29
|
-
"e-commerce",
|
|
30
|
-
"ecommerce",
|
|
31
|
-
"sdk",
|
|
32
|
-
"vibe-coding",
|
|
33
|
-
"vibe-coded",
|
|
34
|
-
"ai-commerce",
|
|
35
|
-
"storefront",
|
|
36
|
-
"headless-commerce",
|
|
37
|
-
"multi-platform",
|
|
38
|
-
"shopify",
|
|
39
|
-
"tiktok",
|
|
40
|
-
"cursor",
|
|
41
|
-
"lovable",
|
|
42
|
-
"v0",
|
|
43
|
-
"cart",
|
|
44
|
-
"checkout",
|
|
45
|
-
"products",
|
|
46
|
-
"sync"
|
|
47
|
-
],
|
|
48
|
-
"author": "Omni-Sync Platform",
|
|
49
|
-
"license": "MIT",
|
|
50
|
-
"repository": {
|
|
51
|
-
"type": "git",
|
|
52
|
-
"url": "https://github.com/omni-sync/omni-sync-platform.git",
|
|
53
|
-
"directory": "packages/sdk"
|
|
54
|
-
},
|
|
55
|
-
"homepage": "https://omni-sync.com",
|
|
56
|
-
"bugs": {
|
|
57
|
-
"url": "https://github.com/omni-sync/omni-sync-platform/issues"
|
|
58
|
-
},
|
|
59
|
-
"devDependencies": {
|
|
60
|
-
"@types/node": "^25.0.3",
|
|
61
|
-
"@typescript-eslint/eslint-plugin": "^8.50.1",
|
|
62
|
-
"@typescript-eslint/parser": "^8.50.1",
|
|
63
|
-
"eslint": "^9.39.2",
|
|
64
|
-
"tsup": "^8.0.0",
|
|
65
|
-
"typescript": "^5.3.0",
|
|
66
|
-
"vitest": "^1.0.0"
|
|
67
|
-
},
|
|
68
|
-
"peerDependencies": {
|
|
69
|
-
"typescript": ">=4.7.0"
|
|
70
|
-
},
|
|
71
|
-
"peerDependenciesMeta": {
|
|
72
|
-
"typescript": {
|
|
73
|
-
"optional": true
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "omni-sync-sdk",
|
|
3
|
+
"version": "0.15.0",
|
|
4
|
+
"description": "Official SDK for building e-commerce storefronts with OmniSync Platform. Perfect for vibe-coded sites, AI-built stores (Cursor, Lovable, v0), and custom storefronts.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"import": "./dist/index.mjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
21
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
22
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"prepublishOnly": "pnpm build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"omni-sync",
|
|
29
|
+
"e-commerce",
|
|
30
|
+
"ecommerce",
|
|
31
|
+
"sdk",
|
|
32
|
+
"vibe-coding",
|
|
33
|
+
"vibe-coded",
|
|
34
|
+
"ai-commerce",
|
|
35
|
+
"storefront",
|
|
36
|
+
"headless-commerce",
|
|
37
|
+
"multi-platform",
|
|
38
|
+
"shopify",
|
|
39
|
+
"tiktok",
|
|
40
|
+
"cursor",
|
|
41
|
+
"lovable",
|
|
42
|
+
"v0",
|
|
43
|
+
"cart",
|
|
44
|
+
"checkout",
|
|
45
|
+
"products",
|
|
46
|
+
"sync"
|
|
47
|
+
],
|
|
48
|
+
"author": "Omni-Sync Platform",
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "https://github.com/omni-sync/omni-sync-platform.git",
|
|
53
|
+
"directory": "packages/sdk"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://omni-sync.com",
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/omni-sync/omni-sync-platform/issues"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/node": "^25.0.3",
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "^8.50.1",
|
|
62
|
+
"@typescript-eslint/parser": "^8.50.1",
|
|
63
|
+
"eslint": "^9.39.2",
|
|
64
|
+
"tsup": "^8.0.0",
|
|
65
|
+
"typescript": "^5.3.0",
|
|
66
|
+
"vitest": "^1.0.0"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"typescript": ">=4.7.0"
|
|
70
|
+
},
|
|
71
|
+
"peerDependenciesMeta": {
|
|
72
|
+
"typescript": {
|
|
73
|
+
"optional": true
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|