Skip to content

Releases: diphyx/harlemify

5.4.2

25 Feb 17:10
7852aab

Choose a tag to compare

Fix

  • Resolve ViewDefinition union contravarianceview.merge() return types are now correctly assignable to the ViewDefinition union by using any for contravariant type parameters, matching the existing pattern in ModelDefinition.

API

  • Export isError and toError from runtime — Error utility functions are now part of the public API via @diphyx/harlemify/runtime.

5.4.1

15 Feb 15:25

Choose a tag to compare

Refactor

  • Remove proxy option from useStoreViewdata is now always a standard Vue ComputedRef. The proxy, UseStoreViewProxy, UseStoreViewComputed, and UseStoreViewData types have been removed. Use data.value in script and data directly in templates.

Docs

  • Fix .value usage inside Vue <template> blocks across all documentation
  • Fix import paths to use @diphyx/harlemify/runtime for runtime exports
  • Correct log messages in logging docs to match source code
  • Add SSR documentation page
  • Rewrite useStoreView docs to reflect simplified API
  • Update README with feature list and corrected examples

5.4.0

15 Feb 06:40

Choose a tag to compare

Features

  • Compose layer — New useStoreCompose composable for orchestrating actions, models, and views together
  • Lazy store — New lazy option for createStore to defer initialization until first use
  • Function default — Support sync function default in model definitions for dynamic initial values
  • Pre/post hooks & silent mode — Model commits now support pre / post hooks and silent option to skip hooks
  • Pure reset — New pure option for model reset to restore shape defaults without side effects
  • Custom SSR — Replace @harlem/plugin-ssr with built-in SSR implementation and automatic state hydration

Fixes

  • Restore @nuxt/kit to dependencies for Nuxt 3 compatibility
  • Allow synchronous callbacks in handler()
  • Narrow Nuxt compatibility range and add setup logging
  • Enforce function-only default in model definitions

Playground

  • Redesign playground UI with improved layout, components, and richer visual styling
  • Add dashboard page with compose layer demo
  • Add composables page showcasing useStoreAction, useStoreModel, useStoreView
  • Add meta model with function default demo

Tests

  • Update e2e selectors and assertions to match redesigned playground

Docs

  • Reorganize and improve documentation content
  • Revamp README with before/after comparison and badges

5.3.0

10 Feb 18:41

Choose a tag to compare

Features

  • Many record model — New many model type for keyed collections, enabling record-based state management with identifier-driven CRUD operations
  • Generic handler payload — Handler factory now supports a generic payload type for stronger type inference

Fixes

  • Preserve API action return type — API action calls now correctly preserve the return type instead of erasing it
  • useStoreAction type narrowingexecute() options type is now narrowed based on the action kind (API vs handler)
  • Type-safe model.remove()model.remove() now uses identifier generic and field matching for compile-time safety

Playground

  • Add teams page demo with keyed collection CRUD (create, update, delete)
  • Add teams API endpoints and server utils

Tests

  • Add many record model test suites
  • Add e2e tests for teams page
  • Update action, store, and view tests

Docs

  • Add many record model documentation with examples
  • Update action documentation

Chore

  • Bump version to 5.3.0

5.2.0

10 Feb 07:03

Choose a tag to compare

Features

  • Handler payload — Handler actions now receive payload in the callback context ({ model, view, payload }), supporting both call-time and definition-level default values (#18)
  • wrapBaseDefinition utility — Shared utility for adding key/setKey to layer definitions, used across model, view, and action layers

Fixes

  • Store config type inferenceStoreConfig.action now preserves concrete action types instead of erasing them to Record<string, ActionDefinition>
  • useStoreAction constraint — Changed from ActionCall to ActionCall<any> to accept handler actions with non-void return types

Refactor

  • Layers — Model, view, and action layers refactored to use shared wrapBaseDefinition
  • Section comments — Added section comments to utils/model.ts and utils/view.ts for consistency

Playground

  • Demo handler payload with toggle (call-time) and rename (definition default) actions

Tests

  • Add handler payload, context, concurrent, and wrapBaseDefinition test suites
  • Add e2e tests for handler payload composable features

Docs

  • Add handler payload documentation with call-time and definition-level examples
  • Add "When to Use API vs Handler" decision table
  • Consolidate duplicated content, add cross-references between concurrency and cancellation

Chore

  • Update .npmignore to cover all non-essential files
  • Bump version to 5.2.0

Closes #18

5.1.0

09 Feb 19:03

Choose a tag to compare

What's Changed

Features

  • composables: add useStoreAction, useStoreModel, useStoreView composables
  • core: add toReactiveProxy utility and timing helpers
  • core: export composables and types from public API
  • playground: add composables demo with todo store

Refactor

  • action: remove action.data from core

Tests

  • Add composable tests and update docs

Chore

  • Remove global $fetch type declaration
  • Bump version to 5.1.0

5.0.0

09 Feb 09:06

Choose a tag to compare

What's Changed

Features

  • action: add alias mapping and explicit json response type
  • model: add aliases method to ModelCall
  • shape: add alias meta and resolve helpers, add defaults() method and createShape utility
  • view: add clone option with ViewClone enum
  • playground: add contacts demo with alias mapping, clone view demos, shape.defaults() for form initialization

Refactor

  • utils: extract base helpers and error classes

Tests

  • e2e: add contacts, clone view, and shape.defaults() coverage
  • test: add alias, error import, clone option, and defaults test suites

Docs

  • Add alias documentation and remove api reference
  • Add clone option and ViewClone types documentation
  • Add defaults() documentation and ShapeCall types
  • Update version badge to 5.0.0

Chore

  • Bump version to 5.0.0

4.0.1

07 Feb 19:52

Choose a tag to compare

Features

  • AUTO Symbol — New exported AUTO symbol for explicit auto-commit value resolution. Use it instead of undefined when passing commit options to signal that the action result should be used as the commit value:
import { AUTO } from "@diphyx/harlemify";

.commit("list", ActionManyMode.ADD, AUTO, { unique: true })
.commit("list", ActionManyMode.ADD, AUTO, { prepend: true })
.commit("list", ActionManyMode.PATCH, AUTO, { by: "email" })

Bug Fixes

  • Fix factory argument order in test files (action.test.ts, view.test.ts)

Documentation

  • Document AUTO symbol usage in action, types, collection, and nested store pattern docs

4.0.0

07 Feb 19:22

Choose a tag to compare

Features

  • Factory-Driven Store API - New createStore() with model(), view(), and action() factory callbacks replacing the flat action-based config
  • Shape Layer - New shape() factory for Zod schema definitions with ShapeInfer type helper
  • Model Layer - Define state slots with one() (singleton) and many() (collection) factories
  • View Layer - Readonly computed queries with from() and merge() factories
  • Action Layer - State mutations via api(), handle(), and commit() factories
  • Per-Store Debug Logging - Built-in debug logging via consola for each store
  • Improved Type Safety - Enhanced type-safety across core types, layers, and utils

Breaking Changes

  • Store Definition Changed: createStore() now uses factory callbacks (model, view, action) instead of flat action config
  • Schema → Shape: Schema concept replaced with shape() factory
  • useStoreAlias Removed: Replaced with new composable pattern
  • Utility Files Restructured: Internal utils reorganized into layers (layers/, types/, utils/)
  • Runtime Config: Config passed through factories instead of direct imports

Migration

// Before (v3.x) - Flat action config
import { createStore } from "@diphyx/harlemify";

export const taskStore = createStore("task", TaskSchema, {
    list: { method: "GET", url: "/tasks/" },
    create: { method: "POST", url: "/tasks/" },
});

// After (v4.x) - Factory-driven API
import { createStore, shape } from "@diphyx/harlemify";

const taskShape = shape({
    id: z.number().meta({ identifier: true }),
    title: z.string(),
});

export const taskStore = createStore({
    name: "task",
    model({ one, many }) {
        return {
            selected: one(taskShape),
            list: many(taskShape),
        };
    },
    view({ from }) {
        return {
            selectedName: from("selected", (task) => task?.name),
        };
    },
    action({ api }) {
        return {
            list: api("GET", "/tasks/"),
            create: api("POST", "/tasks/"),
        };
    },
});

Architecture

New layered architecture with clear separation of concerns:

Layer Purpose Factories
Shape Schema definition shape()
Model State slots one(), many()
View Readonly queries from(), merge()
Action State changes api(), handle(), commit()

Documentation

Full documentation: https://diphyx.github.io/harlemify/

3.0.0

03 Feb 22:26

Choose a tag to compare

Features

  • Function-Based Monitor API - Access monitors as functions (listIsPending()) instead of refs (listIsPending.value)
  • Unit-to-Units Sync on Edit - Automatically sync unit changes to units array when editing
  • Free-Form Action Names - Replace fixed Endpoint enum with custom action names for flexible API patterns
  • Sub-Resource Schemas - Define different schemas per action for sub-resources
  • Memory Behavior Control - Configure how actions affect store memory (set, add, edit, drop, none)

Breaking Changes

  • Monitor API Changed: Monitors are now functions instead of refs
  • Endpoint Enum Removed: Use free-form action names instead of fixed Endpoint enum
  • Store Definition Changed: New action-based configuration structure

Migration

// Before (v2.x) - Monitors as refs
const { listIsPending } = useStoreAlias(taskStore);
if (listIsPending.value) { ... }

// After (v3.x) - Monitors as functions
const { listIsPending } = useStoreAlias(taskStore);
if (listIsPending()) { ... }
// Before (v2.x) - Fixed endpoints
import { Endpoint } from '@diphyx/harlemify/runtime';

export const taskStore = createStore("task", TaskSchema, {
    [Endpoint.GET_UNITS]: { url: "/tasks/" },
    [Endpoint.POST_UNIT]: { url: "/tasks/" },
});

// After (v3.x) - Free-form action names
export const taskStore = createStore("task", TaskSchema, {
    list: { method: "GET", url: "/tasks/" },
    create: { method: "POST", url: "/tasks/" },
    start: { method: "PUT", url: "/tasks/start/" },
    pause: { method: "PUT", url: "/tasks/pause/" },
});

Performance

  • Schema memoization and Set-based action lookups
  • Optimized bulk edit with temp index map for O(1) lookups
  • Module-level Set constants in pluralize utility
  • Simplified cache implementation

Documentation

Full documentation: https://diphyx.github.io/harlemify/

Closes #8