studio-sdk

📁 kvngrf/flowsterix 📅 11 days ago
3
总安装量
3
周安装量
#62126
全站排名
安装命令
npx skills add https://github.com/kvngrf/flowsterix --skill studio-sdk

Agent 安装分布

amp 3
claude-code 3
github-copilot 3
codex 3
kimi-cli 3
gemini-cli 3

Skill 文档

Flowsterix Studio SDK

@flowsterix/studio bridges the open-source Flowsterix library to the proprietary Studio backend. It intercepts analytics events and storage operations, serializes them to JSON-safe payloads, and ships them in batches to a Studio ingest endpoint.

Architecture

TourProvider
  analytics={bridge.analytics}     --> serializer --> transport --> POST /v1/ingest
  storageAdapter={bridge.storage({ inner: localStorage })}
                                       |
                                       +--> inner adapter (read/write)
                                       +--> transport (fire-and-forget sync)
  • No React dependency – pure JS, works with any framework
  • Dep: @flowsterix/core only (uses FlowAnalyticsHandlers, StorageAdapter types)
  • Package: packages/studio/ in the monorepo

Quick Start

import { createStudioBridge } from '@flowsterix/studio'
import { createLocalStorageAdapter } from '@flowsterix/core'

const bridge = createStudioBridge({
  projectId: 'proj_abc',
  apiKey: 'sk_live_xxx',
  // endpoint: 'https://ingest.flowsterix.studio', // default
  // batchSize: 20,        // default
  // flushIntervalMs: 5000, // default
  // debug: false,          // include stack traces in error events
  user: { id: 'user-123', traits: { plan: 'pro' } },
})

// In React:
<TourProvider
  flows={flows}
  analytics={bridge.analytics}
  storageAdapter={bridge.storage({ inner: createLocalStorageAdapter() })}
>

Public API

createStudioBridge(params: StudioBridgeOptions): StudioBridge

interface StudioBridgeOptions {
  projectId: string
  apiKey: string
  endpoint?: string          // default: https://ingest.flowsterix.studio
  user?: UserContext
  debug?: boolean            // include stack traces in error events
  batchSize?: number         // default: 20
  flushIntervalMs?: number   // default: 5000
}

interface UserContext {
  id: string
  traits?: Record<string, unknown>
}

interface StudioBridge {
  analytics: FlowAnalyticsHandlers<unknown>   // pass to TourProvider
  storage: (params: { inner: StorageAdapter }) => StorageAdapter  // wraps an inner adapter
  identify: (params: { user: UserContext }) => void  // update user mid-session
  flush: () => Promise<void>    // force-flush buffered events
  shutdown: () => void          // flush + cleanup listeners
}

Lifecycle

  • identify() — update user context after login; enqueues an identify event
  • flush() — force-send buffered events (useful before navigation)
  • shutdown() — flush remaining via sendBeacon, remove visibilitychange listener, clear interval

Module Overview

File Responsibility
src/bridge.ts createStudioBridge — factory, wires serializer + transport + storage
src/serializer.ts Strips functions, ReactNodes, RegExp from payloads; produces StudioEvent
src/transport.ts Batched HTTP POST to /v1/ingest, retry on failure, 500-event buffer cap, sendBeacon fallback
src/storage.ts StorageAdapter wrapper — delegates to inner, fire-and-forget enqueues storage.set/storage.remove
src/types.ts All type definitions

Serialization Rules

The serializer strips non-JSON-safe values from FlowDefinition and Step:

Flow: keeps id, version, metadata, autoStart, resumeStrategy, stepCount. Drops steps array, hud, migrate, dialogs.

Step: keeps id, target (selector string or 'screen'), placement, mask, controls, dialogId, route (RegExp .source), advance (drops check fn). Drops content, onEnter, onExit, onResume, waitFor, targetBehavior.

Error events: keeps code, meta, message, name. Stack only if debug: true.

Version mismatch: serializes oldVersion/newVersion as "major.minor" strings.

Transport Details

  • Buffer flushes when batchSize reached OR every flushIntervalMs
  • On fetch error: events re-added to front of buffer (retry next flush)
  • Buffer capped at 500 events to prevent memory leaks
  • On visibilitychange → hidden: calls shutdown() which uses sendBeacon
  • Shutdown fallback: fetch with keepalive: true
  • Auth header: Authorization: Bearer ${apiKey}

Flow Registration

Flows are not registered upfront. The first analytics event for each flow implicitly registers it — every StudioEvent contains a serialized flow field. The backend deduplicates by (projectId, flowId, version).

Key Patterns

Wrapping storage with Studio sync

// The storage wrapper delegates all reads/writes to the inner adapter
// and fire-and-forget enqueues sync events to the transport
const storageAdapter = bridge.storage({
  inner: createLocalStorageAdapter()
})

Identifying users after auth

// Call after login — updates user on all subsequent events
bridge.identify({ user: { id: userId, traits: { plan, role } } })

Cleanup on unmount

useEffect(() => {
  return () => bridge.shutdown()
}, [])