Releases: lowdefy/lowdefy
v4.7.1
Highlights
-
Dev server: Icons referenced in page blocks are now dynamically discovered and served without requiring a rebuild or server restart.
-
Date picker e2e testing: All date picker blocks now support
do.select()for calendar interaction anddo.fill()for typing dates directly. DateTimeSelector also supports time selection. -
Operators: Fixed
_functioncallback mutation inevaluateOperatorsthat was causing_build.array.mapand similar operators to produce duplicate results on repeated invocations. -
E2E testing: Environment variable
LOWDEFY_E2E_SECRET_*can now overrideLOWDEFY_SECRET_*values, allowing test infrastructure (e.g., MongoMemoryServer) to coexist with secret managers. -
E2E navigation: Page navigation now waits for
domcontentloadedinstead of the fullloadevent, preventing hangs on pages with WebSocket connections or slow resources. -
E2E utils: Renamed
MDB_E2E_URItoLOWDEFY_E2E_MONGODB_URIin scaffold templates. Init script no longer auto-installs dependencies — they're added topackage.jsonand the user is prompted to install. -
Build performance: Sibling refs are now resolved in parallel to interleave CPU and I/O operations.
Fixes & Improvements
-
fix(build): Dev server dynamically loads icons discovered during JIT page builds. (
@lowdefy/build,@lowdefy/server-dev)Icons referenced only inside page blocks (e.g.,
icon: FiApertureon a Button) were not available in the dev server's static bundle, causing a fallback icon to render. The JIT page builder now detects missing icons when a page is compiled, extracts their SVG data from react-icons, and serves it via a dynamic API endpoint. The client fetches and merges these icons at runtime without triggering a Next.js rebuild or server restart. -
Resolve sibling refs in parallel using Promise.all to interleave CPU and I/O during build. (
@lowdefy/build) -
feat(blocks-antd): Add do.select() and do.fill() to date picker e2e helpers. (
@lowdefy/blocks-antd)All five date picker e2e helpers (DateSelector, DateTimeSelector,
DateRangeSelector, MonthSelector, WeekSelector) now support
do.select()for calendar UI interaction anddo.fill()for
typing dates directly. DateTimeSelector also supports time
selection via the time panel. -
Fix
_functioncallback template being mutated in-place byevaluateOperators, causing_build.array.mapand similar operators to produce duplicate results from repeated callback invocations. (@lowdefy/operators-js) -
feat(server-e2e): Add LOWDEFYE2E_SECRET* override support. (
@lowdefy/server-e2e)Secrets can now be overridden in e2e tests using
LOWDEFY_E2E_SECRET_*environment variables. These take precedence overLOWDEFY_SECRET_*values, allowing test infrastructure (e.g. MongoMemoryServer) to coexist with secret managers injected viacommandPrefix. -
fix(e2e-utils): Use domcontentloaded for page navigation. (
@lowdefy/e2e-utils)Page navigation now uses
waitUntil: 'domcontentloaded'instead of the defaultloadevent. This prevents hangs on pages with WebSocket connections or slow-loading resources, since the Lowdefy client readiness check is already a stronger signal. -
refactor(e2e-utils): Update scaffold env vars and simplify init. (
@lowdefy/e2e-utils)Renamed
MDB_E2E_URItoLOWDEFY_E2E_MONGODB_URIin scaffold templates to align with the newLOWDEFY_E2E_SECRET_*override pattern. The init script no longer runs install automatically — dependencies are added topackage.jsonand the user is prompted to install.
v4.7.0
Highlights
- Build Performance: Single-pass async walker replaces multi-pass JSON serialization for ref resolution, eliminating 5+
serializer.copycalls per ref - Build Errors: Collect and report all ref errors at once instead of stopping on the first failure — faster fix-rebuild cycles when multiple config files have issues
- Inline Pages: Fixed inline page content being stripped during JIT builds with no recovery path
- Template Errors: YAML errors in
.yaml.njktemplates now show "Nunjucks template produced invalid YAML" instead of misleading line numbers - CLI: Build now properly exits with
process.exit(1)on errors instead of hanging with a spinner - CLI Start: Fixed port availability check when no
--portflag is passed (now defaults to port 3000) - Build Logs: Removed spurious
print: warnfields from build logger output - E2E Testing: New
ldf.api()assertions for API endpoint testing —expect.toFinish(),expect.toHaveResponse(),expect.toHavePayload(),response(),state() - E2E Developer Experience: New scaffold scripts (
e2e:headed,e2e:server),SLOW_MOenv var support, and fixed template defaults (appDir, health check, fixtures) - E2E Block IDs: Dotted block IDs (e.g.,
form.field.name) now work correctly in CSS selectors with newescapeId()utility - Helpers: Fixed
makeReplacermutating object marker enumerability, preventing internal markers from leaking to plugin components
What's New
feat: Single-pass async walker for ref resolution
Packages: @lowdefy/build, @lowdefy/operators, @lowdefy/helpers
Single-Pass Walker (@lowdefy/build)
- New
walkermodule replaces the multi-pass JSON round-trip architecture inbuildRefswith a single async tree walk - Resolves
_refmarkers, evaluates_build.*operators, and tags~rprovenance in one pass instead of 5+serializer.copycalls per ref - Wired into both
buildRefs(production) andbuildPageJit(dev server) - Added
isPageContentPathfor semantic shallow build matching, replacing brittle path-index checks - Deleted redundant code replaced by walker:
getRefsFromFile,populateRefs,createRefReviver, and theevaluateStaticOperatorswrapper
In-Place Operator Evaluation (@lowdefy/operators)
- New
evaluateOperatorsfunction walks a tree in-place and evaluates operator nodes, avoiding JSON serialization round-trips - Used by the walker module to evaluate
_build.*operators inline during ref resolution
Serializer Fix (@lowdefy/helpers)
- Added
skipMarkersoption toserializer.serializeToStringto exclude internal markers (~k,~r,~l,~arr) from serialized output
feat(e2e-utils): Add ldf.api() assertions for API endpoint testing
Packages: @lowdefy/e2e-utils
- New
api.jscore module withgetApiState,getApiResponse,expectApifunctions - Reads from
window.lowdefy.apiResponses[endpointId][0](mirrors request pattern) ldf.api(endpointId).expect.toFinish()— wait for API call completionldf.api(endpointId).expect.toHaveResponse(response)— assert responseldf.api(endpointId).expect.toHavePayload(payload)— assert sent payloadldf.api(endpointId).response()— get raw response valueldf.api(endpointId).state()— get full API state objectldf.mock.api()now captures payloads for assertionldf.mock.getCapturedApi(endpointId)— retrieve captured API data
Fixes & Improvements
-
fix(build): Report all ref errors at once instead of stopping on the first one. (
@lowdefy/build)When multiple referenced files have errors (missing files, YAML parse errors, invalid refs), the build now collects and reports all errors at once instead of stopping on the first failure. This reduces the fix-rebuild-fix cycle when multiple config files have issues.
-
fix(build): Preserve inline page content in JIT builds (
@lowdefy/build,lowdefy,@lowdefy/docs)Pages declared inline in
lowdefy.yaml(not via_ref) had their content stripped during shallow builds with no way to recover at JIT time, resulting in empty page shells. Detect inline pages by checking refId matches root ref with no sourceRef, and skip stripping. Set refId to null for inline pages increatePageRegistrysobuildPageJitreads the pre-built artifact instead of attempting JIT resolution. -
fix(build): Improve error message for YAML errors in njk templates (
@lowdefy/build)When a .yaml.njk nunjucks template produces invalid YAML, the error now says "Nunjucks template produced invalid YAML" instead of showing a misleading line number from the generated output.
-
fix(cli): Exit process and stop spinner on build errors. (
lowdefy)The CLI error handler logged errors but never called
process.exit(1), so the process continued running with a spinning indicator after a build failure. Addedprocess.exit(1)torunCommandafter error handling, and added{ spin: 'fail' }to stop the spinner inrunLowdefyBuild,runNextBuild, andinstallServercatch blocks. -
fix(cli): Fix port availability check for start command (
lowdefy,@lowdefy/server-dev)The CLI's
checkPortAvailablewas called withundefinedport when no--portflag was passed, causingnet.listen(undefined)to bind a random port instead of checking port 3000. Added defaultport: 3000ingetOptions. Removed redundantcheckPortAvailablefrom server-dev manager since the CLI now catches port conflicts before the server starts. -
fix(e2e-utils): Escape dotted block IDs in e2e CSS selectors. (
@lowdefy/blocks-antd,@lowdefy/blocks-basic,@lowdefy/e2e-utils)Block IDs containing dots (e.g.,
form.field.name) now work correctly in e2e test locators. AddedescapeId()utility to@lowdefy/e2e-utilsthat escapes CSS special characters, and updated all block e2e helpers and test specs to use it. -
fix(server): Remove unused print mixin from build logger (
@lowdefy/server)Removed the pino
mixinthat added aprintfield to every build log entry. This field was a leftover from a previous CLI display system and caused spuriousprint: warnlines in build output. -
feat(e2e-utils): Improved e2e scaffold with new scripts and SLOW_MO support. (
@lowdefy/e2e-utils)New scaffold scripts:
e2e:headed— Run tests with a visible browser in slow motion (SLOW_MO=500,--workers=1)e2e:server— Start the e2e server once, then rerun tests without rebuilding
SLOW_MO env var:
createConfignow reads theSLOW_MOenvironment variable and passes it to Playwright'slaunchOptions.slowMo- No manual config extension needed — just set
SLOW_MO=500in your npm script
Scaffold template fixes:
- Fixed
appDirfrom'../'to'./'—path.resolveresolves relative to cwd, not the config file - Fixed
fixtures.jstemplate to usemdbFixtures(plural) from/fixturessubpath withmergeTests - Simplified
example.spec.jsto use/api/auth/sessionhealth check — works on auth-protected apps - Fixed README template with correct
appDirvalues, "Faster Test Runs" section, and "Common Patterns" section
-
fix(helpers): Prevent makeReplacer from mutating original object marker enumerability. (
@lowdefy/helpers)makeReplacer used Object.defineProperty to make ~k, ~r, ~l enumerable for JSON.stringify, but operated on the original object reference instead of a copy. This permanently mutated the original, causing internal markers to leak to plugin components via Object.entries/Object.keys.
v4.6.0
Highlights
Looking at the release notes file and the changelog entries you've provided, here are the developer-friendly bullet points organized by theme:
Error Handling & Debugging
- Config-aware error tracing shows exact YAML file:line locations with clickable VSCode links in terminal and browser
- Unified error system in
@lowdefy/errorspackage with standardized TC39 constructor signatures (new MyError(message, { cause, ...options })) - Build-time validation provides "Did you mean?" suggestions for typos and catches NEXTAUTH_SECRET configuration issues
- Plugin errors simplified — operators, actions, and connections throw plain messages; interface layer adds context (received value, location)
- Sentry integration (zero-config: just set
SENTRY_DSN) captures errors on client and server with Lowdefy context (pageId, blockId, config location) - New
UserErrorclass for expected user-facing errors (validation, intentional throws) — logs to browser console only, never to server terminal
Build & Performance
- JIT page building for dev server — pages build on-demand when requested instead of all at once, speeding up development
- Shallow
_refresolution leaves on-demand markers for faster initial builds with file dependency tracking for targeted rebuilds - New
~ignoreBuildChecksproperty suppresses specific build validation errors/warnings, with cascade support to suppress entire page subtrees - Build now collects all errors before stopping instead of failing on first error, showing developers all issues at once
- Schema validation errors stop the build immediately to prevent cascading failures
Developer Experience
- New
@lowdefy/loggerpackage with environment-specific variants (Node, CLI, browser) and standardized logging interface - Dev server now accepts
LOWDEFY_DEV_USERenv var orauth.dev.mockUserconfig for mock user support in e2e testing - Port-in-use check displays clear error message before starting server
- Build-time validation no longer warns about
_statereferences set by SetState actions
Testing
- New
@lowdefy/e2e-utilspackage for Playwright e2e testing with locator-first API (ldf.block('id').do.*), request mocking, and state assertions - Comprehensive e2e tests for blocks-antd (~700 tests covering 63 blocks) and blocks-basic (~40 tests)
npx @lowdefy/e2e-utilsscaffold command sets up e2e testing in your project
Bug Fixes
- Fixed env vars not being passed to Next.js build subprocess (
NEXT_TELEMETRY_DISABLEDwas being ignored) - Array line number metadata (
~l) now preserved throughserializer.copy()— schema validation errors show correct line numbers - Error cause chains properly preserved across plugin boundaries and CLI
- Input block onChange events now pass the input value
What's New
feat: Config-aware error tracing and Sentry integration
Packages: @lowdefy/api, @lowdefy/build, lowdefy, @lowdefy/client, @lowdefy/engine, @lowdefy/operators, @lowdefy/actions-core, @lowdefy/blocks-basic, @lowdefy/connection-axios-http, @lowdefy/connection-knex, @lowdefy/connection-redis, @lowdefy/connection-sendgrid, @lowdefy/operators-change-case, @lowdefy/operators-diff, @lowdefy/operators-js, @lowdefy/operators-jsonata, @lowdefy/operators-moment, @lowdefy/operators-mql, @lowdefy/operators-nunjucks, @lowdefy/operators-uuid, @lowdefy/operators-yaml, @lowdefy/server, @lowdefy/server, @lowdefy/server-dev, @lowdefy/server-dev, @lowdefy/block-utils, @lowdefy/errors, @lowdefy/helpers, @lowdefy/node-utils
Config-Aware Error Tracing (#1940)
- Errors now trace back to exact YAML config locations with file:line
- Clickable VSCode links in terminal and browser
- Build-time validation catches typos with "Did you mean?" suggestions
- Service vs Config error classification
Plugin Error Refactoring
- Operators throw simple error messages without formatting
- Parsers (WebParser, ServerParser, BuildParser) format errors with received value and location
- Removed redundant "Operator Error:" prefix from error messages
- Consistent error format: "{message} Received: {params} at {location}."
- Actions and connections also simplified: removed inline
receivedfrom error messages (interface layer adds it) - Connection plugins (axios-http, knex, redis, sendgrid) no longer expose raw response data in errors
Error Class Hierarchy
- Unified error system in
@lowdefy/errorswith all error classes@lowdefy/errors/build- Build-time classes with sync location resolution
- Error classes:
LowdefyError,ConfigError,ConfigWarning,PluginError,ServiceError ConfigWarningsupportsprodErrorflag to throw in production buildsServiceError.isServiceError()detects network/timeout/5xx errors~ignoreBuildCheckscascades through descendants to suppress warnings/errors
Build Error Collection
- Errors collected in
context.errors[]instead of throwing immediately tryBuildStep()wrapper catches and collects errors from build steps- All errors logged together before summary message for proper ordering
Sentry Integration (#1945)
- Zero-config Sentry support - just set SENTRY_DSN
- Client and server error capture with Lowdefy context (pageId, blockId, config location)
- Configurable sampling rates, session replay, user feedback
- Graceful no-op when DSN not set
feat(server-dev): Add mock user support for e2e testing
Packages: @lowdefy/api, @lowdefy/build, @lowdefy/server-dev
Set LOWDEFY_DEV_USER env var or auth.dev.mockUser in config to bypass login in dev server.
Collect all build errors before stopping
Packages: @lowdefy/build, @lowdefy/build, @lowdefy/helpers
feat: JIT page building for dev server
Packages: @lowdefy/build, @lowdefy/operators-js, @lowdefy/server, @lowdefy/server-dev
Shallow Refs and JIT Build (@lowdefy/build)
- Shallow
_refresolution stops at configured JSON paths, leaving~shallowmarkers for on-demand resolution shallowBuildproduces a page registry with dependency tracking instead of fully built pagesbuildPageJitfully resolves a single page on demand using the shallow build output- File dependency map tracks which config files affect which pages for targeted rebuilds
- Build package reorganized:
jit/folder for dev-server-only files,full/folder for production-only files
JIT Page Building (@lowdefy/server-dev)
- Pages are built on-demand when requested instead of all at once during initial build
- Page cache with file-watcher invalidation for fast rebuilds
/api/page/[pageId]endpoint triggers JIT build if page not cached/api/js/[env]endpoint serves operator JS maps- Build error page component displays errors inline in the browser
Operator JS Hash Check (@lowdefy/operators-js)
- Added hash validation for jsMap to detect stale operator definitions
Add build-time validation for NEXTAUTH_SECRET environment variable when auth providers are configured
Packages: @lowdefy/build
feat(build): Add ~ignoreBuildChecks property to suppress build validation
Packages: @lowdefy/build, @lowdefy/docs
Build Validation Suppression (#1949, #1963)
- New
~ignoreBuildChecksproperty suppresses build-time validation errors and warnings - Supports
true(suppress all) or array of specific check slugs (e.g.,['state-refs', 'types']) - Cascades to all descendant config objects - set on a page to suppress for all child blocks
- Silent suppression - no log output when validation is skipped (visible with
--log-level debug)
Renamed: Previously
~ignoreBuildCheck(singular) - using the old name throws a helpful migration error.
Available Check Slugs:
state-refs,payload-refs,step-refs- Reference validation warningslink-refs,request-refs,connection-refs- Action reference validationtypes- All type validation (blocks, operators, actions, etc.)schema- JSON schema validation errors
Use Cases:
- Dynamic state references created at runtime by custom blocks
- Multi-app monorepos with conditional configurations
- Work-in-progress features during development
- Plugin development with custom types not yet registered
Example:
# Suppress all checks for this page and descendants
pages:
- id: dynamic-page
type: Box
~ignoreBuildChecks: true
blocks:
- id: block1
type: TextInput
properties:
value:
_state: dynamicField # No warning
# Suppress only specific checks
blocks:
- id: custom_block
type: CustomBlock
~ignoreBuildChecks:
- state-refs
- types
properties:
onClick:
_state: dynamicState # No warning (state-refs suppressed)Add e2e testing package for Lowdefy apps
Packages: lowdefy, @lowdefy/client, @lowdefy/blocks-antd, @lowdefy/block-dev-e2e, @lowdefy/e2e-utils
@lowdefy/e2e-utils (new package)
- Locator-first API via
ldfPlaywright fixture:ldf.block('id').do.*,ldf.block('id').expect.* - Request mocking with static YAML files (
mocks.yaml) and inline per-test overrides - Request assertion API:
ldf.request('id').expect.toFinish(),.toHaveResponse(),.toHavePayload() - State and URL assertions:
ldf.state('key').expect.toBe(),ldf.url().expect.toBe() - Manifest generation from build artifacts for block type resolution and helper loading
createConfig()andcreateMultiAppConfig()for Playwright config with automatic build/server management- Scaffold command (`npx @lowdefy/e...
v4.5.2
v4.5.1
v4.5.0
Minor Changes
- 16084c1: Adds Lowdefy APIs. Lowdefy APIs allow you to create custom server-side API endpoints within your Lowdefy application. See https://docs.lowdefy.com/lowdefy-api for more info.
- abc90f3: Change to Apache 2.0 license for all packages. All license checks and restrictions have been removed.
- 09ae496: Add JSONata operator.
- d6c58fe: Add minItems property to ControlledList block.
- b3a2e66: Add afterOpenChange and afterClose events to Drawer block.
- d9512d9: Refactor build to create individual block instances.
- d9512d9: Add hybrid block type to extend block functionality.
- 4f610de: Allow custom icon titles and format the icon name if a title is not specified.
Patch Changes
- fe3676c: Add missing events to S3Upload block schemas.