Skip to content

Overall Flow

Data Source (non-developers write error messages)
    |
    +-- Google Sheets (tabs = per-language separation)
    +-- Airtable
    +-- Notion
    +-- CSV (local file, per-language file separation)
    +-- XLSX (local file, sheets = per-language separation)
    |
    v
@sanghyuk-2i/huh-cli  --- pull command
    |
    +-- Fetch per data source via Adapter pattern
    +-- Parse with @sanghyuk-2i/huh-core's parseSheetData
    +-- Validate with @sanghyuk-2i/huh-core's validateConfig
    +-- (i18n) Cross-locale validate with @sanghyuk-2i/huh-core's validateLocales
    |
    v
huh.json  or  huh/ directory (build-time artifact)
    |              +-- ko.json, en.json (per-locale)
    |              +-- index.ts (auto-generated barrel)
    v
@sanghyuk-2i/huh-react, @sanghyuk-2i/huh-vue, @sanghyuk-2i/huh-svelte  --- HuhProvider
    |
    +-- Inject JSON data via source prop (single language)
    +-- Inject multi-language data via locales prop (i18n)
    +-- Trigger errors with huh(code, variables) (direct trackId or via errorMap)
    +-- Look up + substitute variables via @sanghyuk-2i/huh-core's resolveError
    |
    v
User-provided custom renderers  --- TOAST / MODAL / PAGE / custom types

Package Dependency Graph

@sanghyuk-2i/huh-react          --depends-->  @sanghyuk-2i/huh-core
@sanghyuk-2i/huh-vue            --depends-->  @sanghyuk-2i/huh-core
@sanghyuk-2i/huh-svelte         --depends-->  @sanghyuk-2i/huh-core
@sanghyuk-2i/huh-cli            --depends-->  @sanghyuk-2i/huh-core
@sanghyuk-2i/huh-plugin-sentry   --depends-->  @sanghyuk-2i/huh-core  (+ @sentry/browser peer dep)
@sanghyuk-2i/huh-plugin-datadog  --depends-->  @sanghyuk-2i/huh-core  (+ @datadog/browser-logs peer dep)

@sanghyuk-2i/huh-core    --  (zero dependencies)
  • core has no external dependencies and can be used anywhere.
  • react depends on core; react/react-dom are peer dependencies.
  • vue depends on core; vue >= 3.3 is a peer dependency.
  • svelte depends on core; svelte >= 5.0 is a peer dependency.
  • cli depends on core and uses commander/googleapis/picocolors/xlsx.
  • plugin-sentry depends on core; @sentry/browser is a peer dependency.
  • plugin-datadog depends on core; @datadog/browser-logs is a peer dependency.

Package Responsibilities

@sanghyuk-2i/huh-core

ModuleResponsibility
schema.tsAll type definitions (ErrorConfig, ErrorEntry, ERROR_TYPES, ACTION_TYPES, HuhPlugin, etc.)
plugin.tsPlugin runner utility (runPluginHook)
parser.tsConverts sheet raw data (2D string array) to ErrorConfig
template.ts placeholder substitution utility
resolver.tsLooks up error by trackId + applies variable substitution
validator.tsErrorConfig validation (errors + warnings)
locale-validator.tsMulti-language cross-locale validation (trackId consistency, type/actionType mismatch)

@sanghyuk-2i/huh-react

ModuleResponsibility
ErrorContentProvider.tsxContext Provider, error state management, renderer invocation
useErrorContent.tshuh/clearError hook
types.tsErrorRenderProps, RendererMap type definitions

@sanghyuk-2i/huh-vue

ModuleResponsibility
ErrorContentProvider.tsprovide/inject-based Provider, error state management, render function renderer invocation
useErrorContent.tsinject-based useHuh composable
types.tsErrorRenderProps, RendererMap (Vue Component) type definitions

@sanghyuk-2i/huh-svelte

ModuleResponsibility
HuhProvider.sveltesetContext-based Provider, $state error state management, dynamic component rendering
useErrorContent.tsgetContext-based useHuh
context.tsSeparated Symbol injection key
types.tsErrorRenderProps, RendererMap (Svelte Component) type definitions

@sanghyuk-2i/huh-cli

ModuleResponsibility
commands/init.tsConfig file template generation, source type definitions
commands/pull.tsFetch data via Adapter, parse, validate, generate JSON file
commands/validate.tsJSON file validation
adapters/types.tsSourceAdapter interface definition
adapters/registry.tsAdapter register/get/clear registry
adapters/google-sheets.tsGoogle Sheets API v4 adapter
adapters/airtable.tsAirtable REST API adapter
adapters/notion.tsNotion API adapter
adapters/csv.tsLocal CSV file adapter (RFC 4180 compatible parser)
adapters/xlsx.tsLocal XLSX file adapter (SheetJS)
adapters/index.tsBarrel -- auto-registers all adapters on import
fetch-sheet.tsGoogle Sheets API v4 data fetch (used by adapter)
fetch-airtable.tsRe-export shim -> adapters/airtable
fetch-notion.tsRe-export shim -> adapters/notion
generate.tsErrorConfig -> JSON file write; in i18n mode, generates per-locale files + index.ts barrel

JSON DSL Schema

ErrorConfig (Record<trackId, ErrorEntry>)
|
+-- trackId: string (unique identifier)
|
+-- ErrorEntry
    +-- type: ErrorType (uppercase. Built-in: 'TOAST' | 'MODAL' | 'PAGE' + custom types)
    +-- message: string (supports {{variable}} templates)
    +-- title?: string
    +-- image?: string
    +-- severity?: Severity (uppercase. Built-in: 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL' + custom severity)
    +-- action?: ErrorAction
        +-- label: string
        +-- type: ActionType (uppercase. Built-in: 'REDIRECT' | 'RETRY' | 'BACK' | 'DISMISS' + custom actions)
        +-- target?: string (required for REDIRECT)

Type Extensibility

ErrorType and ActionType are open-ended string types:

  • Built-in types: ERROR_TYPES (TOAST, MODAL, PAGE), ACTION_TYPES (REDIRECT, RETRY, BACK, DISMISS), SEVERITY_LEVELS (INFO, WARNING, ERROR, CRITICAL)
  • Custom types (e.g., BANNER, SNACKBAR, OPEN_CHAT) can be freely added from data sources
  • The parser automatically converts to uppercase (lowercase input is accepted)
  • Custom types work automatically when you register the corresponding renderer in the framework's RendererMap
  • Custom action types are handled via the HuhProvider's onCustomAction callback

Rendering Strategy

The Provider does not supply default renderers. This is intentional:

  • Since every project has a different design system, providing default UI would still require customization.
  • Users implement renderers for each error type they use via RendererMap. In addition to the built-in types (TOAST, MODAL, PAGE), renderers for custom types can also be added.
  • Renderers receive ErrorRenderProps, with onAction and onDismiss callbacks automatically generated.

Action Handling Flow

User clicks action button -> onAction() called
    |
    +-- REDIRECT -> router.push(target) if router provided, else window.location.href = target
    +-- BACK     -> router.back() if router provided, else window.history.back()
    +-- RETRY    -> clearError() + onRetry callback
    +-- DISMISS  -> clearError()
    +-- Custom   -> clearError() + onCustomAction callback

Plugin System

Plugins provide extension points for error monitoring, analytics, and custom integrations. Each framework Provider accepts a plugins prop.

Plugin Lifecycle

huh(code, variables)
    |
    +-- resolveError -> set active error
    +-- runPluginHook(plugins, 'onError', resolved, context)  <-- Plugin hook
    |
    v
User clicks action button -> onAction()
    |
    +-- runPluginHook(plugins, 'onAction', error, action)     <-- Plugin hook
    +-- Execute action (REDIRECT / RETRY / DISMISS / etc.)

Error Isolation

Plugin errors are caught and logged as warnings. A failing plugin never breaks the error rendering flow.

Official Plugins

PackageDescription
@sanghyuk-2i/huh-plugin-sentrySentry integration — captureMessage on error, addBreadcrumb on action
@sanghyuk-2i/huh-plugin-datadogDatadog integration — datadogLogs.logger on error, info-level action logging

Build Configuration

The monorepo is managed with the following tools:

ToolRole
pnpm workspacePackage manager + workspaces
turborepoBuild/test pipeline (caching, dependency ordering)
tsupTypeScript bundling (CJS + ESM + IIFE + d.ts)
vitestTest runner

Build Outputs

FileFormatPurpose
dist/index.jsCJSrequire()
dist/index.mjsESMimport
dist/index.global.jsIIFE (minified)CDN, <script>
dist/index.d.tsTypeScript declarationsType support

Build Order

Turborepo analyzes dependency relationships and determines the order automatically:

1. @sanghyuk-2i/huh-core (no dependencies, built first)
2. @sanghyuk-2i/huh-react + @sanghyuk-2i/huh-vue + @sanghyuk-2i/huh-svelte + @sanghyuk-2i/huh-cli (built in parallel after core)

Directory Structure

/
+-- package.json               # Root (monorepo scripts)
+-- pnpm-workspace.yaml
+-- turbo.json
+-- tsconfig.base.json
+-- vitest.workspace.ts
+-- docs/                      # Documentation
|   +-- getting-started.md
|   +-- google-sheet-guide.md
|   +-- airtable-guide.md
|   +-- notion-guide.md
|   +-- api-core.md
|   +-- api-react.md
|   +-- api-cli.md
|   +-- architecture.md
+-- packages/
    +-- core/
    |   +-- package.json
    |   +-- tsconfig.json
    |   +-- tsup.config.ts
    |   +-- src/
    |       +-- index.ts
    |       +-- schema.ts
    |       +-- parser.ts
    |       +-- resolver.ts
    |       +-- template.ts
    |       +-- validator.ts
    |       +-- locale-validator.ts
    |       +-- __tests__/
    +-- react/
    |   +-- package.json
    |   +-- tsup.config.ts
    |   +-- src/
    |       +-- index.ts
    |       +-- ErrorContentProvider.tsx
    |       +-- useErrorContent.ts
    |       +-- types.ts
    |       +-- __tests__/
    +-- vue/
    |   +-- package.json
    |   +-- tsup.config.ts
    |   +-- src/
    |       +-- index.ts
    |       +-- ErrorContentProvider.ts
    |       +-- useErrorContent.ts
    |       +-- types.ts
    |       +-- __tests__/
    +-- svelte/
    |   +-- package.json
    |   +-- svelte.config.js
    |   +-- src/
    |       +-- index.ts
    |       +-- HuhProvider.svelte
    |       +-- useErrorContent.ts
    |       +-- context.ts
    |       +-- types.ts
    |       +-- __tests__/
    +-- cli/
        +-- package.json
        +-- tsconfig.json
        +-- tsup.config.ts
        +-- src/
            +-- index.ts
            +-- fetch-sheet.ts
            +-- fetch-airtable.ts      # re-export -> adapters/airtable
            +-- fetch-notion.ts        # re-export -> adapters/notion
            +-- generate.ts
            +-- adapters/
            |   +-- index.ts           # barrel (auto-registers all adapters)
            |   +-- types.ts           # SourceAdapter interface
            |   +-- registry.ts        # register/get/clear
            |   +-- google-sheets.ts
            |   +-- airtable.ts
            |   +-- notion.ts
            |   +-- csv.ts
            |   +-- xlsx.ts
            +-- commands/
            |   +-- init.ts
            |   +-- pull.ts
            |   +-- validate.ts
            +-- __tests__/

Released under the MIT License.