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 🙏

© 2026 – Pkg Stats / Ryan Hefner

resync-javascript

v1.0.2

Published

Javascript client library for Resync Content Management System

Readme

Resync JavaScript

A powerful JavaScript library for dynamic content management, remote configuration, and in-app campaign. Resync allows you to manage embed dynamic banners, ctas, forms, text, run campaigns into your mobile app. Deliver dynamic content without app updates. Works seamlessly across JavaScript, React Native, and Expo applications.

Features

  • 🚀 Remote Configuration - Manage app configs remotely without code deployments
  • 🧪 In-app Campaigns - Run campaigns with audiences, automatic variant assignment and tracking
  • 🎨 Dynamic Content Management - Fetch and render content blocks defined in your Resync dashboard
  • 📊 Event Logging - Track custom events and user interactions
  • 💾 Smart Caching - Automatic environment-based caching (6h production, 0ms development)
  • 🔄 Real-time Updates - Subscribe to configuration changes with callback support
  • 📱 Cross-Platform - Works with vanilla JavaScript, React Native, and Expo
  • 🔧 TypeScript Support - Full TypeScript definitions included
  • 🎯 User Targeting - Set user attributes for personalized experiences and audience creation.

Installation

npm install resync-javascript
# or
yarn add resync-javascript

Quick Start

1. Initialize Resync

import Resync from 'resync-javascript';

// Initialize Resync with your API credentials
await Resync.init({
  key: 'your-api-key',
  appId: 7,
  callback: async (config) => {
    console.log('Resync initialized with config:', config);
  },
  storage: localStorage, // or AsyncStorage for React Native
  environment: 'production',
});

2. Get Remote Configuration

// Get a specific config value
const featureEnabled = Resync.getConfig('FEATURE_FLAG');
const apiEndpoint = Resync.getConfig('API_ENDPOINT');

console.log('Feature enabled:', featureEnabled);

3. Campaign

// Get variant for an Campaign experiment
const variant = await Resync.getVariant('homepage_experiment');

if (variant === 'variant_a') {
  // Show variant A
} else {
  // Show variant B
}

4. Event Logging

// Log custom events
Resync.logEvent({
  eventId: 'evt_button_clicked',
  metadata: {
    buttonName: 'signup',
    screen: 'homepage',
  },
});

5. Get Content Blocks

// Fetch all content blocks
const contentBlocks = Resync.getContent();

// Find a specific content view by name
const welcomeCard = contentBlocks.find(
  (view) => view.name === 'HomeWelcomeCard'
);

console.log('Welcome card content:', welcomeCard);

API Reference

Resync.init(options)

Initialize the Resync SDK. Must be called before using any other methods.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | key | string | ✅ | Your Resync API key | | appId | number | ✅ | Your application ID | | callback | () => void | ❌ | Callback function invoked when config is loaded | | storage | Storage | ✅ | Storage object for caching (localStorage, AsyncStorage, etc.) | | environment | sandbox | production | ✅ | Environment for your project |

Returns

Promise<void> - Returns the Resync instance

Example

await Resync.init({
  key: 'rsk_live_abc123',
  appId: 7,
  callback: () => {
    console.log('Config loaded:');
  },
  storage: localStorage,
  environment: 'sandbox'
});

Resync.getConfig(key)

Get a configuration value by key.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | key | string | ✅ | Configuration key to retrieve |

Returns

any - The configuration value

Example

const apiUrl = Resync.getConfig('API_BASE_URL');
const maxRetries = Resync.getConfig('MAX_RETRIES');
const features = Resync.getConfig('ENABLED_FEATURES');

console.log('API URL:', apiUrl);
console.log('Max retries:', maxRetries);

Resync.getVariant(campaignName)

Get the assigned variant for a Campaign.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | campaignName | string | ✅ | Name of the campaign |

Returns

Promise<number | null> - Returns the variant content view ID or null

Example

const variant = await Resync.getVariant('checkout_flow_test');

if (variant === 123) {
  // Show variant A (content view ID 123)
  renderCheckoutVariantA();
} else if (variant === 124) {
  // Show variant B (content view ID 124)
  renderCheckoutVariantB();
}

Resync.getContent()

Get all content blocks from the current configuration.

Returns

ContentView[] - Array of content blocks

Example

const contentBlocks = Resync.getContent();

// Find specific content view
const bannerContent = contentBlocks.find(
  (view) => view.name === 'PromoAnnouncement'
);

// Iterate through all published content
contentBlocks
  .filter((view) => view.status === 'published')
  .forEach((view) => {
    console.log(`Content view: ${view.name}`);
  });

Resync.loginUser(userId, metadata)

Set the user ID for tracking and personalized variant assignment.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | userId | string \| number | ✅ | Unique user identifier | | metadata | object | ❌ | User metadata (email, name, phone, language) |

Returns

Promise<boolean> - Returns true if successful

Example

// Simple user ID
await Resync.loginUser('user_12345');

// With metadata
await Resync.loginUser('user_12345', {
  email: '[email protected]',
  name: 'John Doe',
  phone: '+1234567890',
  language: 'en',
});

Resync.setUserAttributes(attributes)

Set user attributes for targeting and personalization.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | attributes | object | ✅ | User attributes object | | attributes.email | string | ❌ | User email | | attributes.name | string | ❌ | User name | | attributes.phone | string | ❌ | User phone | | attributes.language | string | ❌ | User language | | attributes.attributes | object | ❌ | Additional custom attributes |

Returns

Promise<boolean> - Returns true if successful

Example

await Resync.setUserAttributes({
  email: '[email protected]',
  name: 'Jane Smith',
  phone: '+1234567890',
  language: 'en',
  attributes: {
    subscriptionTier: 'premium',
    country: 'US',
    signupDate: '2025-01-15',
  },
});

Resync.setClient(client)

Set a client identifier for tracking purposes.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | client | string | ✅ | Client identifier (e.g., 'web', 'mobile', 'ios', 'android') |

Example

Resync.setClient('web');
// or
Resync.setClient('mobile-ios');

Resync.logEvent(event)

Log a custom event for analytics and tracking.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | event | object | ✅ | Event object | | event.eventId | string | ✅ | Event identifier | | event.logId | string | ❌ | External log ID for correlation | | event.metadata | object | ❌ | Additional event metadata |

Example

// Simple event
Resync.logEvent({
  eventId: 'evt_user_signup',
});

// Event with metadata
Resync.logEvent({
  eventId: 'evt_purchase_completed',
  logId: 'order_789',
  metadata: {
    amount: 99.99,
    currency: 'USD',
    productId: 'prod_123',
    quantity: 2,
  },
});

Resync.submitForm(formData)

Submit form data to the Resync backend.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | formData | object | ✅ | Form submission object | | formData.contentViewId | number | ✅ | Content view ID of the form | | formData.data | object | ✅ | Form field data |

Returns

Promise<boolean | Error> - Returns true if successful, Error otherwise

Example

try {
  const success = await Resync.submitForm({
    contentViewId: 456,
    data: {
      name: 'John Doe',
      email: '[email protected]',
      message: 'Hello!',
    },
  });

  if (success) {
    console.log('Form submitted successfully');
  }
} catch (error) {
  console.error('Form submission failed:', error);
}

Resync.subscribe(callback)

Subscribe to configuration updates. The callback will be invoked whenever the configuration changes.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | callback | (config: AppConfig) => void | ✅ | Callback function |

Example

function handleConfigUpdate(config) {
  console.log('Config updated:', config);
  // Update UI or app state
}

Resync.subscribe(handleConfigUpdate);

Resync.unsubscribe(callback)

Unsubscribe from configuration updates.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | callback | (config: AppConfig) => void | ✅ | Previously subscribed callback function |

Example

Resync.unsubscribe(handleConfigUpdate);

Advanced Usage

Real-time Configuration Updates

Subscribe to configuration changes to update your app dynamically:

await Resync.init({
  key: 'your-api-key',
  appId: 7,
  storage: localStorage,
  callback: () => {
    console.log('Initial config loaded:');
  },
  environment: 'sandbox'
});

// Subscribe to future updates
Resync.subscribe(() => {
  console.log('Config updated!');
  // Update your app's state or UI
  updateAppSettings();
});

User Segmentation with attributes

Combine user attributes for targeted campaigns:

// Set user attributes
await Resync.loginUser('user_123', {
  email: '[email protected]',
  name: 'Alice',
});

await Resync.setUserAttributes({
  attributes: {
    userTier: 'premium',
    region: 'north-america',
  },
});

// Get variant (assignment may be based on attributes)
const variant = await Resync.getVariant('premium_feature_test');

if (variant) {
  // Show experiment variant
} else {
  // Show control
}

Dynamic Feature Flags

Use remote config for feature flagging:

// Check if a feature is enabled
const newUIEnabled = Resync.getConfig('ENABLE_NEW_UI');
const darkModeAvailable = Resync.getConfig('DARK_MODE_AVAILABLE');

if (newUIEnabled) {
  renderNewUI();
} else {
  renderLegacyUI();
}

// Get configuration objects
const apiSettings = Resync.getConfig('API_SETTINGS');
console.log('API timeout:', apiSettings?.timeout);
console.log('Max retries:', apiSettings?.maxRetries);

Event Tracking Pipeline

Build a comprehensive event tracking system:

// Track user journey
Resync.logEvent({
  eventId: 'evt_app_opened',
  metadata: { timestamp: Date.now() },
});

// Track interactions
document.getElementById('cta-button').addEventListener('click', () => {
  Resync.logEvent({
    eventId: 'evt_cta_clicked',
    metadata: {
      buttonId: 'cta-button',
      page: 'homepage',
    },
  });
});

// Track conversions
async function completePurchase(orderId, amount) {
  await processPayment();

  Resync.logEvent({
    eventId: 'evt_purchase_completed',
    logId: orderId,
    metadata: {
      amount,
      currency: 'USD',
      timestamp: Date.now(),
    },
  });
}

Storage Adapters

Use different storage adapters based on your platform:

Browser (Web)

await Resync.init({
  key: 'your-api-key',
  appId: 7,
  storage: localStorage, // or sessionStorage
  environment: 'sandbox'
});

React Native

import AsyncStorage from '@react-native-async-storage/async-storage';

await Resync.init({
  key: 'your-api-key',
  appId: 7,
  storage: AsyncStorage,
  environment: 'sandbox'
});

Custom Storage Adapter

// Implement your own storage adapter
const customStorage = {
  async getItem(key) {
    // Your implementation
  },
  async setItem(key, value) {
    // Your implementation
  },
  async removeItem(key) {
    // Your implementation
  },
  async clear() {
    // Your implementation
  },
};

await Resync.init({
  key: 'your-api-key',
  appId: 7,
  storage: customStorage,
  environment: 'sandbox'
});

TypeScript Support

The library includes comprehensive TypeScript definitions:

import Resync, {
  InitOptions,
  AppConfig,
  ContentView,
  Experiment,
  ExperimentVariant,
  AppEvent,
  Storage,
} from 'resync';

// Type-safe initialization
const options: InitOptions = {
  key: 'your-api-key',
  appId: 7,
  callback: () => {
    console.log('Resync loaded');
  },
  storage: localStorage,
};

await Resync.init(options);

// Type-safe event logging
const event: AppEvent = {
  eventId: 'evt_user_action',
  metadata: {
    action: 'click',
    target: 'button',
  },
};

Resync.logEvent(event);

Platform Support

  • JavaScript (ES6+) - Modern JavaScript environments
  • React Native - iOS and Android apps
  • Expo - Managed and bare workflows
  • Node.js - Server-side JavaScript (with compatible storage)
  • Web Browsers - Chrome, Firefox, Safari, Edge

Best Practices

1. Initialize Early

Initialize Resync as early as possible in your application lifecycle:

// App entry point
import Resync from 'resync';

async function initializeApp() {
  await Resync.init({
    key: process.env.RESYNC_API_KEY,
    appId: parseInt(process.env.RESYNC_APP_ID),
    storage: localStorage,
    environment: 'sandbox'
  });

  // Continue app initialization
  startApp();
}

initializeApp();

Note: Cache TTL is automatically configured based on your environment:

  • Development: No caching (always fetches fresh data for fast iteration)
  • Production: 6 hours cache (optimal performance)

2. Handle Errors Gracefully

Always handle potential errors:

try {
  await Resync.init({
    key: 'your-api-key',
    appId: 7,
    storage: localStorage,
    environment: 'sandbox'
  });
} catch (error) {
  console.error('Failed to initialize Resync:', error);
  // Fallback to default configuration
}

3. Use Environment Variables

Store API credentials securely:

await Resync.init({
  key: process.env.RESYNC_API_KEY,
  appId: parseInt(process.env.RESYNC_APP_ID),
  storage: localStorage,
  environment: 'sandbox'
});

4. Automatic Cache Management

The SDK automatically manages caching based on your environment:

await Resync.init({
  key: 'your-api-key',
  appId: 7,
  storage: localStorage,
  environment: 'sandbox'
});

// Cache TTL is set automatically:
// - Development: 0ms (no caching, always fresh)
// - Production: 6 hours (21600000ms)

5. Clean Up Subscriptions

Unsubscribe from updates when components unmount:

function MyComponent() {
  useEffect(() => {
    const handleUpdate = (config) => {
      console.log('Config updated:', config);
    };

    Resync.subscribe(handleUpdate);

    return () => {
      Resync.unsubscribe(handleUpdate);
    };
  }, []);
}

Troubleshooting

API Key Issues

Problem: "API key is required" error

Solution: Ensure you're passing the API key during initialization:

await Resync.init({
  key: 'rsk_live_your_api_key', // Make sure this is set
  appId: 7,
  storage: localStorage,
  environment: 'sandbox'
});

Storage Issues

Problem: "Storage is required" error

Solution: Provide a valid storage object:

// Web
await Resync.init({
  key: 'your-api-key',
  appId: 7,
  storage: localStorage, // Add storage
  environment: 'sandbox'
});

// React Native
import AsyncStorage from '@react-native-async-storage/async-storage';

await Resync.init({
  key: 'your-api-key',
  appId: 7,
  storage: AsyncStorage, // Add storage
  environment: 'sandbox'
});

Configuration Not Updating

Problem: Configuration values aren't updating in production

Solution: The cache TTL is automatically set based on environment:

  • Production: 6 hours cache
  • Development: No cache (always fresh)

Examples

Check out the example for a complete working example.

License

MIT


Built with ❤️ for developers who ship fast