Commit Graph

1433 Commits

Author SHA1 Message Date
github-actions[bot] 5de1b7a100 Version Packages (beta) (#2859)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
workflow@5.0.0-beta.30
2026-07-10 14:57:35 -07:00
Peter Wielander 4dce2aeca2 fix(world-vercel): cancel v4 event frame stream on early exit to release undici connections (#2873) 2026-07-10 14:50:34 -07:00
Mitul Shah 36c63af4a8 feat(core): record replay lineage in run executionContext (#2872)
* feat(core): record replay lineage in run executionContext

recreateRunFromExisting now stamps the source run id into the new run's
executionContext as `replayedFromRunId`, and `start` accepts a matching
option. This lets tooling (e.g. the dashboard runs list) surface a run as
a replay and link back to the run it was replayed from — previously a
replay started a brand-new run with no link to its origin.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Apply suggestion from @mitul-s

Signed-off-by: Mitul Shah <mitulxshah@gmail.com>

* cleanup

* Update runs.test.ts

* update

---------

Signed-off-by: Mitul Shah <mitulxshah@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 14:37:39 -07:00
Mitul Shah 8b3a3580e0 fix(web-shared): remove unused flex-1 from attribute copy-value rows (#2864)
The row is already right-aligned via the parent's justify-between, so
flex-1 was only forcing the value column to stretch. Drop it so values
hug their content.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 15:23:54 -04:00
Karthik Kalyan 84df8f3a05 Update @vercel/queue from 0.3.1 to 0.4.0 (#2876)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 12:22:58 -07:00
Karthik Kalyan 48fcc4efcc [core] Thread queue namespace through o11y run actions and bound healthCheck stream reads (#2874)
* [core] Thread queue namespace through o11y run actions and bound healthCheck stream reads

Deployments that use a queue namespace (e.g. eve's __eve_wkf_workflow_*
topics) could not be targeted by cross-context callers: start(),
recreateRunFromExisting(), reenqueueRun(), and wakeUpRun() always built
queue names from the caller's WORKFLOW_QUEUE_NAMESPACE env, so dashboard
replays published to topics the target deployment has no consumer for.

Additionally, healthCheck()'s poll loop only checked its timeout between
iterations while world.streams.get() itself was unbounded — against
workflow-server, which holds unwritten streams open for ~2 minutes, a
2s capability probe hung until the caller's function timed out (the
observed 30s 504s on dashboard replay).

- Add a `namespace` option to StartOptionsBase, RecreateRunOptions,
  StopSleepOptions, and new ReenqueueRunOptions; thread it into
  getWorkflowQueueName() and the cross-deployment capability probe.
- Fold the inline `namespace` param into HealthCheckOptions.
- Race streams.get() against the remaining health-check budget.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Shorten changeset

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 11:45:56 -07:00
Peter Wielander 25b1509e19 [rollup] Externalize optional @opentelemetry/api peer (only when absent) so framework builds don't fail (#1947) 2026-07-10 10:13:34 -07:00
Peter Wielander 66036282b5 Fix duplicate inline step execution on mid-step wake via message ownership (#2848) 2026-07-10 09:46:40 -07:00
Nathan Colosimo 145835b647 Centralize workflow event semantics (#2790)
* Centralize workflow event semantics

* Simplify centralized event helper usage

* refactor: finish centralizing event semantics

* refactor(world): derive Hook from its schema

* fix(world): preserve event helper compatibility
2026-07-10 09:31:22 -07:00
Karthik Kalyan 2c6ee614b5 feat(world-vercel): client-observed stream write/read e2e latency spans (#2857)
* feat(world-vercel): name stream client spans + add stream attributes

Stream write/read requests already share the instrumented HTTP envelope
(a CLIENT span + W3C trace-context injection), but the spans were named
for the bare HTTP verb (`http PUT`/`http GET`) and carried only generic
HTTP attributes — so stream latency couldn't be sliced per run/stream.

Name these spans for their operation (`workflow.stream.write` /
`workflow.stream.read`) and tag them with `workflow.run.id`,
`workflow.stream.name`, `workflow.stream.operation`
(write | write_multi | close | read), and `workflow.stream.start_index`
(read). Implemented via new optional `spanName`/`attributes` fields on
`instrumentedFetch`, so other callers are unaffected.

Additive OTEL only: no behavior change when no OpenTelemetry SDK is
registered (the span is undefined and attributes are dropped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Shorten changeset summary

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Add client-observed end-to-end read TTFC span

The read GET can't report a client-measured latency back to the server (the
value only exists after the response starts streaming), so capture it purely
in the SDK's own OTEL: watch response.body for the first non-empty chunk and
emit a workflow.stream.read span back-dated to read dispatch, whose duration is
the end-to-end time-to-first-chunk (incl. the network hop) via
workflow.stream.read.ttfc_ms. Rename the fetch/connect span to
workflow.stream.read.connect. No-op without an OTEL SDK registered.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Add client-observed e2e write latency attribute

The write PUT is request/response and the server acks only after capturing the
chunk, so the workflow.stream.write span duration already equals the
client->server write latency. Expose it as a named attribute
workflow.stream.write.e2e_ms (via a durationAttribute option on
instrumentedFetch) for direct querying, parallel to the read ttfc_ms.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: document stream spans and latency attributes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Emit read TTFC span from the core reader instead of a world-vercel transform

Per review: move the client-observed time-to-first-chunk measurement out of a
TransformStream wrapper in world-vercel and into WorkflowServerReadableStream in
core, emitting workflow.stream.read on the first non-empty chunk reaching the
consumer. Removes the passthrough, measures at the reader abstraction, and is
backend-agnostic. world-vercel keeps the workflow.stream.read.connect HTTP span;
the recordElapsedSpan helper now lives in @workflow/core.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Apply suggestion from @VaguelySerious

Signed-off-by: Peter Wielander <mittgfu@gmail.com>

* Update docs/content/docs/v5/observability/tracing.mdx

Co-authored-by: Peter Wielander <mittgfu@gmail.com>
Signed-off-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com>

* Address review: rename write.e2e_ms -> write.chunk_rtt; docs + changeset wording

Per review, rename the write attribute to workflow.stream.write.chunk_rtt (it's
a per-chunk client<->server round-trip, not a full e2e), update the docs row
wording for both write and read attributes, and shorten the changeset.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Signed-off-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-07-09 17:28:41 -07:00
Nathan Colosimo df7e71de1c fix(builders): harden Windows HMR file writes (#2853) 2026-07-09 15:57:41 -07:00
Syed Osama Ali Shah 9958424f22 fix(core): guard extractStreamIds against circular references (#2687)
Signed-off-by: Osamaali313 <86572800+Osamaali313@users.noreply.github.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-07-09 12:30:23 -07:00
Karthik Kalyan f28150c626 Report STSO step progress telemetry (#2850)
* feat: report STSO step progress

* fix: report step and event counts
2026-07-09 11:38:03 -07:00
Mitul Shah 392d347e5d Anchor trace viewer shortcut helper to the timeline's left edge (#2837)
* Anchor trace viewer shortcut helper to the timeline's left edge

Render the shortcut helper inside the timeline column instead of as a
pane-root overlay, so it aligns to the timeline's left edge (tracking
the divider for free) and sticks to the bottom of the viewport while
the pane scrolls. Gate visibility on a container-query width
(`@container` on the timeline column + `@min-[420px]`) rather than the
viewport `md` breakpoint, so it hides based on the timeline's own width.

No SplitPane API change required.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Raise shortcut-helper container-query threshold to 480px

At 420px the helper could still show when the detail panel squeezes the
timeline, colliding with the zoom controls in the bottom-right. 480px
leaves comfortable clearance so it hides once the timeline is narrow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Update trace-viewer.tsx

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 16:25:23 +00:00
github-actions[bot] b498844a4d Version Packages (beta) (#2824) workflow@5.0.0-beta.29 2026-07-09 08:51:39 -07:00
Peter Wielander 39673b7a38 [ci] Benchmark preflight + fail-fast for broken deployments (#2846) 2026-07-08 17:53:30 -07:00
Peter Wielander 210a153587 fix(world-local): stabilize hook-index perf test against Windows CI jitter (#2847) 2026-07-08 17:26:36 -07:00
Peter Wielander 8977666479 [ci] Benchmark comment: show avg-latency deltas vs main (#2842) 2026-07-08 23:47:43 +00:00
Peter Wielander 712ed61f0a Add optional reason to run cancellation (#2840) 2026-07-08 16:40:03 -07:00
Peter Wielander 3f696668bc [core/world/world-vercel] Report TTFS/STSO latency telemetry on step terminal events (#2833) 2026-07-08 16:17:15 -07:00
Mitul Shah 36798335ea make event list border colours solid (#2832) 2026-07-08 22:44:10 +00:00
Mitul Shah f2f4b9d29f Match split-pane divider drag to the detail panel (#2838)
* Match split-pane divider drag to the detail panel

The trace event-list / timeline split-pane divider now reuses the shared
DraggableBorder component, so it resizes identically to the span detail
panel: a wider invisible hit strip, hover/focus/drag highlight rendered
over the divider, double-click reset, and keyboard/ARIA (role="separator")
resize. Width stays in-memory (not persisted), unlike the detail panel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Update split-pane.tsx

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 22:43:26 +00:00
Andrew Barba 79a9813f25 perf(world-local): index hook lookups instead of scanning the global event log (#2830)
* perf(world-local): index hook lookups instead of scanning the global event log

Hook creation, hook cache rebuilds, and token lookups previously read
and parsed every event file ever written across all runs, and run
termination read every live hook entity — making every turn of a
long-lived local session slower as history accumulated. Maintain
durable per-token / per-hookId indexes and per-run hook markers
(with a one-time backfill for pre-index data dirs), resolve tokens
through the claim file, read directory listings concurrently, reuse
compiled filename regexes, and raise the recovery page size.

* chore: trim development comments

* test(world-local): make hook-index perf guard machine-speed independent

The absolute 2s wall-clock bound timed out on Windows CI, where
filesystem operations are ~50x slower. Compare hook-creation cost
before vs. after seeding foreign event history instead.

* review: keep world package untouched, batch backfill reads

- Revert the recovery page-size change in @workflow/world; default
  world-local runs.list to a 200-item page instead
- Read backfill event/hook files with bounded concurrency (32),
  matching paginatedFileSystemQuery, to cut one-time migration cost
  on large legacy data dirs (slow-fs platforms especially)
2026-07-08 22:18:36 +00:00
Peter Wielander da4e0995b0 [ci] Overhaul performance benchmarks: focused metrics + sticky PR comment (#2820) 2026-07-08 15:06:28 -07:00
Mitul Shah cfdb86dc73 Use ease-in-out curve for trace viewer click-to-focus zoom (#2835)
The click-to-focus viewport reframe used a weak quadratic ease-out over
150ms, which read as a near-linear snap. Switch to a stronger
easeInOutQuart curve (~cubic-bezier(0.77, 0, 0.175, 1)) over 240ms so the
camera zoom/pan accelerates and decelerates like a smooth move.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 21:47:57 +00:00
Mitul Shah 0459ffc8c1 allow space for ids on detail panel (#2827) 2026-07-08 20:10:01 +00:00
Mitul Shah 68ad966d12 ok (#2826) 2026-07-08 20:07:27 +00:00
Mitul Shah d6defd490a ok (#2817) 2026-07-08 14:43:01 -04:00
Nathan Colosimo 421ff4f349 Bump e2e framework versions (#2814)
* Fix SvelteKit config loading

* Bump e2e framework versions
2026-07-08 10:25:34 -07:00
github-actions[bot] ab56979d0e Version Packages (beta) (#2815) workflow@5.0.0-beta.28 2026-07-08 16:53:04 +00:00
Nathan Colosimo 2552d8bc21 Fix next watcher custom dist dir (#2813) 2026-07-08 09:31:16 -07:00
Mitul Shah caac565402 Add minimap to the trace viewer (#2800)
* nice

* Update trace-viewer-skeleton.tsx
2026-07-08 10:45:05 -04:00
Peter Wielander e7e5a0e56d [world-local] Fix per-step AbortSignal latency and O(world) chunk polling (#2807) 2026-07-07 23:38:22 -07:00
Karthik Kalyan fe327e69e2 [world][web][cli] o11y: window-aware runs listing (#2812)
* web: infinite scroll for the runs table

Replace Previous/Next cursor paging with front-style infinite scroll:
a useInfiniteList hook accumulates cursor pages with per-run dedup and
generation-guarded resets, and useLoadMoreOnScroll drives loadMore from
an IntersectionObserver sentinel (400px prefetch margin, guarded against
double-fetch, observed against the table's scroll container). Footer now
shows the loaded count and the analytics lookback window.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* web: back the runs infinite list with SWR so tab switches serve from cache

Rewrite useInfiniteList on useSWRInfinite: pages are keyed by
[cacheKey, cursor] in SWR's global cache, so unmount/remount (switching
tabs) restores fetched pages instantly instead of refetching. Revalidation
is conservative because analytics list queries are expensive:
revalidateFirstPage and revalidateIfStale are off; freshness comes from
the Refresh button and the visibility-change auto-reload, which map to
reload() (reset to first page + revalidate).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* world: expose startTime/endTime on analytics runs listing

The workflow-server /v2/analytics/runs endpoint has accepted a bounded
startTime/endTime window since it shipped, and is significantly faster
with one (the window prunes the ClickHouse scan: ~2s for 12h vs ~8s for
the default 30-day entitlement window). The world client never exposed
the params, so the CLI and web UI could only issue windowless requests.
Pass them through so clients can send bounded windows (e.g. a period
picker like front's workflows o11y).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* web: front-style period picker for the runs list

Add a time-window picker (1h/6h/24h/3d/7d/30d, default 24h, URL-backed
via ?period=) that sends an explicit startTime/endTime window through
fetchRuns -> world.analytics.runs.list, keeping the ClickHouse scan
bounded. The window is frozen per selection/refresh so all cursor pages
share the same bounds, and it participates in the SWR cache key.

Plan tiers are honored data-driven from the server's pageInfo: presets
longer than the plan's observability lookback are disabled in the picker
(labeled Observability Plus when an upgrade is available), and a 402
observability-upgrade-required response renders through the existing
upgrade-required error handling. The footer now labels the selected
window instead of the plan lookback. The runtime (local) fallback path
ignores the window since the storage API has no time filter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* web: allow status filtering without a workflow name filter

The status dropdown was disabled on Vercel backends until a workflow was
selected — a limitation of the runtime DynamoDB API's index design. The
runs list now reads via world.analytics, whose ClickHouse query filters
derived status independently of workflowName, so drop the guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* cli: time-window flags for runs listing; widen name lookups past the default window

The analytics backend now defaults windowless runs listings to the
trailing 24h. Replicate the web's window support in the CLI:

- 'workflow inspect runs' gains --since/--until (relative durations like
  30m/12h/7d/2w, or timestamps) which are sent as an explicit
  startTime/endTime window. Out-of-plan windows surface through the
  existing observability-upgrade-required handling; non-analytics
  backends warn that the flags are ignored.
- 'workflow start <name>' resolves the workflow's latest run via a
  windowless (default-window) listing and now retries across the plan's
  whole observability window on a miss, so names idle for more than a
  day keep resolving.
- Bulk 'workflow cancel' matches across the plan window up front — a run
  can sleep or wait on a hook for days without recent events, so the
  default recent window must not bound cancellation matching.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: tighten changeset descriptions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* web: persist frozen listing windows across remounts; minimize lockfile diff

Address review findings:

- The frozen startTime/endTime lived in component state, but RunsTable
  fully remounts on tab switches, so every remount minted a new SWR cache
  key — the cached-pages restore never hit and cache entries grew
  unboundedly (one per key, including every 5s local-backend poll tick).
  Move the frozen windows to a module-scope store keyed by period: a
  remount reuses the stored window (same cache key, instant restore), and
  the window only advances on explicit refresh/reload. Non-analytics
  backends now send no window at all (the runtime APIs ignore it anyway),
  which also hides the period picker and window label there.

- Regenerate pnpm-lock.yaml from main so the diff contains only the swr
  addition (plus its own use-sync-external-store dependency), dropping
  the unrelated docs-importer radix-ui re-resolutions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 18:12:17 -07:00
Nathan Colosimo aae47b9fdd Fix SvelteKit config loading (#2802) 2026-07-08 01:04:31 +00:00
Nathan Colosimo 49a50e83d9 Document configuration environment variables (v5) (#2468) 2026-07-07 17:56:41 -07:00
Peter Wielander c1d29f14ca [world-local] Fix resumeHook racing hook disposal being journaled after hook_disposed (#2808) 2026-07-07 16:42:13 -07:00
Nathan Colosimo 2ca34ac69c fix(sveltekit): production server crash from bundled TypeScript compiler (#2799)
* fix(sveltekit): patch server chunks with rollup-renamed __filename bindings

The adapter-node chunk patch skipped any chunk matching
/\b(const|let|var)\s+__(file|dir)name\b/ — but $ is not a regex word
character, so rollup-renamed declarations like `__filename$1` (produced
when adapter-node re-bundles the intermediate server output and our
banner's declaration collides) satisfied the check. Chunks that declared
only a renamed binding while a bundled CJS dependency referenced the
bare `__filename` were skipped, and the production server crashed at
boot (observed on main with the TypeScript compiler bundled via
cosmiconfig through @workflow/world-postgres).

Anchor both regexes with (?![\w$]) so renamed identifiers no longer
match. Verified: the sveltekit workbench production server now boots and
serves health checks (with and without a base path), and queue
deliveries from start() succeed.

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>

* fix(sveltekit): keep the TypeScript compiler out of the server bundle

Since the world-target injection change, the sveltekit workbench's
hooks.server.ts imports @workflow/world-postgres, whose dependency chain
(graphile-worker -> cosmiconfig) reaches cosmiconfig's TS-config loader.
At runtime that loader's require('typescript') is lazy and never fires,
but SvelteKit bundles the whole chain into the server and rollup's CJS
conversion hoists it into an eager top-level evaluation — executing the
entire TypeScript compiler at boot and crashing the server
("__filename is not defined" inside the bundled compiler).

Alias 'typescript' to a stub module in the SvelteKit plugin, following
the existing pg-native pattern. Server output shrinks from 36MB to 11MB
and boots cleanly.

Verified: sveltekit workbench production build boots, serves
flow?__health (200), and start() runs execute with clean queue
deliveries. The chunk-patch regex fix from the previous commit stays as
hardening for any other CJS dependency that references __filename.

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>

* Update .changeset/fix-sveltekit-filename-chunk-patch.md

Signed-off-by: Peter Wielander <mittgfu@gmail.com>

---------

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-07-07 23:07:13 +00:00
Karthik Kalyan 54f46f976d cli: restore dynamic world loading for community backends (#2806)
* cli: restore dynamic world loading for community backends

Since #2752 moved world selection to static injection, setupCliWorld only
constructed the vercel, local, and postgres worlds explicitly and threw
'Unsupported workflow backend' for anything else — breaking community
worlds (e.g. @workflow-worlds/turso) that previously loaded through the
dynamic createWorld() in @workflow/core/runtime.

Generalize the postgres-only dynamic path: any backend other than
vercel/local is now resolved from the user's project directory and loaded
via its createWorld() export, matching @workflow/web's world construction
(#2804), with clear errors when the package is missing or does not export
createWorld().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* cli: fall back to default.createWorld for CJS world packages

Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Update .changeset/cli-generic-world-backends.md

Signed-off-by: Peter Wielander <mittgfu@gmail.com>

---------

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-07-07 15:47:58 -07:00
Karthik Kalyan cdfac39e07 web: construct worlds explicitly instead of via static-injection stub (#2804)
* web: construct worlds explicitly instead of via static-injection stub

Since #2752, createWorld() from @workflow/core/runtime is a stub that
throws unless a framework build plugin aliases it to a world package.
The CLI was migrated to construct worlds directly, but @workflow/web
still called the stub, so 'workflow web' crashed with 'Workflow target
world was not statically injected' for local and postgres backends
(the vercel path was unaffected since it constructs the world directly).

Mirror the CLI: import the local world statically and resolve any other
configured world package from the inspected project's directory.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* web: fall back to default.createWorld for CJS world packages

Review feedback: import() of a require-resolved CJS entry relies on
cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails. Mirrored in the CLI in #2806.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 15:47:51 -07:00
Nathan Colosimo 1c07d7d29a fix(workbench): add @repo/* tsconfig alias to nitro-v2 (#2787)
The workbench workflows are shared across apps (nitro-v2/workflows
symlinks into files shared with workbench/example), and the shared
99_e2e.ts workflow imports @repo/lib/steps/paths-alias-test. nitro-v2's
tsconfig was missing the @repo/* path alias that nitro-v3 already has,
so building nitro-v2 with the Vercel preset failed at esbuild
resolution:

  ../example/workflows/99_e2e.ts: ERROR: Could not resolve
  "@repo/lib/steps/paths-alias-test"

Mirror nitro-v3's alias. Verified NITRO_PRESET=vercel pnpm build now
succeeds (was failing on main before this change).
2026-07-07 15:09:15 -07:00
Peter Wielander 7637196cf0 Fix hook token reuse after dispose() (same-run and cross-run) (#2779) 2026-07-07 14:13:15 -07:00
Karthik Kalyan ae51f45166 web: list hooks from analytics, fetch token on demand (#2652)
* Add workflow analytics world APIs

* web: read observability list views from world.analytics when available

Route the runs/steps/events/hooks list server actions through the optional
world.analytics namespace when the backend provides one, falling back to the
runtime storage APIs otherwise. Events listing only uses the analytics path
when no payload data is requested. Detail/get actions, streams, and mutations
are unchanged.

* web: keep events and hooks list reads on the runtime storage API

The Events tab and trace viewer derive step names and wait resumeAt from
resolved event payloads, and the hooks table needs the secret token and
ownerId for its resume/copy-token actions. The metadata-only analytics rows
do not carry these, so only the runs and steps list views use world.analytics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* web: read events list from world.analytics with a runtime-shape remap

The events list/trace consumers read only top-level eventType, correlationId,
and createdAt; event payloads are loaded lazily per event via fetchEvent(...,
'all') on the runtime path. Map the flat analytics event rows into the runtime
Event shape (reconstructing eventData.stepName) so fetchEvents and
fetchEventsByCorrelationId can use the analytics read path when available.
Hooks remain on the runtime path (they need the secret token + ownerId).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* web: list hooks from world.analytics, fetch token on demand

The hooks list now reads from the metadata-only world.analytics namespace
when the backend provides one (falling back to the runtime storage APIs
otherwise). A hook's secret token is no longer shipped in list rows — it is
fetched one hook at a time via world.hooks.get only when the user copies the
token or resumes the hook, keeping the secret out of bulk list responses.

Adds a fetchHookToken server action + RPC, a HookListItem type (Hook without
token), and a lazy HookTokenCell for the copy-token affordance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Handle analytics access metadata in web

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:06:41 -07:00
Karthik Kalyan 1518c48608 web: read observability list views from world.analytics when available (#2647)
* Add workflow analytics world APIs

* web: read observability list views from world.analytics when available

Route the runs/steps/events/hooks list server actions through the optional
world.analytics namespace when the backend provides one, falling back to the
runtime storage APIs otherwise. Events listing only uses the analytics path
when no payload data is requested. Detail/get actions, streams, and mutations
are unchanged.

* web: keep events and hooks list reads on the runtime storage API

The Events tab and trace viewer derive step names and wait resumeAt from
resolved event payloads, and the hooks table needs the secret token and
ownerId for its resume/copy-token actions. The metadata-only analytics rows
do not carry these, so only the runs and steps list views use world.analytics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* web: read events list from world.analytics with a runtime-shape remap

The events list/trace consumers read only top-level eventType, correlationId,
and createdAt; event payloads are loaded lazily per event via fetchEvent(...,
'all') on the runtime path. Map the flat analytics event rows into the runtime
Event shape (reconstructing eventData.stepName) so fetchEvents and
fetchEventsByCorrelationId can use the analytics read path when available.
Hooks remain on the runtime path (they need the secret token + ownerId).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Handle analytics access metadata in web

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 11:45:07 -07:00
Karthik Kalyan 17d4ce2253 cli: read list views from world.analytics when available (#2648)
* Add workflow analytics world APIs

* cli: read list views from world.analytics when available

inspect list views (runs, steps, events, hooks, sleeps) now read from the
optional world.analytics namespace when the active backend provides one,
falling back to the runtime storage APIs otherwise. Payload and detail views
are unchanged. Deprecate --with-data for list views; payloads are viewable
per-resource via 'inspect <resource> <id>'.

* cli: keep hook listing on the runtime storage API

The analytics read path omits ownerId (and the secret hook token), so routing
hook listing through it silently drops the ownerId column. Keep inspect hooks
on the runtime APIs, consistent with the web observability UI. Runs, steps,
events, and sleeps continue to use the analytics read path when available.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Handle analytics access metadata in CLI

* test(cli): preserve analytics pageInfo in json output

* fix(cli): paginate analytics sleeps output

* fix(cli): correct deprecation message flag name to --withData

The list-view deprecation warning referenced '--with-data', but the actual
oclif flag is '--withData' (with '-d' alias); '--with-data' errors with
"Nonexistent flag". Fix the warning text, the doc comment, and the changeset
to reference the real flag name.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cli): preserve inspect json array output

* fix(cli): fall back when analytics lists are empty

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 11:44:57 -07:00
Nathan Colosimo 239031ad9e fix(next): respect basePath for workflow routes (#2732)
* fix(next): respect basePath for workflow routes

* docs(core): note workflow URL resolution gap

* fix(next): expose workflow health route methods

* test(utils): remove workflow route helper tests

* test(builders): remove route handler string test

* fix(next): defer basePath validation to Next.js

* refactor(utils): remove workflow url helper wrappers

* Test Next basePath builder wiring
2026-07-06 16:43:35 -07:00
Nathan Rajlich 03862edb65 feat(world-vercel): send x-vercel-queue-region on proxy-mode queue sends (#2789)
* feat(world-vercel): send x-vercel-queue-region on proxy-mode queue sends

Token/proxy clients (CLI, dashboards, external scripts) send queue
messages through api.vercel.com's /v1/workflow proxy, where the fixed
resolveBaseUrl override replaces the queue SDK's own
region -> <region>.vercel-queue.com base-URL resolution — so every
proxied send landed on the region-less VQS host, while the direct
in-function path already dials the regional host (iad1 today).

The proxy now routes sends to the region's VQS dataplane when the
x-vercel-queue-region header is present (vercel/api#79056, deployed).
Set it on every proxy-mode send from the region the QueueClient is
constructed with, giving proxy clients parity with the direct path.

Today that region is the static 'iad1'; when per-send region
resolution lands (#1981), the header automatically carries the
tag/option-derived region — this change is the transport mechanism,
not the policy.

Tests: proxy-mode construction carries the header matching the
client's region; the direct path doesn't.

* chore: trim comments, drop private repo reference

* chore: changeset for proxy-mode x-vercel-queue-region header
2026-07-06 22:30:00 +00:00
Mitul Shah 8a766884cf change timing markers to be precise on the timeline (#2775)
* doen

* Fix: Old test file `test/format-duration-precise.test.ts` still asserts two-decimal output ("45.20s", "1m 0.00s") that no longer matches the trimmed-zero output of `formatDurationPrecise`, so `pnpm test`/CI fails.

This commit fixes the issue reported at packages/web-shared/test/format-duration-precise.test.ts:15

## Bug

The PR changed `formatDurationPrecise` (in `packages/web-shared/src/lib/utils.ts`) to trim trailing zeros by wrapping the fractional value in `Number(x.toFixed(fractionDigits))`:

```ts
if (normalizedMs < MS_IN_MINUTE) {
  return `${Number((normalizedMs / MS_IN_SECOND).toFixed(fractionDigits))}s`;
}
...
parts.push(`${Number(seconds.toFixed(fractionDigits))}s`);
```

`Number("45.20")` → `45.2`, `Number("0.00")` → `0`, so whole/half seconds now render without padding.

A new test file `packages/web-shared/src/lib/utils.test.ts` reflects this behavior, but the pre-existing `packages/web-shared/test/format-duration-precise.test.ts` was left untouched and still asserts the **old** padded output.

## Concrete trigger

Reproduced the actual function output (integer decomposition + trimmed zeros):

| Input | Old assertion | New actual output |
|-------|---------------|-------------------|
| `45200` | `45.20s` | `45.2s` |
| `999.6` | `1.00s` | `1s` |
| `999.5` | `1.00s` | `1s` |
| `59999` | `1m 0.00s` | `1m 0s` |
| `59995` | `1m 0.00s` | `1m 0s` |
| `119999` | `2m 0.00s` | `2m 0s` |
| `3659999` | `1h 1m 0.00s` | `1h 1m 0s` |
| `86459999` | `1d 1m 0.00s` | `1d 1m 0s` |

The root `vitest.config.ts` uses default include globs, so `test/*.test.ts` runs and these assertions fail, breaking CI. (I couldn't run vitest directly in the sandbox because dev deps weren't installed / `vitest/config` unresolved, so I reproduced the exact function logic in a standalone Node script to confirm the outputs.)

## Fix

Updated the stale assertions in `test/format-duration-precise.test.ts` to the trimmed-zero outputs, and adjusted the file-level doc comment (which referenced `"1m 0.00s"` / `"60.00s"`) to describe the current behavior.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: mitul-s <mitulxshah@gmail.com>

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
2026-07-06 18:27:10 -04:00
JJ Kasper 0f557d5ae4 Statically inject workflow world target (#2752)
* Statically inject workflow world target

* Fix static world injection in host bundles

* Fix static world injection gaps

* Fix Vite Nitro server startup

* Fix Nitro pg-native aliasing

* Fix static world target CI gaps

* Fix static world dev rebuild gaps

* Avoid broad runtime alias in Nitro

* Refresh Next dev route for step HMR

* Externalize Nest target world

* Use canary HMR rediscovery timeout

* Bundle local world in Nest builds

* Dedupe world target helpers and fix SvelteKit chunk patch guard
2026-07-06 14:19:45 -07:00
github-actions[bot] 166bb7bde6 Version Packages (beta) (#2692) workflow@5.0.0-beta.27 2026-07-06 13:32:59 -07:00