npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@liquidcommerce/cloud-sdk

v1.6.0

Published

LiquidCommerce Cloud SDK

Downloads

238

Readme

LiquidCommerce Cloud SDK

The LiquidCommerce Cloud SDK provides an easy way to interact with our APIs through a server-side SDK for Node.js and Web JS script.

Table of Contents

Installation

Install the package with:

npm install @liquidcommerce/cloud-sdk
# or
yarn add @liquidcommerce/cloud-sdk
# or
pnpm add @liquidcommerce/cloud-sdk

Configuration

The SDK requires configuration during initialization:

import { LiquidCommerce, LIQUID_COMMERCE_ENV } from '@liquidcommerce/cloud-sdk';

const client = await LiquidCommerce('YOUR_LIQUIDCOMMERCE_API_KEY', {
  googlePlacesApiKey: 'YOUR_GOOGLE_PLACES_API_KEY', // Required for address services
  env: LIQUID_COMMERCE_ENV.STAGE // STAGE or PROD
});

await client.init();

Response Types

All API responses follow a consistent structure:

interface ApiResponse<T> {
  statusCode: number;
  message: string;
  metadata: {
    languages: string[];
    timestamp: number;
    timezone: string;
    requestId: string;
    path: string;
    version: string;
  };
  data?: T; // Present in responses with data
}

Services

Address

Services for address validation and lookup:

// Address autocompletion
const autocompleteResponse = await client.address.autocomplete({
  input: '100 Madison Ave, New York'
});

// Response type: IApiResponseWithData<IAddressAutocompleteResult[]>
// {
//   id: string;
//   description: string;
// }

// Get detailed address information
const detailsResponse = await client.address.details({
  id: 'ChIJd8BlQ2BZwokRjMKtTjMezRw'
});

// Response type: IApiResponseWithData<IAddressDetailsResult>
// {
//   formattedAddress: string;
//   coords: {
//     lat: number;
//     long: number;
//   }
// }

Catalog

Product catalog search and availability services:

// Check product availability
const availabilityResponse = await client.catalog.availability({
  upcs: ['123456789012', '210987654321'], // UPC codes
  grouping: ['group1', 'group2'], // Optional group identifiers
  ids: ['id1', 'id2'], // Optional product IDs
  loc: {
    address: {
      one: '123 Main St',
      city: 'New York',
      state: 'NY',
      zip: '10001'
    }
  },
  shouldShowOffHours: true
});

// Search catalog with filters
const searchResponse = await client.catalog.search({
  search: 'whiskey',
  page: 1,
  perPage: 20,
  orderBy: ENUM_ORDER_BY.PRICE,
  orderDirection: ENUM_NAVIGATION_ORDER_DIRECTION_TYPE.ASC,
  filters: [
    { 
      key: ENUM_FILTER_KEYS.CATEGORIES, 
      values: [ENUM_SPIRITS.WHISKEY] 
    },
    { 
      key: ENUM_FILTER_KEYS.PRICE, 
      values: { min: 2000, max: 10000 } // Prices in cents
    },
    {
      key: ENUM_FILTER_KEYS.AVAILABILITY,
      values: ENUM_AVAILABILITY_VALUE.IN_STOCK
    }
  ],
  loc: {
    address: {
      one: '123 Main St',
      city: 'New York',
      state: 'NY',
      zip: '10001'
    }
  }
});

Cart

Shopping cart management:

// Create new cart
const newCart = await client.cart.get();

// Retrieve existing cart
const existingCart = await client.cart.get('cart_id', true); // Second parameter for refresh

// Update cart
const updatedCart = await client.cart.update({
  id: 'cart_id',
  items: [
    {
      partNumber: '123456789012_retailer_id', // Required: {UPC}_{retailerId}
      quantity: 2,
      fulfillmentId: 'fulfillment_id',
      engravingLines: ['Line 1', 'Line 2'], // Optional
      scheduledFor: '2024-12-25', // Optional
    }
  ],
  loc: {
    address: {
      one: '123 Main St',
      city: 'New York',
      state: 'NY',
      zip: '10001'
    }
  },
  promoCode: 'DISCOUNT10', // Optional
  giftCards: ['GC123456'] // Optional
});

User

User profile and preferences management:

// Create/update user session
const userSession = await client.user.session({
  email: "[email protected]",
  firstName: "John",
  lastName: "Smith",
  phone: "2125551234",
  company: "Company Inc",
  profileImage: "https://...",
  birthDate: "1990-01-01"
});

// Fetch user by ID or email
const userData = await client.user.fetch('user_id_or_email');

// Address management
const newAddress = await client.user.addAddress({
  customerId: 'customer_id',
  placesId: 'google_places_id', // Optional if providing address details
  one: '100 Madison St',
  two: 'Apt 4B',
  city: 'New York',
  state: 'NY',
  zip: '10004',
  country: 'US',
  lat: 40.7128, // Optional
  long: -74.0060, // Optional
  type: ENUM_ADDRESS_TYPE.SHIPPING,
  isDefault: true
});

const updatedAddress = await client.user.updateAddress({
  // Same parameters as addAddress
});

// Payment methods
const newPayment = await client.user.addPayment({
  customerId: 'customer_id',
  paymentMethodId: 'payment_method_id',
  isDefault: true
});

const updatedPayment = await client.user.updatePayment({
  customerId: 'customer_id',
  paymentMethodId: 'payment_method_id',
  isDefault: true // Required for updates
});

// Data removal
await client.user.purge('user_id_or_email');
await client.user.purgeAddress('address_id');
await client.user.purgePayment('customer_id', 'payment_id');

Payment

The payment system uses secure elements for handling sensitive payment data. Before using payment features, you must first create a user session.

Prerequisites

  1. User Session Creation:
// First create or get a user session
const userSession = await client.user.session({
  email: "[email protected]",
  // ... other user details
});

// The session response includes necessary payment credentials
const { setupIntent, publicKey } = userSession.data.session;

Payment Element Integration

// Initialize payment form using session credentials
await client.payment.mount({
  clientSecret: userSession.data.session.setupIntent,  // Required: from session
  key: userSession.data.session.publicKey,            // Required: from session
  elementId: 'payment-element-container',             // Your DOM element ID
  appearance: { 
    theme: 'night'  // 'default' | 'night' | 'flat'
  },
  elementOptions: { 
    layout: 'tabs'  // 'tabs' | 'accordion' | 'auto'
  }
});

// Monitor payment element state
client.payment.subscribe('ready', () => {
  // Element is ready to accept input
});

client.payment.subscribe('change', (event) => {
  const { complete, empty, value } = event;
  // Handle validation state changes
});

// Process payment when ready
const tokenResult = await client.payment.generateToken();

// Handle the result
if ('error' in tokenResult) {
  const { type, message, code } = tokenResult.error;
  // type can be: 'validation_error' | 'api_error' | 'client_error' | 'confirm_error'
} else {
  // Use tokenResult.id for checkout completion or saving payment method
  const { id, card } = tokenResult;
}

// Always clean up when done
client.payment.unmount();
client.payment.destroy();

Security Considerations

  1. PCI Compliance: The payment element handles card data securely within an iframe, ensuring your application never directly touches sensitive payment information.

  2. Token-Based: All payment data is tokenized - you only receive secure tokens that can't be used to retrieve the original card details.

  3. Single Use: Payment tokens are single-use and expire after a short time period.

  4. Domain Validation: Payment elements will only work on domains that have been pre-registered with your account.

Best Practices

  1. Error Handling: Always implement proper error handling:
try {
  const token = await client.payment.generateToken();
  if ('error' in token) {
    switch(token.error.type) {
      case 'validation_error':
        // Handle invalid card data
        break;
      case 'api_error':
        // Handle API/network issues
        break;
      case 'client_error':
        // Handle setup/configuration issues
        break;
      case 'confirm_error':
        // Handle payment confirmation failures
        break;
    }
  }
} catch (error) {
  // Handle unexpected errors
}
  1. Cleanup: Always clean up payment elements when done:
  • When navigation away from payment page
  • After successful payment
  • After failed payment attempt
  • Before unmounting payment component
  1. Event Handling: Monitor element state for better user experience:
client.payment.subscribe('change', (event) => {
  // Update UI based on validation state
  const { complete, empty } = event;
  submitButton.disabled = !complete || empty;
});

client.payment.subscribe('loaderror', (event) => {
  // Handle element loading failures
  console.error('Payment element failed:', event.error);
});

Responsive Design

The payment element automatically adapts to:

  • Mobile and desktop viewports
  • Right-to-left languages
  • Dark/light themes
  • Different container sizes

Testing Cards

When testing payments in staging environment, use these test cards:

// Test Visa Card
Card Number: 4242 4242 4242 4242
Expiry: Any future date
CVC: Any 3 digits
ZIP: Any 5 digits

// Test Mastercard
Card Number: 5555 5555 5555 4444
Expiry: Any future date
CVC: Any 3 digits
ZIP: Any 5 digits

// Example test card usage:
/*
  Card: 4242 4242 4242 4242
  Expiry: 12/29
  CVC: 123
  ZIP: 10001
*/

These cards will be accepted in test mode and will simulate successful payments. They should only be used in the staging environment, never in production.

Important Notes:

  • These cards work only in test/staging environment
  • Real cards will be declined in test mode
  • Test cards will be declined in production
  • All test transactions use simulated funds
  • Use test credentials in staging environment
  • Never use production credentials in development
  • Test all error scenarios
  • Verify proper cleanup implementation
  • Test on multiple devices and browsers

Checkout

Checkout process management:

// Prepare checkout
const preparedCheckout = await client.checkout.prepare({
  cartId: "cart_id",
  customer: {
    id: "customer_id", // Optional
    email: "[email protected]",
    firstName: "John",
    lastName: "Smith",
    phone: "2125551234",
    birthDate: "1990-01-01"
  },
  hasAgeVerify: true,
  billingAddress: {
    firstName: "John",
    lastName: "Smith",
    email: "[email protected]",
    phone: "2125551234",
    one: "123 Main St",
    two: "Apt 4B",
    city: "New York",
    state: "NY",
    zip: "10001",
    country: "US"
  },
  hasSubstitutionPolicy: true,
  isGift: true,
  billingSameAsShipping: false,
  giftOptions: {
    message: "Happy Birthday!",
    recipient: {
      name: "Jane Smith",
      email: "[email protected]",
      phone: "2125555678"
    }
  },
  marketingPreferences: {
    canEmail: true,
    canSms: true
  },
  deliveryTips: [
    {
      fulfillmentId: "fulfillment_id",
      tip: 500 // Amount in cents
    }
  ],
  acceptedAccountCreation: true,
  scheduledDelivery: "2024-12-25T14:00:00Z"
});

// Complete checkout
const completedCheckout = await client.checkout.complete({
  token: preparedCheckout.token,
  payment: "payment_token"
});
```_

#### Checkout Payment

For direct checkout payments, the flow is similar but uses the checkout session:

```typescript
// 1. First prepare the checkout
const preparedCheckout = await client.checkout.prepare({
  cartId: "cart_id",
  // ... other checkout details
});

// 2. Initialize payment form with checkout data
await client.payment.mount({
  clientSecret: preparedCheckout.payment.clientSecret, // From checkout prepare response
  key: preparedCheckout.payment.publicKey,            // From checkout prepare response
  elementId: 'payment-element-container',
  appearance: { theme: 'night' },
  elementOptions: { layout: 'tabs' }
});

// 3. Handle payment element events
client.payment.subscribe('change', (event) => {
  // Monitor payment form state
  const { complete, empty, value } = event;
});

// 4. When ready to complete checkout, generate payment token
const tokenResult = await client.payment.generateToken();
if (!('error' in tokenResult)) {
  // 5. Complete checkout with payment token
  const completedCheckout = await client.checkout.complete({
    token: preparedCheckout.token,
    payment: tokenResult.id
  });
}

// 6. Clean up
client.payment.unmount();
client.payment.destroy();

Error Handling

The SDK throws errors for various scenarios. Always wrap SDK calls in try-catch blocks:

try {
  const result = await client.someMethod();
} catch (error) {
  console.error('Operation failed:', error.message);
  // Handle specific error cases
}

Common error scenarios:

  • Authentication failures
  • Invalid parameters
  • Network errors
  • Resource not found
  • Rate limiting
  • Validation errors

Price Handling

All monetary values in the SDK are handled in cents (the smallest currency unit). For example:

  • $10.00 is represented as 1000
  • $5.99 is represented as 599
  • $0.50 is represented as 50

Documentation

For more detailed information about each method and its parameters, please refer to our official documentation.