Skip to content

[pull] main from vercel:main#395

Merged
pull[bot] merged 2 commits into
erickirt:mainfrom
vercel:main
Jun 14, 2026
Merged

[pull] main from vercel:main#395
pull[bot] merged 2 commits into
erickirt:mainfrom
vercel:main

Conversation

@pull

@pull pull Bot commented Jun 14, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

pranaygp and others added 2 commits June 14, 2026 01:03
* docs: document run idempotency

* docs: address idempotency review feedback

* docs: make hook tokens the idempotency pattern

* docs: address toolbar idempotency feedback

* docs: clarify idempotency page description

* docs: scope idempotency descriptions

* docs: move step idempotency example under section

* docs: simplify idempotency guidance

* docs: simplify idempotency cookbook

* docs: add empty changeset

Signed-off-by: Nathan Rajlich <n@n8.io>

* docs: address idempotency review feedback

* feat: add hook ready promise

* docs: mention conflicting hook run id

* test: cover hook ready continuation scheduling

* feat: replace hook.ready with hook.hasConflict (Promise<boolean>)

- hook.hasConflict resolves true when the token is owned by another
  active hook, false once registration is committed — no throw, so
  workflows can branch on conflicts early. Awaiting it suspends the
  workflow to commit the hook registration (createHook alone does not).
- Chain the already-created fast-path through promiseQueue so
  resolution order matches event-log order (review feedback).
- Skip inline step execution when a suspension has an awaited hook
  creation so the hasConflict continuation can advance independently
  of step execution (review feedback).
- Update unit tests, e2e tests, workbench workflows, and v4/v5 docs.

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

* docs: fix inconsistent hasConflict bullet in create-webhook reference

State both resolution values explicitly (true = token already owned,
false = registered) instead of a parenthetical that only described the
false case.

* docs: require docs preview links in PR descriptions for docs changes

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

* docs: restore SWC Plugin heading in AGENTS.md

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

* docs: adopt hook.hasConflict in run idempotency docs

- Primary claim pattern is now `if (await hook.hasConflict)` instead of
  try/catch on HookConflictError; payload awaits still reject with
  HookConflictError (with conflictingRunId) when the owner's run ID is
  needed.
- Route example returns the active owner via resumeHook()'s runId
  instead of threading conflictingRunId through the workflow result.
- Update claim-pattern prose across start(), getHookByToken(), world
  storage, scheduling, workflow composition, and cookbook idempotency
  pages (v4 + v5).
- Add @skip-typecheck marker to the cross-block route sample, fixing a
  pre-existing docs typecheck failure.

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

* docs: move resume-or-start guidance into a dedicated resumeHook example

The early callout was too vague and out of place at the top of the API
reference. Replace it with a 'Resume or Start' example section that
explains the flow, shows the resume-first/start-then-retry route, and
links to the run idempotency pattern.

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

* docs: detect the concurrent-start race via runId comparison instead of awaiting returnValue

The 'Resume or Start' example returned the just-started run's runId with
reused: false even when a concurrent request's run won the token race —
the payload had reached the actual owner, so the response pointed callers
at a run that exits as a duplicate. The foundations route handled the
race correctly but by awaiting run.returnValue, blocking the HTTP
response on full workflow completion.

resumeHook() always resolves against the actual active owner, so
comparing the resumed hook's runId with the started run's runId detects
the race in both examples — race-correct and non-blocking.

* 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>

* docs: adopt hook.getConflict and add conflict-handling strategy guide

Run idempotency docs now use getConflict (resolves with the conflicting
Run in v5, { runId } in v4) and document code-driven conflict strategies
in place of static ID-reuse policies: reject the duplicate, adopt the
owner's result, inspect before deciding, signal the owner via
resumeHook, and supersede via cancel-and-reclaim.

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>

* docs: getConflict is a method — hook.getConflict()

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

* docs: typecheck every sample — drop skip-typecheck escape hatches

Route examples typecheck as-is since the runId-comparison rewrite;
strategy fragments are now complete self-contained workflows; the
publishing-libraries cross-block dependency uses the declare @setup
convention. 934 samples typechecked, none skipped by this PR.

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>

* docs: restore run-idempotency anchors now that the section exists here

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

* docs: describe fixed conflict policies generically, without naming other systems

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

---------

Signed-off-by: Nathan Rajlich <n@n8.io>
Co-authored-by: Nathan Rajlich <n@n8.io>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators Jun 14, 2026
@pull pull Bot added the ⤵️ pull label Jun 14, 2026
@pull pull Bot merged commit 0178fa5 into erickirt:main Jun 14, 2026
0 of 7 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants