Files
Pranay Prakash 01c8c0878a Replace hook.hasConflict with hook.getConflict() returning the conflicting Run (#2373)
* feat: replace hook.hasConflict with hook.getConflict (Promise<Run | null>)

hasConflict's boolean didn't expose WHICH run owns the token, so the
duplicate run couldn't act on the conflict. getConflict resolves with
null once registration commits, or with a Run handle for the conflicting
run — letting the workflow return/log the owner's runId, inspect its
status, await its result, or cancel it and continue, all in code.

The workflow-mode create-hook module exposes the bundle's compiled Run
class (durable step-proxy methods) on a well-known symbol so the host-
side hook consumer can construct the conflicting run inside the VM.
Contexts without the class (plain unit tests) fall back to a { runId }
object, which is also the documented v4 shape (no native Run
serialization in v4).

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

* fix: never resolve getConflict with a non-Run fallback shape

getConflict's contract is Promise<Run | null>. In the degenerate cases
where a real Run cannot be constructed — a hook_conflict event persisted
by an old world without conflictingRunId, or a context that never loaded
the workflow-mode create-hook module — reject with HookConflictError
instead of resolving with a { runId }-shaped impostor.

Test harnesses now register the Run class on the (VM) globalThis like
real bundles do.

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

* refactor: make getConflict a method — hook.getConflict()

A property getter that triggers registration/suspension reads as passive
state; a method makes the side effect explicit. Update implementation,
types, tests, e2e workflows, docs, and changeset.

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

* review: guard Run class registration, fix anchors, clarify changeset

- Only register WORKFLOW_RUN_CLASS when the workflow runtime is present
  (WORKFLOW_CREATE_HOOK installed on globalThis), so host imports of the
  workflow-mode module neither mutate the host global nor expose the
  non-step-proxy host Run.
- Drop #run-idempotency link fragments — that section lands in the
  stacked docs PR (#2011), which restores the anchored links.
- Note in docs that getConflict() rejects with HookConflictError for
  legacy hook_conflict events lacking the owner's run ID.
- Changeset now calls out the hasConflict -> getConflict() replacement.

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

* refactor: resolve the conflicting Run through the serialization class registry

Replace the bespoke WORKFLOW_RUN_CLASS global with the registry the
serialization pipeline already uses to revive Run instances:

- The SWC plugin already auto-registers the workflow bundle's compiled
  Run in globalThis[workflow-class-registry], but under a path-derived
  classId the host cannot know statically. The workflow-mode create-hook
  module now aliases it under a stable id (class//workflow//Run) via a
  new aliasSerializationClass() helper (a plain registry entry —
  registerSerializationClass cannot be reused since the plugin's IIFE
  already defined the non-configurable classId property).

- createConflictingRun() looks the class up with
  getSerializationClass(RUN_CLASS_ID, ctx.globalThis) and constructs
  through its WORKFLOW_DESERIALIZE hook, exactly as the Instance reviver
  would for a serialized Run crossing from a step into the workflow.

- Because the registry is keyed per-global, no environment guard is
  needed: a stray host-side import registers the host Run on the host
  registry, which is the correct class for that context. The
  WORKFLOW_CREATE_HOOK guard, the ??=, and the WORKFLOW_RUN_CLASS symbol
  are all deleted.

Verified: 1156 core unit tests; compiled workbench bundle contains the
stable alias alongside the plugin's path-derived registration with zero
WORKFLOW_RUN_CLASS references; all 5 hookGetConflict e2e tests pass
against a local nextjs-turbopack dev server, including conflict
resolution reading conflict.status through a durable step.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Nathan Rajlich <n@n8.io>
2026-06-12 07:52:36 +00:00
..
2026-03-23 19:30:01 -07:00
2026-04-22 14:05:38 -07:00
…

Workbench

These apps are used for testing internally. Refer to Workflow SDK Examples to see some use cases and working examples.