Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions packages/client/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
# @temporal-contract/client

## 8.0.0-beta.9

### Minor Changes

- 3ed260c: Ready-made error pattern groups — `WORKFLOW_START_PATTERNS`,
`WORKFLOW_RESULT_PATTERNS`, `WORKFLOW_EXECUTE_PATTERNS`,
`WORKFLOW_STOPPED_PATTERNS`, `SIGNAL_PATTERNS`, `QUERY_PATTERNS`,
`UPDATE_PATTERNS`, `SCHEDULE_CREATE_PATTERNS`. Each mirrors one method's error
union exactly, so `matcher.with(...WORKFLOW_RESULT_PATTERNS, handler)` replaces
six hand-written `P.tag(...)` arguments.

Exhaustiveness is unchanged: these are ordinary pattern tuples, so a missing
member is still a compile error naming it. A workflow's **declared contract
errors** are deliberately not in these groups — no shipped group can name a
user's own errors — so for a workflow that declares `errors`, a group alone is
not exhaustive: match those first with `{ errorName: "..." }`.

- 5545236: Workflows can derive their **workflow ID** from their input:

```ts
const processOrder = defineWorkflow({
input: OrderSchema,
output: OrderResultSchema,
workflowId: ({ orderId }) => `order-${orderId}`,
startPolicy: "once-per-id",
});
```

`startPolicy` only bites when two starts of the same logical request collide on
one ID, and the ID used to be entirely the caller's — passing
`crypto.randomUUID()` made `"once-per-id"` inert with no diagnostic. A workflow
that declares `workflowId` now derives it from the validated payload on
`startWorkflow` / `executeWorkflow` / `signalWithStart`, and supplying one at
the call site is a type error. Workflows that declare none are unchanged.

`IdempotencyMode` is renamed to `WorkflowStartPolicy` (the old name stays as a
deprecated type alias).

### Patch Changes

- Updated dependencies [4e47875]
- Updated dependencies [5545236]
- @temporal-contract/contract@8.0.0-beta.9

## 8.0.0-beta.8

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@temporal-contract/client",
"version": "8.0.0-beta.8",
"version": "8.0.0-beta.9",
"description": "Client utilities with unthrown Result/AsyncResult for consuming temporal-contract workflows",
"keywords": [
"client",
Expand Down
57 changes: 57 additions & 0 deletions packages/contract/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,62 @@
# @temporal-contract/contract

## 8.0.0-beta.9

### Minor Changes

- 4e47875: Activities can declare an **idempotency key**, derived from their input:

```ts
const chargeCard = defineActivity({
input: z.object({ orderId: z.string(), customerId: z.string(), amount: z.number() }),
output: PaymentSchema,
// Key on what IDENTIFIES the charge, not on what describes it: one customer
// placing two orders of the same value must not collide on one key.
idempotencyKey: ({ orderId }) => `charge:${orderId}`,
});

chargeCard: ({ input, idempotencyKey }) =>
fromPromise(
gateway.charge(input, { idempotencyKey }),
qualifyFailure("CHARGE_FAILED", { expected: GatewayError }),
),
```

Temporal runs activities **at least once**, and nothing in the library helped
with that until now — `idempotency` on a workflow is start deduplication and
says nothing about an activity running twice. Being payload-derived, the key is
stable across activity retries, worker crashes, and a fresh workflow execution
with the same input.

`helpers.idempotencyKey` is typed `string` for an activity that declares one and
`undefined` for one that does not, so reaching for a key that was never declared
is a compile error. `runActivity` hands over the same value.

Good key sources: a business identifier already in the input, a dedicated
`idempotencyKey` field the caller mints, or the workflow ID — which is
per-execution and, when the contract derives it, a function of the payload.

- 5545236: Workflows can derive their **workflow ID** from their input:

```ts
const processOrder = defineWorkflow({
input: OrderSchema,
output: OrderResultSchema,
workflowId: ({ orderId }) => `order-${orderId}`,
startPolicy: "once-per-id",
});
```

`startPolicy` only bites when two starts of the same logical request collide on
one ID, and the ID used to be entirely the caller's — passing
`crypto.randomUUID()` made `"once-per-id"` inert with no diagnostic. A workflow
that declares `workflowId` now derives it from the validated payload on
`startWorkflow` / `executeWorkflow` / `signalWithStart`, and supplying one at
the call site is a type error. Workflows that declare none are unchanged.

`IdempotencyMode` is renamed to `WorkflowStartPolicy` (the old name stays as a
deprecated type alias).

## 8.0.0-beta.8

## 8.0.0-beta.7
Expand Down
2 changes: 1 addition & 1 deletion packages/contract/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@temporal-contract/contract",
"version": "8.0.0-beta.8",
"version": "8.0.0-beta.9",
"description": "Contract builder for temporal-contract",
"keywords": [
"contract",
Expand Down
57 changes: 57 additions & 0 deletions packages/testing/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,62 @@
# @temporal-contract/testing

## 8.0.0-beta.9

### Minor Changes

- 4e47875: Activities can declare an **idempotency key**, derived from their input:

```ts
const chargeCard = defineActivity({
input: z.object({ orderId: z.string(), customerId: z.string(), amount: z.number() }),
output: PaymentSchema,
// Key on what IDENTIFIES the charge, not on what describes it: one customer
// placing two orders of the same value must not collide on one key.
idempotencyKey: ({ orderId }) => `charge:${orderId}`,
});

chargeCard: ({ input, idempotencyKey }) =>
fromPromise(
gateway.charge(input, { idempotencyKey }),
qualifyFailure("CHARGE_FAILED", { expected: GatewayError }),
),
```

Temporal runs activities **at least once**, and nothing in the library helped
with that until now — `idempotency` on a workflow is start deduplication and
says nothing about an activity running twice. Being payload-derived, the key is
stable across activity retries, worker crashes, and a fresh workflow execution
with the same input.

`helpers.idempotencyKey` is typed `string` for an activity that declares one and
`undefined` for one that does not, so reaching for a key that was never declared
is a compile error. `runActivity` hands over the same value.

Good key sources: a business identifier already in the input, a dedicated
`idempotencyKey` field the caller mints, or the workflow ID — which is
per-execution and, when the contract derives it, a function of the payload.

- 2cc0053: `createTimeSkippingContractTest({ contract, workflowsPath, activities })` — the
one-call fixture for the **time-skipping** tier, the Docker-free counterpart to
`createContractTest`. It owns the `TestWorkflowEnvironment`, the workflow bundle
(built once per Vitest worker process), the worker, the `TypedClient` binding,
and the replay-on-finish check, and hands the test `{ worker, client }`.

Previously the tier with the better ergonomics was also the one that needed
Docker: the time-skipping tier only offered `testRig`, which makes the caller
build a bundle and manage the environment. `testRig` stays as the lower-level
seam.

### Patch Changes

- Updated dependencies [4e47875]
- Updated dependencies [8d1359a]
- Updated dependencies [3ed260c]
- Updated dependencies [5545236]
- @temporal-contract/contract@8.0.0-beta.9
- @temporal-contract/worker@8.0.0-beta.9
- @temporal-contract/client@8.0.0-beta.9

## 8.0.0-beta.8

### Patch Changes
Expand Down
8 changes: 4 additions & 4 deletions packages/testing/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@temporal-contract/testing",
"version": "8.0.0-beta.8",
"version": "8.0.0-beta.9",
"description": "Temporal testing utilities",
"keywords": [
"contract",
Expand Down Expand Up @@ -88,9 +88,9 @@
"zod": "catalog:"
},
"peerDependencies": {
"@temporal-contract/client": "^8.0.0-beta.8",
"@temporal-contract/contract": "^8.0.0-beta.8",
"@temporal-contract/worker": "^8.0.0-beta.8",
"@temporal-contract/client": "^8.0.0-beta.9",
"@temporal-contract/contract": "^8.0.0-beta.9",
"@temporal-contract/worker": "^8.0.0-beta.9",
"@temporalio/client": "^1.16.0",
"@temporalio/testing": "^1.16.0",
"@temporalio/worker": "^1.16.0",
Expand Down
56 changes: 56 additions & 0 deletions packages/worker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,61 @@
# @temporal-contract/worker

## 8.0.0-beta.9

### Minor Changes

- 4e47875: Activities can declare an **idempotency key**, derived from their input:

```ts
const chargeCard = defineActivity({
input: z.object({ orderId: z.string(), customerId: z.string(), amount: z.number() }),
output: PaymentSchema,
// Key on what IDENTIFIES the charge, not on what describes it: one customer
// placing two orders of the same value must not collide on one key.
idempotencyKey: ({ orderId }) => `charge:${orderId}`,
});

chargeCard: ({ input, idempotencyKey }) =>
fromPromise(
gateway.charge(input, { idempotencyKey }),
qualifyFailure("CHARGE_FAILED", { expected: GatewayError }),
),
```

Temporal runs activities **at least once**, and nothing in the library helped
with that until now — `idempotency` on a workflow is start deduplication and
says nothing about an activity running twice. Being payload-derived, the key is
stable across activity retries, worker crashes, and a fresh workflow execution
with the same input.

`helpers.idempotencyKey` is typed `string` for an activity that declares one and
`undefined` for one that does not, so reaching for a key that was never declared
is a compile error. `runActivity` hands over the same value.
Comment thread
btravers marked this conversation as resolved.

Good key sources: a business identifier already in the input, a dedicated
`idempotencyKey` field the caller mints, or the workflow ID — which is
per-execution and, when the contract derives it, a function of the payload.
Comment thread
btravers marked this conversation as resolved.

- 8d1359a: `bestEffort(result, onFailure)` — the counterpart to `propagateFailure` for a
non-critical call (a notification, a metric, an audit write). It hands the
failure to `onFailure` and resolves `undefined` instead of ending the workflow,
but **re-raises real cancellation** (`ActivityCancelledError`,
`ChildWorkflowCancelledError`, `WorkflowCancelledError`) so a workflow can no
longer absorb its own cancel by accident. That rule used to live in every
hand-written best-effort fold; it is now structural.

`propagateActivityFailure` is renamed to **`propagateFailure`** — it has always
also handled child-workflow calls and cancellation scopes, and the old name said
otherwise. The old name is **removed**, not aliased: it only ever shipped in 8.0
betas, and this release already renames `idempotency` to `startPolicy` outright.
Rename the import; behaviour is unchanged.

### Patch Changes

- Updated dependencies [4e47875]
- Updated dependencies [5545236]
- @temporal-contract/contract@8.0.0-beta.9

## 8.0.0-beta.8

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/worker/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@temporal-contract/worker",
"version": "8.0.0-beta.8",
"version": "8.0.0-beta.9",
"description": "Worker utilities with unthrown Result/AsyncResult for implementing temporal-contract workflows and activities",
"keywords": [
"contract",
Expand Down
Loading