New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@layers/foyer

Package Overview
Dependencies
Maintainers
3
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install
Package was removed
Sorry, it seems this package was removed from the registry

@layers/foyer

Foyer SDK for React Native/Expo - Dynamic onboarding flows with A/B testing

latest
Source
npmnpm
Version
1.0.1
Version published
Maintainers
3
Created
Source

@layers/foyer

Foyer SDK for React Native and Expo - Dynamic onboarding flows with A/B testing.

Installation

npm install @layers/foyer
# or
yarn add @layers/foyer

Quick Start

1. Get Your API Key

First, create an API key in your Foyer dashboard at https://foyer.yourdomain.com/dashboard/api-keys

2. Initialize the SDK

import { Foyer } from '@layers/foyer';

const foyer = new Foyer({
  apiKey: process.env.FOYER_API_KEY, // Your Foyer API key
  projectId: 'your-project-id',
  enableAnalytics: true,
  debug: __DEV__,
});

3. Start a Flow

const flow = await foyer.startFlow('user-123', {
  onAnswer: (data) => {
    console.log('Screen answered:', data);
    // Update your app state, save to AsyncStorage, etc.
  },
  onComplete: (data) => {
    console.log('Flow completed!', data);
    // Navigate to main app
    navigation.navigate('Home');
  },
  onAbandon: (data) => {
    console.log('Flow abandoned:', data);
  },
  onError: (error) => {
    console.error('Error:', error);
  },
});

4. Use the Pre-built UI Component

import { FoyerFlow } from '@layers/foyer';

function OnboardingScreen() {
  return (
    <FoyerFlow
      foyer={foyer}
      userId="user-123"
      callbacks={{
        onComplete: (data) => {
          navigation.navigate('Home');
        },
      }}
    />
  );
}

API Reference

Foyer Class

Constructor

new Foyer(config: FoyerConfig)

Config Options:

  • apiKey (required) - Your Foyer API key (get from dashboard)
  • projectId (required) - Your Foyer project ID
  • enableAnalytics (optional) - Enable event tracking (default: true)
  • enableOfflineQueue (optional) - Queue events offline (default: false)
  • debug (optional) - Enable debug logging (default: false)

Methods

startFlow(userId: string, callbacks?: FoyerCallbacks): Promise<Flow>

Start a flow for a user. Returns the flow definition.

submitAnswer(answerValue: unknown): Promise<void>

Submit an answer for the current screen and advance to the next.

skipScreen(): Promise<void>

Skip the current screen (only if it's optional).

abandonFlow(): Promise<void>

Abandon the current flow.

getCurrentScreen(): Screen | null

Get the current screen definition.

getCurrentScreenIndex(): number

Get the index of the current screen (0-based).

getTotalScreens(): number

Get the total number of screens in the flow.

hasNextScreen(): boolean

Check if there are more screens after the current one.

getProgress(): number

Get progress percentage (0-100).

flush(): Promise<void>

Manually flush queued analytics events.

Callbacks

interface FoyerCallbacks {
  onAnswer?: (data: AnswerCallbackData) => void;
  onComplete?: (data: CompleteCallbackData) => void;
  onAbandon?: (data: AbandonCallbackData) => void;
  onError?: (error: Error) => void;
}

onAnswer

Fires when a user answers a screen.

{
  screen_id: string;
  screen_index: number;
  screen_type: ScreenType;
  answer_value: unknown;
  flow_id: string;
  variant_id: string;
}

onComplete

Fires when the flow is completed.

{
  flow_id: string;
  variant_id: string;
  total_time_ms: number;
  screens_completed: number;
}

onAbandon

Fires when the flow is abandoned.

{
  flow_id: string;
  variant_id: string;
  screen_id: string;
  screen_index: number;
  total_time_ms: number;
}

Screen Types

Info

Display information with optional image.

{
  "id": "welcome",
  "type": "info",
  "title": "Welcome!",
  "body": "Let's get started",
  "image": "https://example.com/image.png"
}

Single Choice

Single selection from options.

{
  "id": "bedtime",
  "type": "single_choice",
  "question": "When do you go to bed?",
  "options": ["Before 10PM", "10-12PM", "After midnight"]
}

Multiple Choice

Multiple selections from options.

{
  "id": "goals",
  "type": "multiple_choice",
  "question": "What are your goals?",
  "options": ["Sleep better", "Exercise more", "Eat healthier"],
  "minSelections": 1,
  "maxSelections": 3
}

Text Input

Free-form text input.

{
  "id": "name",
  "type": "text_input",
  "question": "What's your name?",
  "placeholder": "Enter your name",
  "maxLength": 50,
  "validation": "none"
}

Validation options: "email", "phone", "url", "none"

Slider

Numeric range selection.

{
  "id": "hours",
  "type": "slider",
  "question": "How many hours do you sleep?",
  "min": 4,
  "max": 12,
  "step": 0.5,
  "minLabel": "4h",
  "maxLabel": "12h",
  "defaultValue": 8
}

Date Input

Date/time selection.

{
  "id": "birthday",
  "type": "date_input",
  "question": "When is your birthday?",
  "mode": "date"
}

Mode options: "date", "time", "datetime"

Custom UI

If you want to build custom UI instead of using the pre-built components:

import { Foyer } from '@layers/foyer';

function CustomOnboarding() {
  const [foyer] = useState(() => new Foyer({ /* ... */ }));
  const [screen, setScreen] = useState(null);

  useEffect(() => {
    async function start() {
      await foyer.startFlow('user-123', {
        onAnswer: (data) => {
          // Handle answer
          setScreen(foyer.getCurrentScreen());
        },
        onComplete: () => {
          // Navigate away
        },
      });
      setScreen(foyer.getCurrentScreen());
    }
    start();
  }, []);

  const handleAnswer = async (answer) => {
    await foyer.submitAnswer(answer);
  };

  if (!screen) return <Loading />;

  // Render custom UI based on screen.type
  switch (screen.type) {
    case 'info':
      return <CustomInfoScreen screen={screen} onContinue={() => handleAnswer(null)} />;
    case 'single_choice':
      return <CustomChoiceScreen screen={screen} onAnswer={handleAnswer} />;
    // ... etc
  }
}

TypeScript Support

The SDK is written in TypeScript and includes full type definitions:

import type {
  Flow,
  Screen,
  InfoScreen,
  SingleChoiceScreen,
  AnswerCallbackData,
  // ... etc
} from '@layers/foyer';

Validation

All flows and events are validated at runtime using Zod:

import { validateFlow, isValidScreen } from '@layers/foyer';

try {
  const flow = validateFlow(data);
} catch (error) {
  console.error('Invalid flow:', error);
}

if (isValidScreen(data)) {
  // Safe to use
}

Offline Support

Enable offline event queuing:

const foyer = new Foyer({
  // ...
  enableOfflineQueue: true,
});

// Events will be queued and sent when online
// Manually flush if needed
await foyer.flush();

Examples

Check the /examples directory for complete integration examples:

  • Expo app with TypeScript
  • React Native app
  • Custom UI implementation
  • Offline support demo

License

Proprietary - Not licensed for public use

Keywords

onboarding

FAQs

Package last updated on 10 Nov 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts