Skip to main content

@slopit/adapter-shared API Reference

Shared utilities and base classes for building platform adapters. This package provides the foundation that all platform-specific adapters build upon.

Installation

pnpm add @slopit/adapter-shared
note

Most users do not need to install this package directly. It is a dependency of all platform-specific adapters (e.g., @slopit/adapter-jspsych, @slopit/adapter-labjs).

When to Use This Package

Install @slopit/adapter-shared directly when:

  • Building a custom adapter for an unsupported platform
  • Creating utilities that work across multiple adapters
  • Extending the base recorder with custom functionality

BaseRecorder

Abstract base class that all platform-specific recorders extend. Manages session state, trial lifecycle, and behavioral capture.

Creating a Custom Recorder

import { BaseRecorder } from "@slopit/adapter-shared";
import type { PlatformInfo } from "@slopit/core";

class MyPlatformRecorder extends BaseRecorder {
protected getPlatformInfo(): PlatformInfo {
return {
name: "my-platform",
version: "1.0.0",
adapterVersion: "0.1.0",
};
}
}

Constructor

constructor(config?: RecorderConfig)

RecorderConfig

PropertyTypeDefaultDescription
participantIdstring-Participant identifier from recruitment platform
studyIdstring-Study identifier
metadataRecord<string, unknown>-Session-level metadata
behavioralBehavioralCaptureConfig{}Behavioral capture configuration

Methods

startTrial(config)

Starts a new trial.

startTrial(config: TrialConfig): void

Parameters:

ParameterTypeDescription
configTrialConfigTrial configuration

Throws: Error if a trial is already in progress.

recorder.startTrial({
trialId: "trial_1",
trialType: "survey-text",
targetElement: document.querySelector("textarea"),
stimulus: {
type: "text",
content: "Describe your experience.",
},
});

endTrial(response?, platformData?)

Ends the current trial and returns the completed trial data.

endTrial(response?: ResponseInfo, platformData?: Record<string, unknown>): CompletedTrial

Parameters:

ParameterTypeDescription
responseResponseInfoResponse information
platformDataRecord<string, unknown>Platform-specific trial data

Returns: CompletedTrial object with behavioral data.

Throws: Error if no trial is in progress.

const trial = recorder.endTrial({
type: "text",
value: "User response text",
characterCount: 18,
wordCount: 3,
});

attachCapture(element, startTime?)

Attaches behavioral capture to an element for the current trial. Use this when the target element becomes available after startTrial() is called.

attachCapture(element: HTMLElement, startTime?: number): void

Throws: Error if no trial is in progress or if capture is already attached.

recorder.startTrial({ trialId: "trial_1" });

// later, when element is available
const textarea = document.querySelector("textarea");
recorder.attachCapture(textarea);

detachCapture()

Detaches behavioral capture without ending the trial.

detachCapture(): void

exportSession()

Exports the session data in SlopitSession format.

exportSession(): SlopitSession
const session = recorder.exportSession();
await fetch("/api/sessions", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(session),
});

getCurrentTrial()

Gets the current trial state.

getCurrentTrial(): TrialState | null

getTrials()

Gets all completed trials.

getTrials(): CompletedTrial[]

isTrialInProgress()

Checks if a trial is currently in progress.

isTrialInProgress(): boolean

getSessionId()

Gets the session ID.

getSessionId(): string

reset()

Resets the recorder for a new session. Clears all trials and generates a new session ID.

reset(): void

Element Discovery

Utilities for finding DOM elements that may not exist yet when capture needs to start.

discoverElement(options)

Discovers an element in the DOM using a MutationObserver. If the element already exists, the callback is invoked immediately. Otherwise, it watches for DOM changes until the element appears or the timeout is reached.

function discoverElement(options: DiscoverElementOptions): () => void

Returns: Cleanup function to disconnect the observer and cancel the timeout.

DiscoverElementOptions

PropertyTypeDefaultDescription
selectorstring(required)CSS selector for the element to find
containerHTMLElement | Document(required)Container to search within
timeoutnumber5000Timeout in milliseconds
onFound(element: HTMLElement) => void(required)Callback when element is found
onTimeout() => void-Callback if element not found within timeout
import { discoverElement } from "@slopit/adapter-shared";

const cleanup = discoverElement({
selector: "textarea.response-input",
container: document.getElementById("trial-container"),
timeout: 3000,
onFound: (element) => {
recorder.attachCapture(element);
},
onTimeout: () => {
console.warn("Target element not found within timeout");
},
});

// to cancel observation early
cleanup();

discoverElements(options)

Discovers multiple elements in the DOM. Waits until the minimum number of matching elements are present.

function discoverElements(options: DiscoverElementsOptions): () => void

DiscoverElementsOptions

PropertyTypeDefaultDescription
selectorstring(required)CSS selector for elements to find
containerHTMLElement | Document(required)Container to search within
minCountnumber1Minimum number of elements required
timeoutnumber5000Timeout in milliseconds
onFound(elements: HTMLElement[]) => void(required)Callback when elements are found
onTimeout(found: HTMLElement[]) => void-Callback with partial results on timeout
import { discoverElements } from "@slopit/adapter-shared";

const cleanup = discoverElements({
selector: "input[type='text']",
container: document.body,
minCount: 3,
onFound: (inputs) => {
inputs.forEach((input) => capture.attach(input));
},
});

Export Utilities

Functions for building SlopitSession data structures.

createSessionMetadata(platform, options?)

Creates the base structure for a SlopitSession.

function createSessionMetadata(
platform: PlatformInfo,
options?: CreateSessionMetadataOptions
): SessionMetadataResult
import { createSessionMetadata } from "@slopit/adapter-shared";

const sessionBase = createSessionMetadata(
{ name: "jspsych", version: "8.0.0", adapterVersion: "0.1.0" },
{ participantId: "P001", studyId: "study-123" }
);

completeSession(sessionBase, trials, options?)

Completes a session by adding timing and global events.

function completeSession(
sessionBase: SessionMetadataResult,
trials: SlopitTrial[],
options?: CompleteSessionOptions
): SlopitSession

convertTrialToSlopit(data)

Converts trial data to the SlopitTrial format.

function convertTrialToSlopit(data: TrialConversionData): SlopitTrial

createTextResponse(text)

Creates a ResponseInfo object from a text string.

function createTextResponse(text: string): ResponseInfo
import { createTextResponse } from "@slopit/adapter-shared";

const response = createTextResponse("Hello world");
// { type: "text", value: "Hello world", characterCount: 11, wordCount: 2 }

Types

TrialConfig

Configuration for starting a new trial.

interface TrialConfig {
trialId?: string;
trialIndex?: number;
trialType?: string;
stimulus?: StimulusInfo;
targetElement?: HTMLElement;
targetSelector?: string;
}

TrialState

State of a trial currently being recorded.

interface TrialState {
trialId: string;
trialIndex: number;
trialType?: string;
startTime: number;
stimulus?: StimulusInfo;
element?: HTMLElement;
}

CompletedTrial

Complete trial data after recording.

interface CompletedTrial {
trialId: string;
trialIndex: number;
trialType?: string;
startTime: number;
endTime: number;
stimulus?: StimulusInfo;
response?: ResponseInfo;
behavioral?: BehavioralData;
captureFlags?: CaptureFlag[];
platformData?: Record<string, unknown>;
}

AdapterConfig

Base configuration for platform adapters.

interface AdapterConfig extends BehavioralCaptureConfig {
enabled?: boolean;
targetSelector?: string;
}

AdapterData

Data collected by the adapter during a trial.

interface AdapterData {
behavioral: BehavioralData;
flags: CaptureFlag[];
}

Test Utilities

Helper functions for testing adapters. These are exported for use in adapter test suites.

import {
createMockTextarea,
createMockInput,
simulateTyping,
simulateKeystroke,
simulatePaste,
simulateFocus,
simulateBlur,
delay,
waitFor,
} from "@slopit/adapter-shared";

simulateTyping(element, text, options?)

Simulates typing a string character by character.

await simulateTyping(textarea, "Hello world", { delay: 50 });

simulateKeystroke(element, key, options?)

Simulates a single keystroke event.

simulateKeystroke(textarea, "a", { shiftKey: true });

simulatePaste(element, text, options?)

Simulates a paste event.

simulatePaste(textarea, "pasted content", { dispatchInput: true });