Skip to content

createSession

createSession creates a headless store for one quote journey. Your view subscribes to it and renders; the session handles saving, resume, quoting and handoff.

const session = createSession({ client, vertical })
import { createSession, sessionStorageAdapter } from '@partner-sdk/core/session';
const session = createSession({
client,
vertical: 'cyber',
storage: sessionStorageAdapter(),
});
  • client: a Client.
  • vertical: the product to quote, such as "cyber".
  • storage (optional): where answers persist. Default memoryStorage() (lost on reload). Use sessionStorageAdapter() in browsers. See storage.
  • storageKey (optional): default `sb-quote:${vertical}`.
  • initial (optional): a Promise<Questionnaire> already being created, for prefetching. Adopted by start() when nothing is resumed.
  • debounceMs (optional): quiet period before edits are sent as one PATCH. Default 400.
  • quoteTimeoutMs (optional): default 120000.
  • ttlMs (optional): stored sessions older than this are ignored. Default 24 hours.
  • onEvent (optional): (event) => void. Events never carry answers.
  • eventTarget (optional): where online and pagehide are listened for. Default globalThis; pass null outside browsers.

A Session.

  • Actions never reject. Failures land in state.
  • After handoff or dispose(), every action is a no-op.

Returns the current SessionState. A new object after every change.

Calls listener after every change. Returns an unsubscribe function.

session.select(selector, listener, equals?)

Section titled “session.select(selector, listener, equals?)”

Calls listener only when selector(state) changes, compared by equals (default Object.is). Returns an unsubscribe function.

session.select(toScreen, render, screenEquals);

Resumes the stored questionnaire if it is still valid, else creates one. Idempotent.

  • A 401, 403, 404 or 410 on resume clears storage and starts fresh.
  • A network error keeps storage and sets error: { action: "start" }; call start() again to retry.

Stores a value by question name, clears that question’s errors and schedules a sync. Synchronous.

If the journey is quoting, quoted or failed, an edit returns it to questioning and stops any poll.

Sends pending answers now. Call it when a field commits (field.commit: blur or change).

Only one PATCH is in flight at a time; edits made meanwhile go in the next batch. A failed sync keeps the answers pending and retries on the next edit, flush or online event.

Searches trades with the named question’s template. The latest call per name wins. Results land in state.search[name]. Debounce typing in your UI.

Flushes, then polls for quotes if ready. Otherwise sets quotes: { status: "blocked", missing }. A second call joins the running one.

After failed: follows the server’s retry, or polls again.

After quoted: selects the quote, removes stored answers and moves to handoff with handoffUrl. A failure sets error: { action: "selectQuote" }.

After quoted with no selectable quote: removes stored answers and moves to handoff with the comparison URL. Otherwise a no-op.

Persists once, then stops every timer, request and listener.

const session = createSession({ client, vertical: 'cyber', storage: sessionStorageAdapter() });
await session.start(); // picks up where the customer left off, answers included

Start creating it before your UI mounts:

const initial = client.start('cyber');
// ...later
const session = createSession({ client, vertical: 'cyber', initial });
createSession({
client,
vertical: 'cyber',
onEvent: (event) => analytics.track(`quote_${event.type}`, event),
});

Events are safe to send: counts, durations and error names only.

import { createFakeSession } from '@partner-sdk/core/session/testing';
const fake = createFakeSession([{ phase: 'starting' }, { phase: 'questioning', questions }]);
fake.next(); // move to the next state
fake.calls; // actions your view called

Edits are debounced. Call session.flush() on blur or choice change, or wait for debounceMs. Check state.sync.status for "error".

edit() with the value already stored is a no-op. That’s by design.