@bytelyst/survey-client (0.1.0)
Published 2026-03-29 07:53:29 +00:00 by bytelyst-admin
Installation
@bytelyst:registry=npm install @bytelyst/survey-client@0.1.0"@bytelyst/survey-client": "0.1.0"About this package
@bytelyst/survey-client
TypeScript client for the ByteLyst Survey platform. Provides survey discovery, question flow management, response submission, and offline caching.
Installation
npm install @bytelyst/survey-client
# or
pnpm add @bytelyst/survey-client
Quick Start
import { createSurveyClient } from '@bytelyst/survey-client';
const client = createSurveyClient({
baseURL: 'https://api.bytelyst.io/v1',
productId: 'lysnrai',
getAuthToken: async () => {
return localStorage.getItem('token');
}
});
// Check for active survey
const [survey, error] = await client.getActiveSurvey();
if (survey) {
console.log('Survey available:', survey.title);
}
API Reference
createSurveyClient(config)
Creates a new survey client instance.
Config:
| Option | Type | Required | Description |
|---|---|---|---|
baseURL |
string | Yes | API base URL |
productId |
string | Yes | Product identifier |
getAuthToken |
() => Promise | Yes | Function to retrieve JWT token |
enableOfflineCache |
boolean | No | Enable offline response caching (default: true) |
Methods
getActiveSurvey()
Check if there's an active survey for the current user.
const [survey, error] = await client.getActiveSurvey();
// Returns: ActiveSurvey | null
startSurvey(surveyId: string)
Start a survey session.
const [state, error] = await client.startSurvey('srv_123');
// Returns: { surveyStateId: string, currentQuestionIndex: number }
submitAnswer(surveyId: string, questionId: string, answer: SurveyAnswer)
Submit an answer for a specific question.
const [result, error] = await client.submitAnswer('srv_123', 'q1', {
type: 'rating',
value: { value: 8 }
});
// Returns: { currentQuestionIndex: number, nextQuestionId: string, isComplete: boolean }
Answer Types:
// Single choice
{ type: 'single_choice', value: { value: 'option_1' } }
// Multiple choice
{ type: 'multiple_choice', value: { values: ['opt_1', 'opt_2'] } }
// Rating/NPS/Scale
{ type: 'rating', value: { value: 8 } }
// Text
{ type: 'text', value: { value: 'My feedback here' } }
// Ranking
{ type: 'ranking', value: { order: ['opt_1', 'opt_2', 'opt_3'] } }
completeSurvey(surveyId: string)
Mark survey as complete and claim any incentive.
const [completion, error] = await client.completeSurvey('srv_123');
// Returns: { success: boolean, incentiveClaimed: boolean, incentiveType?: string, incentiveAmount?: number }
dismissSurvey(surveyId: string)
Dismiss survey without completing.
await client.dismissSurvey('srv_123');
startPolling(intervalMs: number, callback: (survey) => void)
Start polling for active surveys.
client.startPolling(60000, (survey) => {
if (survey) {
showSurveyModal(survey);
}
});
stopPolling()
Stop survey polling.
client.stopPolling();
flushOfflineQueue()
Manually flush any cached offline responses.
await client.flushOfflineQueue();
React Integration
Hook Usage
import { useSurvey } from './hooks/useSurvey';
function SurveyWidget() {
const {
activeSurvey,
currentQuestion,
submitAnswer,
completeSurvey,
progress
} = useSurvey({
autoStart: true,
pollingInterval: 60000
});
if (!activeSurvey) return null;
return (
<SurveyModal
survey={activeSurvey}
currentQuestion={currentQuestion}
progress={progress}
onSubmit={submitAnswer}
onComplete={completeSurvey}
/>
);
}
Complete Survey Flow Example
function SurveyFlow() {
const client = useSurveyClient();
const [survey, setSurvey] = useState<ActiveSurvey | null>(null);
const [currentIndex, setCurrentIndex] = useState(0);
const [answers, setAnswers] = useState<Record<string, SurveyAnswer>>({});
useEffect(() => {
loadSurvey();
}, []);
async function loadSurvey() {
const [activeSurvey] = await client.getActiveSurvey();
if (activeSurvey) {
await client.startSurvey(activeSurvey.id);
setSurvey(activeSurvey);
}
}
async function handleAnswer(questionId: string, answer: SurveyAnswer) {
const [result] = await client.submitAnswer(survey!.id, questionId, answer);
setAnswers(prev => ({ ...prev, [questionId]: answer }));
setCurrentIndex(result.currentQuestionIndex);
if (result.isComplete) {
const [completion] = await client.completeSurvey(survey!.id);
if (completion.incentiveClaimed) {
showIncentiveToast(completion.incentiveAmount, completion.incentiveType);
}
}
}
if (!survey) return null;
const question = survey.questions[currentIndex];
const isLast = currentIndex === survey.questions.length - 1;
return (
<QuestionView
question={question}
onSubmit={(answer) => handleAnswer(question.id, answer)}
onSkip={question.required ? undefined : () => handleSkip(question.id)}
/>
);
}
Offline Support
The client automatically caches responses when offline:
const client = createSurveyClient({
baseURL: 'https://api.bytelyst.io/v1',
productId: 'lysnrai',
getAuthToken: () => getToken(),
enableOfflineCache: true // Enabled by default
});
// Responses are queued when offline
// Flush queue manually or on reconnect
window.addEventListener('online', () => {
client.flushOfflineQueue();
});
Types
interface ActiveSurvey {
id: string;
title: string;
description?: string;
questions: Question[];
currentQuestionIndex: number;
incentive?: {
type: 'pro_days' | 'credits';
amount: number;
};
}
interface Question {
id: string;
type: 'single_choice' | 'multiple_choice' | 'rating' | 'scale' |
'nps' | 'text_short' | 'text_long' | 'ranking' | 'dropdown';
text: string;
description?: string;
required: boolean;
options?: QuestionOption[];
minValue?: number;
maxValue?: number;
maxLength?: number;
showIf?: ShowIfCondition;
}
interface QuestionOption {
id: string;
text: string;
emoji?: string;
}
interface SurveyAnswer {
type: string;
value: Record<string, unknown>;
}
interface SurveyConfig {
baseURL: string;
productId: string;
getAuthToken: () => Promise<string>;
enableOfflineCache?: boolean;
}
Question Type Reference
| Type | Answer Format | UI Component |
|---|---|---|
single_choice |
{ value: string } |
Radio group |
multiple_choice |
{ values: string[] } |
Checkboxes |
rating |
{ value: number } |
Star rating (1-5) |
scale |
{ value: number } |
Numeric slider |
nps |
{ value: number } |
0-10 buttons |
text_short |
{ value: string } |
Single line input |
text_long |
{ value: string } |
Textarea |
ranking |
{ order: string[] } |
Drag-to-sort |
dropdown |
{ value: string } |
Select dropdown |
Conditional Logic
Questions can be shown/hidden based on previous answers:
// Question only shows if q1 answer is NOT 9 or 10
{
id: 'q2',
type: 'text_long',
text: 'What could we improve?',
showIf: {
questionId: 'q1',
operator: 'not_equals',
value: ['9', '10']
}
}
Operators: equals, not_equals, greater_than, less_than, contains
Error Handling
const [data, error] = await client.submitAnswer('srv_123', 'q1', answer);
if (error) {
switch (error.code) {
case 'SURVEY_NOT_FOUND':
console.error('Survey expired or unavailable');
break;
case 'ALREADY_COMPLETED':
console.error('User already completed this survey');
break;
case 'VALIDATION_ERROR':
console.error('Invalid answer format');
break;
default:
console.error('Survey error:', error.message);
}
}
Browser Support
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
License
MIT © ByteLyst
Details
2026-03-29 07:53:29 +00:00
Assets (1)
Versions (1)
View all
npm
2
latest
7.5 KiB
survey-client-0.1.0.tgz
7.5 KiB
0.1.0
2026-03-29