Changes
The bundled API contract (spec.json and the generated api.gen.d.ts) now
covers the full served surface, adding typed paths for service accounts,
invitations, billing, deployments and their sub-resources, custom domains,
entitlements, LLM settings, chat sessions, MCP tokens, runners, and the package
catalog. No runtime behavior change; clients gain accurate types for these
endpoints.
Batched destination delivery now reports failures. A batch push that fails
(including BigQuery row errors) is routed to the dead-letter buffer and counted
as failed instead of being silently dropped, and graceful shutdown waits for
in-flight batches to finish. Also fixes a shutdown timer that could delay
process exit, and makes a zero millisecond batch wait (batch: 0) correctly
enable batching.
The BigQuery destination now creates the timing column as FLOAT64 instead of
INT64. Event timing carries sub-second decimal precision, which was previously
truncated to whole numbers on write. Existing tables keep their column type;
alter it to FLOAT64 to preserve precision going forward.
The single-instance guard is now scoped to the window instead of the module, so
loading the tag more than once on the same page is inert rather than
re-initializing. A second load no longer re-binds DOM triggers, re-adopts the
event layer, or surfaces an error to the host page.
walkeros run now accepts a .tar.gz/.tgz flow archive (URL or local file):
it extracts the bundle and its node_modules/ and runs it, so server flows with
external step packages resolve them at runtime. walkeros bundle -o flow.tar.gz
packs a server bundle directory into that archive. Web single-file bundles do
not support archive output.
Browser flow bundles are now emitted as an IIFE so all internal code stays
inside a private scope. Previously the bundled helper functions could leak onto
the global window object and collide with other scripts on the page, such as
Google Analytics or a consent manager. Server bundles are unchanged and still
emit ESM.
CodeBox now memoizes its toolbar and tabs so a validation-marker update repaints
only the error and warning badges instead of re-rendering the whole editor. This
removes the visible editor flicker when content or markers change rapidly.
Lifecycle dispatch now fails closed when called with a non-collector argument.
If an internal function is ever reached by foreign code (for example a global
name collision), it returns quietly instead of throwing, so it can no longer
break the surrounding page.
Promote chain, route shape, and reference scanner helpers to the public surface
so app and tooling can resolve transformer chains, probe route shapes, and
discover $flow. references without reaching into internal modules:
- collector: re-export
walkChain(resolve a transformer chain start into the
ordered step IDs) andextractTransformerNextMap(read static next-links from
aTransformer.Transformersmap). - core: re-export
isRouteArrayandisRouteConfigEntry(the canonical shape
probes forTransformer.Route) and addscanFlowRefs(value, into?), which
walks any value (string, object, array) and returns every$flow.<name>
reference found, including refs nested inside$code:snippets.
Consent and state-gated source reactions, such as the session source's session
start, now fire reliably regardless of source init order or whether state
arrives before or after run. The collector delivers each state change exactly
once per subscriber, so sources no longer need to re-fire on repeat collector
notifications of the same state.
Destinations now batch every event when you set config.batch, with no '* *'
wildcard mapping rule needed. A bare number sets the debounce wait;
{ wait, size, age } tunes the window. Rule-level batch still overrides per
event type, and pending batches now flush on shutdown.
Migration: if you previously set config.batch alongside a single non-wildcard
rule batch, config.batch only capped that rule before; it now batches all of
the destination's events. To batch only specific events, drop config.batch and
set batch on those rules.
Add an optional, strictly-typed config.credentials field to destinations,
stores, and sources. Service-account credentials now configure under
config.credentials, validated per package and resolved from $env. The
package-specific settings.credentials still works but is deprecated, so move
credentials to config.credentials. The raw settings.<sdk> passthrough (e.g.
settings.bigquery) is unchanged.
Source-level mapping examples for the dataLayer source now key on the prefix as
entity and the gtag action as action: mapping.<prefix>.<action>. The shipped
examples/mapping.ts, the comprehensive flow-complete.json example, and the
related docs reflect the convention, including the special-cased actions
consent, config, and set whose trailing token is dropped by the
entity/action split.
Refresh runtime dependencies to their latest majors: Express 5, Commander 15,
better-sqlite3 12, @libsql/client 0.17, Google Cloud functions-framework 5,
mixpanel 0.22, and jsdom 29. No public API changes; installs now pull the
current versions of these SDKs.
Internal type-safety cleanup: removed unsafe casts around browser globals and
env mocks by typing each destination's Env and reading globals through
getEnv<Env>(env). No behavior change.
The built bundle now preserves its leading "use client" directive, so Next.js
treats the package as a client boundary. The minifier could previously strip it,
which broke server components that import the package at build time.
Fix $flow reference scanning to match the resolver's name grammar, so names
with leading digits or hyphens no longer produce false-positive references.
FlowState records can now carry an optional platform field
('web' | 'server') identifying the runtime that produced the state. Observers
can use it alongside flowId to correlate telemetry across web and server
runtimes of the same flow.
getEnv is now generic over a destination's Env. Passing your env type
(getEnv<Env>(env)) returns window/document as the real DOM globals merged
with your declared SDK shape, so destinations no longer need to cast browser
globals (as Window/as Document) at the call site.
getHashServer now accepts an algorithm option (sha256 default, or md5),
so destinations can request either digest from the shared util instead of
calling Node crypto directly. Criteo's email hashing composes this util for its
md5, sha256, and sha256_md5 forms. No behavior change for existing SHA-256
callers.
Documentation fix: server source config.ingest examples now use the map
operator with direct request field paths instead of a bare object. A bare object
like { url: 'req.url' } is silently inert, so the ingest stayed empty and
downstream ingest.* fields never resolved. Affects package hints, READMEs, the
core source type docs, and the bundled CLI example.
Bundle skeletons now expose each package's dev exports through a lazy loader.
Production deploy bundles drop it entirely, so a shipped walker.js never
carries the dev schema graph, while in-process simulate and push inline the dev
exports so they resolve on a minimal runtime without the source packages
installed alongside. This fixes a browser deploy bundle that could fail to build
or retain dev schemas, and web simulation that could not find the dev exports.
The MCP now loads flows by ID, requires the flow_simulate step parameter it
always enforced, and adds a diagnostics tool reporting client and CLI versions
plus backend reachability. Package discovery returns a complete catalog with a
warning when a source degrades, instead of silently caching partial results, and
returned flow configs are round-trip safe (structural values stay literal). The
demo source can now be simulated as a source step; the CLI also exports
VERSION and resolveAppUrl and clears a deleted default project.
The MCP flow_simulate and flow_bundle tools now accept a cloud flow id as
configPath, so you can simulate or bundle a saved flow without a manual file
round-trip, and repeated simulations reuse a prebuilt bundle for faster runs.
Loading or fetching a flow with no default project set now returns a clear "no
default project" error, and flow_examples surfaces a referenced package's
shipped examples when a step has none inline. Bundle stats now report the real
total bundle size and list package names instead of a per-package estimate, and
the GA4 transformer documents its wiring contract via package hints.
Step examples are no longer bundled into production output. They were
accidentally exported from the production entry of these packages and pulled
into bundled JS. Examples remain available via the package ./dev subpath for
simulation and testing.
Add the Piano Analytics web destination, forwarding events to the official Piano
pa SDK via sendEvent.
Preview creation can now target a deployed version: pass
source: { kind: 'deployment-version', deploymentVersionId } to createPreview
(CLI) or the MCP flow_manage preview_create action to preview what's live
instead of the flow's draft. Deleting a preview no longer errors on the empty
204 No Content response and resolves to a confirmation record.
Request caching now persists structured HTTP responses, including binary bodies
(Buffer, Uint8Array, ArrayBuffer), to byte/string store backends
(filesystem, S3, GCS, in-memory) and honors TTL. Previously, caching a response
could crash the process or never populate, and entries never expired. Cached
values now round-trip safely (binary bodies decode back as a Buffer) and
expire correctly instead of serving stale content after a redeploy.
A source or destination with a require gate now activates reliably from the
collector's current recorded state, regardless of source init order or which
source provided the required state (such as a CMP applying consent). CMP and
session sources now perform their initial consent read during init(), so
construction stays side-effect free.
Trace telemetry now activates at runtime by polling the deployment's trace
window, so web and server flows start and stop full-payload recording without a
redeploy. A future trace window upgrades a flow to full inbound and outbound
recording, and a null or past window reverts to the flow's observe baseline
and self-expires.
Add the data-elb_ scoped generic attribute. It carries the same key:value
properties as the blanket data-elb- generic, but only events whose triggered
element is nested below the data-elb_ element receive them. The
createTagger() API gains a scoped() method and the generate_tagging MCP
tool gains a scoped input to produce it. Use data-elb- for properties every
trigger in an entity should carry, and data-elb_ when only triggers within a
specific branch should.
Add a secret_manage MCP tool (and matching CLI functions) to manage a flow's
secrets. List secret metadata, create, rotate, and delete secrets that flow
steps reference as $env.<NAME>. Values are write-only: encrypted at rest and
never returned or logged.
Source simulation gains a collector step that runs the real collector
enrichment and returns the fully enriched event. Transformer simulation now
accepts an optional raw ingest so request decoders like GA4 can be tested
standalone by supplying a url. The flow_simulate MCP tool accepts the new
collector step and the transformer ingest input.
The inspector now shows scoped (data-elb_) and generic (data-elb-)
attributes resolved onto the entities that use them, labeled by origin, and
scoped attributes are included in the visual property highlight. The three panel
tabs are renamed to Events (N), Live Events (N), and Skeleton (N).
Add a declarative state block for get/set against a store, replacing
$code: for simple fetch and stash. Available on source, transformer, and
destination steps; defaults to an in-memory store.
Stores now use one structured value type with binary (Uint8Array) as a
first-class leaf, serialized by a shared codec. A new file: true store option
serves byte-exact assets such as walker.js (default is structured key-value).
TTL is owned by the cache layer, not the store. Sheets is structured-only and
rejects file: true.
Add a unified tag visualization: the Tag atom plus TagCanvas and
TagTreeEditor. It renders walkerOS data-elb tagging as nested rectangles
(entity, context, global, action, property) with an auto-laid-out reading view
and an overlay you can draw onto a screenshot. The overlay editor supports
dragging and resizing rectangles, keeping every tag fully nested or fully
separate. The existing TagSkeleton and TagSkeletonOverlay continue to work.
The wrapped browser bundle can now install a telemetry observer without a trace
poll. When the telemetry options omit traceUrl, the bundle emits at a fixed
level with no polling, suited to short-lived, URL-opted-in sessions. Bundles
that pass traceUrl keep the existing poll behavior.
New @walkeros/transformer-validate transformer validates events against JSON
Schema contracts. It runs in both web and server flows, supports strict and pass
modes, and writes the verdict and error list to configurable paths so you can
gate or observe event quality.
The declarative per-step validate field on sources, transformers, and
destinations is removed. Define event shapes in the top-level contract and
enforce them at runtime by adding a transformer-validate step that references
them via $contract.<name>; format: true still checks an event is a valid
WalkerOS.PartialEvent. Design-time validation now checks step examples against
the resolved contract.
Flow validation now scopes the "web flows cannot reference a managed secret"
check per flow. A multi-flow config where a web flow forwards to a server flow
that holds a $secret. reference now validates cleanly, instead of the server
flow's secret being wrongly flagged against the web flow.
Fix schema-only contract rules being skipped during validation. A contract rule
that carries only a whole-event schema (no events block) is now enforced
instead of being treated as an inert inline schema.
Published Packages
- @walkeros/cli
- @walkeros/collector
- @walkeros/core
- @walkeros/destination-demo
- @walkeros/explorer
- @walkeros/mcp
- @walkeros/mcp-source-browser
- @walkeros/server-core
- @walkeros/server-destination-api
- @walkeros/server-destination-criteo
- @walkeros/server-destination-datamanager
- @walkeros/server-destination-gcp
- @walkeros/server-destination-mixpanel
- @walkeros/server-destination-sqlite
- @walkeros/server-source-aws
- @walkeros/server-source-express
- @walkeros/server-source-fetch
- @walkeros/server-source-gcp
- @walkeros/server-store-fs
- @walkeros/server-store-gcs
- @walkeros/server-store-s3
- @walkeros/server-store-sheets
- @walkeros/server-transformer-bot
- @walkeros/server-transformer-fingerprint
- @walkeros/source-demo
- @walkeros/storybook-addon
- @walkeros/transformer-demo
- @walkeros/transformer-ga4
- @walkeros/transformer-validate
- @walkeros/web-core
- @walkeros/web-destination-api
- @walkeros/web-destination-gtag
- @walkeros/web-destination-meta
- @walkeros/web-destination-piano
- @walkeros/web-destination-piwikpro
- @walkeros/web-destination-plausible
- @walkeros/web-destination-snowplow
- @walkeros/web-source-browser
- @walkeros/web-source-cmp-cookiefirst
- @walkeros/web-source-cmp-cookiepro
- @walkeros/web-source-cmp-usercentrics
- @walkeros/web-source-datalayer