npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@owlmeans/flow

v0.1.1

Published

A configurable user flow management system for OwlMeans Common applications. This package provides a comprehensive framework for defining, managing, and executing multi-step user workflows with state management, transitions, and cross-service coordination

Readme

@owlmeans/flow

A configurable user flow management system for OwlMeans Common applications. This package provides a comprehensive framework for defining, managing, and executing multi-step user workflows with state management, transitions, and cross-service coordination.

Overview

The @owlmeans/flow package is a workflow orchestration library in the OwlMeans Common ecosystem that enables:

  • Multi-Step Workflows: Define complex user journeys with multiple steps and decision points
  • State Management: Maintain flow state across steps and services
  • Cross-Service Coordination: Coordinate workflows across different microservices
  • Configurable Transitions: Define conditional transitions between workflow steps
  • Payload Management: Handle data passing between workflow steps
  • Reversible Steps: Support for backward navigation in workflows
  • Serialization: Persistent workflow state through URL parameters or storage
  • Internationalization: Built-in i18n support for workflow content

Installation

npm install @owlmeans/flow

Core Concepts

Flow Definition

A flow is a structured definition of a multi-step process with:

  • Steps: Individual stages in the workflow
  • Transitions: Connections between steps with conditions
  • Configuration: Global settings and service mappings
  • Payload Mapping: Data transformation rules between steps

Flow State

The current state of a workflow execution including:

  • Current step
  • Previous step (for reversible flows)
  • Payload data
  • Target service
  • Status information

Flow Model

A runtime instance that provides methods to:

  • Navigate between steps
  • Execute transitions
  • Manage state and payload
  • Serialize/deserialize flow state

API Reference

Types

Flow

Complete flow definition with configuration and prefabs.

interface Flow extends ShallowFlow {
  config: FlowConfig
  prefabs: { [step: string]: string }
}

ShallowFlow

Basic flow structure without configuration.

interface ShallowFlow {
  flow: string
  initialStep: string
  steps: { [key: string]: FlowStep }
}

FlowStep

Individual step definition in a workflow.

interface FlowStep {
  index: number
  step: string
  service: string
  path?: string
  module?: string
  initial?: boolean
  payloadMap?: { [key: string]: number }
  transitions: { [key: string]: FlowTransition }
}

FlowTransition

Transition between workflow steps.

interface FlowTransition {
  transition: string
  step: string
  explicit?: boolean      // User can choose this transition
  reversible?: boolean    // User can go back
}

FlowState

Current state of workflow execution.

interface FlowState {
  flow: string
  step: string
  previous?: string
  entityId?: string | null
  service: string
  payload?: FlowPayload
  message?: string
  ok: boolean
}

FlowConfig

Global configuration for flow behavior.

interface FlowConfig {
  queryParam?: string                    // URL parameter name for flow state
  services?: { [ref: string]: string }   // Service reference mappings
  modules?: { [ref: string]: string }    // Module reference mappings
  pathes?: { [ref: string]: string }     // Path reference mappings
  defaultFlow?: string                   // Default flow to use
}

FlowModel

Runtime workflow management interface.

interface FlowModel {
  target: (service: string) => FlowModel
  entity: (entityId: string) => FlowModel
  enter: (step?: string) => FlowModel
  steps: (enter?: boolean) => FlowStep[]
  state: () => FlowState
  setState: (state: FlowState | null) => FlowModel
  payload: <T extends FlowPayload>() => T
  step: (step?: string) => FlowStep
  transitions: (explicit?: boolean) => FlowTransition[]
  transition: (transition: string) => FlowTransition
  next: () => FlowTransition
  transit: (transition: string, ok: boolean, message?: string | FlowPayload, payload?: FlowPayload) => string
  serialize: () => string
}

Factory Functions

makeFlowModel(flow: string | ShallowFlow, provider?: FlowProvider): Promise<FlowModel>

Creates a flow model instance from flow definition or serialized state.

Parameters:

  • flow: Flow name, definition, or serialized state
  • provider: Optional flow provider function

Returns: Promise resolving to FlowModel instance

Helper Functions

flow<C>(cfg: C, flow: ShallowFlow): C

Adds a flow definition to configuration.

configureFlows<C>(cfg: C & WithFlowConfig, config: FlowConfig): C & WithFlowConfig

Adds flow configuration to application config.

Error Types

The package provides specialized error types for flow operations:

FlowError

Base error class for all flow-related errors.

FlowUnsupported

Error for unsupported flow operations.

FlowTargetError

Error related to flow target service issues.

UnknownFlow

Error when referenced flow doesn't exist.

FlowStepError

Base error for step-related issues.

FlowStepMissconfigured

Error for misconfigured flow steps.

UnknownFlowStep

Error when referenced step doesn't exist.

UnknownTransition

Error when referenced transition doesn't exist.

Constants

// Standard flow types
const STD_AUTH_FLOW = '_oa'      // Authentication flow
const STD_OIDC_FLOW = '_oidc'    // OIDC flow
const STD_STAB_FLOW = '_stb'     // Stabilization flow
const STD_OIDP_FLOW = '_oidp'    // OIDC Provider flow

// Configuration
const CFG_FLOW_PREFIX = 'flow'
const FLOW_RECORD = 'flow'
const TARGET_SERVICE = '-'

Usage Examples

Basic Flow Definition

import { flow, makeFlowModel } from '@owlmeans/flow'

const registrationFlow: ShallowFlow = {
  flow: 'user-registration',
  initialStep: 'start',
  steps: {
    start: {
      index: 0,
      step: 'start',
      service: 'auth-service',
      path: '/register/start',
      initial: true,
      transitions: {
        next: { transition: 'next', step: 'credentials' },
        cancel: { transition: 'cancel', step: 'cancelled' }
      }
    },
    credentials: {
      index: 1,
      step: 'credentials',
      service: 'auth-service', 
      path: '/register/credentials',
      transitions: {
        submit: { transition: 'submit', step: 'verify' },
        back: { transition: 'back', step: 'start', reversible: true }
      }
    },
    verify: {
      index: 2,
      step: 'verify',
      service: 'auth-service',
      path: '/register/verify',
      transitions: {
        confirmed: { transition: 'confirmed', step: 'complete' },
        resend: { transition: 'resend', step: 'verify' }
      }
    },
    complete: {
      index: 3,
      step: 'complete',
      service: 'auth-service',
      path: '/register/complete',
      transitions: {}
    }
  }
}

// Add to configuration
const config = flow(baseConfig, registrationFlow)

Flow Execution

// Create flow model
const flowModel = await makeFlowModel('user-registration', flowProvider)

// Target a specific service
flowModel.target('auth-service')

// Set entity context
flowModel.entity('user123')

// Get current step
const currentStep = flowModel.step()
console.log(`Current step: ${currentStep.step}`)

// Get available transitions
const transitions = flowModel.transitions(true) // Only explicit transitions
console.log('Available actions:', transitions.map(t => t.transition))

// Execute transition
const nextState = flowModel.transit('submit', true, 'Success', { 
  username: 'john_doe',
  email: '[email protected]' 
})

// Serialize state for URL or storage
const serializedState = flowModel.serialize()

Flow State Management

// Load from serialized state
const flowModel = await makeFlowModel(serializedState, flowProvider)

// Check if flow completed successfully
const state = flowModel.state()
if (state.ok && state.step === 'complete') {
  console.log('Registration completed successfully')
}

// Handle errors
if (!state.ok && state.message) {
  console.error('Flow error:', state.message)
}

// Access payload data
const payload = flowModel.payload<{username: string, email: string}>()
console.log('User data:', payload)

Cross-Service Flow

const crossServiceFlow: ShallowFlow = {
  flow: 'order-fulfillment',
  initialStep: 'create-order',
  steps: {
    'create-order': {
      index: 0,
      step: 'create-order',
      service: 'order-service',
      transitions: {
        created: { transition: 'created', step: 'process-payment' }
      }
    },
    'process-payment': {
      index: 1,
      step: 'process-payment',
      service: 'payment-service',
      transitions: {
        paid: { transition: 'paid', step: 'ship-order' },
        failed: { transition: 'failed', step: 'payment-failed' }
      }
    },
    'ship-order': {
      index: 2,
      step: 'ship-order',
      service: 'shipping-service',
      transitions: {
        shipped: { transition: 'shipped', step: 'complete' }
      }
    }
  }
}

Configuration Setup

import { configureFlows } from '@owlmeans/flow'

const config = configureFlows(baseConfig, {
  queryParam: 'flow',
  defaultFlow: 'user-registration',
  services: {
    auth: 'auth-service',
    payment: 'payment-service'
  },
  modules: {
    login: 'auth:login',
    register: 'auth:register'
  },
  pathes: {
    home: '/dashboard',
    login: '/auth/login'
  }
})

Flow Provider Implementation

import { FlowProvider } from '@owlmeans/flow'

const flowProvider: FlowProvider = async (flowName: string) => {
  // Load from database, configuration, or static definitions
  const flowRecord = await flowRepository.get(flowName)
  
  return {
    ...flowRecord,
    config: {
      queryParam: 'f',
      services: { auth: 'auth-service' }
    },
    prefabs: {
      start: 'welcome-template',
      complete: 'success-template'
    }
  }
}

Error Handling

import { UnknownFlow, FlowStepError } from '@owlmeans/flow'

try {
  const flowModel = await makeFlowModel('unknown-flow', flowProvider)
} catch (error) {
  if (error instanceof UnknownFlow) {
    console.error('Flow not found')
  } else if (error instanceof FlowStepError) {
    console.error('Step configuration error:', error.message)
  }
}

Advanced Features

Payload Mapping

Configure how data flows between steps:

const step: FlowStep = {
  index: 1,
  step: 'credentials',
  service: 'auth-service',
  payloadMap: {
    username: 0,    // Map to first payload parameter
    email: 1,       // Map to second payload parameter  
    phone: 2        // Map to third payload parameter
  },
  transitions: { /* ... */ }
}

Conditional Transitions

Implement business logic in transitions:

const flowModel = await makeFlowModel(flow, flowProvider)

// Custom transition logic
const canProceed = await validateUserInput(payload)
const nextState = flowModel.transit(
  canProceed ? 'submit' : 'error',
  canProceed,
  canProceed ? 'Validation passed' : 'Please fix errors'
)

URL-Based Flow State

// Extract flow state from URL
const urlParams = new URLSearchParams(window.location.search)
const flowState = urlParams.get('flow')

if (flowState) {
  const flowModel = await makeFlowModel(flowState, flowProvider)
  // Resume flow from URL state
}

// Update URL with current flow state
const currentState = flowModel.serialize()
const newUrl = `${window.location.pathname}?flow=${currentState}`
window.history.pushState({}, '', newUrl)

Integration with OwlMeans Ecosystem

The @owlmeans/flow package integrates with:

  • @owlmeans/config: Configuration management and record storage
  • @owlmeans/error: Resilient error handling system
  • @owlmeans/resource: Flow state persistence and retrieval
  • @owlmeans/i18n: Internationalization for flow content
  • @owlmeans/client-flow: Client-side flow execution
  • @owlmeans/server-flow: Server-side flow management
  • @owlmeans/web-flow: Web-specific flow features

Best Practices

Flow Design

  • Keep steps focused on single responsibilities
  • Design for both forward and backward navigation
  • Use meaningful step and transition names
  • Plan for error scenarios and recovery paths

State Management

  • Minimize payload size for URL serialization
  • Use appropriate TTL for flow state persistence
  • Handle state corruption gracefully
  • Implement proper cleanup for abandoned flows

Security

  • Validate payload data at each step
  • Implement proper authorization for step access
  • Sanitize flow state when exposing in URLs
  • Use secure channels for sensitive flow data

Performance

  • Cache flow definitions for better performance
  • Implement efficient flow provider lookups
  • Use pagination for large step lists
  • Optimize serialization for large payloads

Fixes #32.