You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: fix beta install path and stale guidance from v8 review
Wave 1 meta/docs items from the v8 review remediation spec:
- Item 7: add a beta-install warning and @beta-tagged install commands
to the root README, docs/how-to/install.md, and tutorial step 1 —
npm's latest dist-tag is 7.0.0 while the docs teach the v8 API.
- Item 8: correct AGENTS.md rule 2 and handlers.md — unthrown 5 does
export OkAsync/ErrAsync (only lowercase okAsync/errAsync are absent);
switch handlers.md's cancellation example from free-function
isErr(result) to the method style the codebase uses.
- Item 9: add the missing @temporalio/testing ^1 peer to
dependencies.md's testing row and key-dependencies table.
- Item 10: examples/README.md — drop stale "Promise-based worker" and
"Result/Future" wording, list all three example packages; fix the
matching one-line comment in order-processing-contract's contract.ts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .agents/rules/dependencies.md
+7-6Lines changed: 7 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,6 +8,7 @@
8
8
|`@temporalio/worker`| Temporal worker SDK — peer dep of `worker`|
9
9
|`@temporalio/workflow`| Temporal workflow API — peer dep of `worker`|
10
10
|`@temporalio/common`| Shared Temporal types — peer dep of `client`/`worker`|
11
+
|`@temporalio/testing`| Time-skipping test server (`TestWorkflowEnvironment`) — peer dep of `testing`|
11
12
|`@standard-schema/spec`| Standard Schema specification — direct dep |
12
13
|`unthrown`|`Result` / `AsyncResult` — peer dep of `client`/`worker`|
13
14
|`zod`| Direct dep of `contract` (used internally for the `defineContract` runtime validation pass); user-side schema lib for the others |
@@ -37,12 +38,12 @@ All dependency versions are centralized in `pnpm-workspace.yaml` under the `cata
37
38
38
39
Anything that appears in a published package's **public type signatures** must be a peer dep, not a regular dep — otherwise downstream consumers can end up with two disjoint nominal types in their typechecker (theirs and ours), even though the runtime classes are compatible.
| contract |`unthrown ^5` (optional — only needed when using `result-async`) |
45
-
| testing |`vitest ^4` (the `globalSetup` hook integrates with vitest's test runner), `@temporalio/client ^1`, `@temporalio/worker ^1` (both exposed by the `it` fixture's public types) |
| contract |`unthrown ^5` (optional — only needed when using `result-async`) |
46
+
| testing |`vitest ^4` (the `globalSetup` hook integrates with vitest's test runner), `@temporalio/client ^1`, `@temporalio/testing ^1`, `@temporalio/worker ^1` (all exposed by the fixtures' public types — e.g. `TestWorkflowEnvironment` in `time-skipping`) |
46
47
47
48
When you add a peer dep, also add it to `devDependencies` (with the same `"catalog:"` reference) so the local workspace build still resolves it. The workspace has `autoInstallPeers: false`, so peers must be present somewhere on the install side.
Workflows opt into cancellation control via `context.cancellableScope` / `context.nonCancellableScope`. They fold cancellation into the project's `AsyncResult` shape — callers branch on `Err(WorkflowCancelledError)` instead of catching `CancelledFailure`.
130
131
131
132
```typescript
132
-
import { isErr } from"unthrown";
133
-
134
133
implementation: async (context, args) => {
135
134
const result =awaitcontext.cancellableScope(async () => {
136
135
returncontext.activities.processStep(args);
137
136
});
138
137
139
-
if (isErr(result)) {
138
+
if (result.isErr()) {
140
139
// Workflow was cancelled. Cleanup that must not be cancelled itself
-`cancellableScope<T>(fn)` — returns `AsyncResult<T, WorkflowCancelledError>`. Cancels propagate from outside.
153
152
-`nonCancellableScope<T>(fn)` — same shape; _outside_ cancels are ignored. Cancels raised _inside_ still surface as `Err(...)`. Use for graceful-shutdown cleanup.
154
-
- Non-cancellation errors thrown by `fn` are _unmodeled_ failures: they ride unthrown's **`defect`** channel (inspectable via `isDefect(result)` / `result.cause`, re-thrown at the edge), not the modeled `err` channel.
153
+
- Non-cancellation errors thrown by `fn` are _unmodeled_ failures: they ride unthrown's **`defect`** channel (inspectable via `result.isDefect()` / `result.cause`, re-thrown at the edge), not the modeled `err` channel.
Copy file name to clipboardExpand all lines: AGENTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,7 @@ This file is the source of truth for agent guidance in this repo. `CLAUDE.md` an
7
7
## The 6 rules that prevent broken PRs
8
8
9
9
1.**Workflow code is deterministic.** No `Date.now()`, `Math.random()`, `setTimeout`, `crypto.randomUUID()`, native I/O, or `process.env` reads inside `declareWorkflow`'s `implementation`. Use `@temporalio/workflow` primitives (`sleep`, `uuid4`, the patched `Date`) or push the side effect into an activity. See [.agents/rules/workflow-determinism.md](.agents/rules/workflow-determinism.md). This is the #1 cause of broken Temporal workflows — read that file before touching workflow code.
10
-
2. **Activities and the typed client return `AsyncResult<T, E>` from `unthrown`.** Never throw — wrap technical errors in `ApplicationFailure` and surface them via `Err(...).toAsync()` (or `fromPromise(promise, qualify)`, where `qualify` returns the modeled error `E`). unthrown has no `okAsync`/`errAsync`: lift a sync `Result` with `.toAsync()`. The client uses unthrown's `Result` for sync returns. unthrown adds a third **`defect`** channel for _unanticipated_ failures — a thrown exception the code didn't model surfaces as a defect (inspectable via `result.isDefect()` / `result.cause`, re-thrown at the edge), not a typed `err`. Narrow before reaching `.value`/`.error`/`.cause` — both the `r.isOk()` method and the `isOk(r)` free function are type guards (same for `isErr`/`isDefect`); the codebase uses the methods. Error classes are built with `TaggedError("@temporal-contract/Name", { name: "Name" })<{ ...payload }>` — the `_tag` is package-namespaced to avoid collisions, while `options.name` keeps `Error.name` the bare class name for readable logs. The worker's `ValidationError` subclasses are the exception — they must stay `ApplicationFailure` for Temporal's terminal-failure semantics. There is no `neverthrow`, no `@swan-io/boxed`, and no `@temporal-contract/boxed` package — those were removed.
10
+
2. **Activities and the typed client return `AsyncResult<T, E>` from `unthrown`.** Never throw — wrap technical errors in `ApplicationFailure` and surface them via `Err(...).toAsync()` (or `fromPromise(promise, qualify)`, where `qualify` returns the modeled error `E`). unthrown has no lowercase `okAsync`/`errAsync`: use `OkAsync(value)`/`ErrAsync(error)` to construct an `AsyncResult` directly, or lift an existing sync `Result` with `Ok(value).toAsync()`/`Err(error).toAsync()`. The client uses unthrown's `Result` for sync returns. unthrown adds a third **`defect`** channel for _unanticipated_ failures — a thrown exception the code didn't model surfaces as a defect (inspectable via `result.isDefect()` / `result.cause`, re-thrown at the edge), not a typed `err`. Narrow before reaching `.value`/`.error`/`.cause` — both the `r.isOk()` method and the `isOk(r)` free function are type guards (same for `isErr`/`isDefect`); the codebase uses the methods. Error classes are built with `TaggedError("@temporal-contract/Name", { name: "Name" })<{ ...payload }>` — the `_tag` is package-namespaced to avoid collisions, while `options.name` keeps `Error.name` the bare class name for readable logs. The worker's `ValidationError` subclasses are the exception — they must stay `ApplicationFailure` for Temporal's terminal-failure semantics. There is no `neverthrow`, no `@swan-io/boxed`, and no `@temporal-contract/boxed` package — those were removed.
11
11
3.**No `any`.** Use `unknown` and narrow. Enforced by oxlint.
12
12
4.**`.js` extensions in every import.** TypeScript files import each other as `./foo.js`, never `./foo` or `./foo.ts`. Required by ESM module resolution.
13
13
5.**ESM only.** All packages are `"type": "module"`. No CommonJS in source.
0 commit comments