From fda346bf19c0ae019b237b70edb6555395337d47 Mon Sep 17 00:00:00 2001 From: wangbill Date: Wed, 29 Jul 2026 15:43:21 -0700 Subject: [PATCH 1/2] docs(release): changelog, README, and copilot-instructions updates Split out of #335 as a standalone, independently reviewable change. Documentation-only updates supporting the per-package release: - CHANGELOG.md (root, core + azuremanaged) - packages/azure-functions-durable/CHANGELOG.md (compat) - packages/azure-functions-durable/README.md - .github/copilot-instructions.md No runtime code changes. Content is byte-identical to the CI-green #335 branch at 8501bc0; this is a pure re-partition with no behavior change. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d86f5f69-4e1a-4c1d-b017-5e290c85cc05 --- .github/copilot-instructions.md | 14 ++- CHANGELOG.md | 25 +++++ packages/azure-functions-durable/CHANGELOG.md | 100 +++++++++++++++++- packages/azure-functions-durable/README.md | 18 +++- 4 files changed, 147 insertions(+), 10 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c8c15017..2e177551 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -113,7 +113,7 @@ Task — Base: result, exception, isComplete, isFailed, parent r │ ├── RetryableTask — Policy-driven retries (exponential backoff) │ └── RetryHandlerTask — Custom retry handler function └── CompositeTask — Holds children with parent backlinks - ├── WhenAllTask — Completes when ALL children done; fails fast on first failure + ├── WhenAllTask — Completes when ALL children are terminal (waits for every child) └── WhenAnyTask — Completes when ANY child done ``` @@ -123,11 +123,15 @@ Task — Base: result, exception, isComplete, isFailed, parent r **Important:** `CompositeTask` checks already-complete children in its constructor. A composite task can be **immediately complete upon construction** — callers must handle this. -### WhenAll Fail-Fast Behavior +### WhenAll Wait-All Behavior -`WhenAllTask` marks itself complete on the **first** failed child. Other children may still -be in flight. The `isComplete` guard prevents double-completion, but the mental model is: -one failure = whole task fails immediately, remaining results ignored. +`WhenAllTask` completes only when **every** child is terminal (`_completedTasks == _tasks.length`) — +a failing child does **not** complete it early. This prevents a later failing sibling's `TaskFailed` +from being dropped against an already-terminal instance (issue #301). `_exception` is set only at +completion, so `isFailed` and `isComplete` flip together — otherwise `resume()` (which checks +`isFailed` before `isComplete`) would throw into the generator before the other siblings finish, +re-introducing fail-fast. On failure, all child exceptions are aggregated into an `AggregateError` +whose message inlines each child message. --- diff --git a/CHANGELOG.md b/CHANGELOG.md index a725396a..5faa07b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ ## Upcoming +### Breaking changes + +- **`whenAll` no longer fails fast.** A `whenAll` task — and therefore the Durable Functions compat + `context.df.Task.all()`, which forwards straight to it — now completes only after **every** child + is terminal, instead of the moment the first child fails. Two user-visible effects: (1) **timing** — + the orchestrator resumes past the `whenAll` only once all siblings finish, not at the first failure; + (2) **error type** — on failure it throws a JS-native `AggregateError` (`.errors` populated, message + of the form `" of tasks in the whenAll failed: "`) instead of + re-throwing the first child's own exception. This fixes a lost-failure bug where a later failing + sibling was dropped against an already-terminal `whenAll` + ([#301](https://github.com/microsoft/durabletask-js/issues/301)). Fan-out/fan-in is the canonical + Durable Functions pattern, so review any `Task.all()` error handling that relied on early completion + or on catching a single child error. +- **Default sub-orchestration instance IDs now derive from the parent's execution ID.** When a + sub-orchestration is scheduled **without** an explicit `instanceId`, the auto-generated ID changed + from `${parentInstanceId}:${suffix}` to `${parentExecutionId}:${suffix}` (`suffix` is a 4-hex-digit + sequence number). Explicit `instanceId`s are untouched, and there is a **fallback**: backends that + do not populate an execution ID still get the legacy `${parentInstanceId}:${suffix}` form, so this + is not an unconditional format change. It fixes a continue-as-new collision — the sequence number + resets each work item and the parent instance ID is stable across generations, so a default-ID + sub-orchestration scheduled after continue-as-new (e.g. `callHttp`) re-derived the previous + generation's ID and failed with "instance already exists" — and keeps the ID constant-length + (~37 chars) at any nesting depth instead of concatenating every ancestor's ID, which would breach + the Durable Task Scheduler 100-character instance-ID limit at ~2 levels of nesting. + ### New ### Fixes diff --git a/packages/azure-functions-durable/CHANGELOG.md b/packages/azure-functions-durable/CHANGELOG.md index 00858aea..60caa077 100644 --- a/packages/azure-functions-durable/CHANGELOG.md +++ b/packages/azure-functions-durable/CHANGELOG.md @@ -1,5 +1,99 @@ -# Changelog +## Upcoming -## TBD +First preview of the rewritten `durable-functions` provider. This is a **preview release**: it is +published under the `preview` npm dist-tag, and APIs may change before the stable `4.0.0`. -- Details to be finalized at release time. +Install with: + +```bash +npm install durable-functions@preview +``` + +### Why this is a new major version + +v4 is a rewrite on top of `@microsoft/durabletask-js`: replay, activities, entities, retries, and +instance-management all come from that shared core, so behavior matches the .NET, Python, and Java +Durable providers. Durable work items flow over a single gRPC channel instead of the legacy +out-of-process HTTP protocol -- the same consolidation `durabletask-python` shipped as +`azure-functions-durable` 2.0.0b1. It supersedes the legacy `durable-functions` v3 +([Azure/azure-functions-durable-js](https://github.com/Azure/azure-functions-durable-js)). Classic +`context.df.*` orchestrators and entities keep working through a compatibility layer, but several +surfaces changed (see below). + +### Requirements + +- **Node.js >= 22** (v3 supported Node 18 and 20; those are no longer supported). +- **Functions extension bundle** -- GA `Microsoft.Azure.Functions.ExtensionBundle` `[4.36.0, 5.0.0)` + or Preview `Microsoft.Azure.Functions.ExtensionBundle.Preview` `[4.29.0, 5.0.0)`. The provider needs + a durable extension that starts a gRPC server for Node + ([Azure/azure-functions-durable-extension#3260](https://github.com/Azure/azure-functions-durable-extension/pull/3260)); + on an earlier bundle the app starts normally but every orchestration starter hangs and times out + after ~60 s with no error. A fresh app on the default GA range works -- the trap is an explicit pin + at or below 4.32.0. GA and Preview version numbers are NOT comparable across feeds. + +### Underlying packages + +- `@microsoft/durabletask-js` `0.4.0` (exact pin). +- `@azure/functions` `^4.16.1`. +- `@azure/identity` `^4.0.0` as an **optional** peer dependency -- needed only for a `callHttp` + `tokenSource`, and not installed automatically. + +### Breaking changes from durable-functions v3 + +- **Node.js >= 22** is required. +- **Classic contexts no longer extend `InvocationContext`** -- only `df` plus replay-safe log helpers + are available (the classic entity context is just `{ df }`). +- **Task result shape follows the core SDK** -- use `isComplete` / `isFailed` / `getResult()` instead + of v3's `isCompleted` / `isFaulted` / `result`. `context.df.createTimer(...)` still returns a + cancelable `TimerTask`. +- **Entity locking moved to the core context.** `context.df.lock` / `context.df.isLocked` and the + `DurableLock` / `LockState` / `LockingRulesViolationError` exports are removed and will **not** be + restored. Acquire locks with `context.entities.lockEntities(...)` (returns a `LockHandle` with + `release()`) and query with `context.entities.isInCriticalSection()`. +- **A plain non-generator classic orchestrator is no longer supported.** A synchronous, + single-argument, non-generator function is now treated as core-native and receives the core + `OrchestrationContext` (which has no `.df`); sync generators (`function*`) using `context.df.*` are + unaffected. +- **Some v3 top-level exports were removed** -- `DummyOrchestrationContext`, `DummyEntityContext`, and + the entity-lock types above. `TaskFailedError` is re-exported from the core SDK, and aggregate + failures now surface as JS-native `AggregateError`; use the core `TestOrchestrationWorker` / + `TestOrchestrationClient` for orchestration unit tests. + +### Added + +- **`context.df.callHttp(...)` is restored** as a worker-side durable HTTP call. It accepts the v3 + `CallHttpOptions` (`method`, `url`, `body`, `headers`, `tokenSource`, `enablePolling`) and returns a + `Task` (`{ statusCode, headers, content }`), including automatic `202 Accepted` + polling that honors `Retry-After` via durable timers. Caveats: + - **Trust-boundary change** -- in v3 the Functions **host** extension ran the request; here it runs + as a durable **activity inside your worker** (via `fetch`), so egress path, source identity, and + firewall/VNet rules follow the worker process -- re-verify IP allow-lists. + - **Cross-origin `202` poll credentials are stripped** -- when the callee-controlled `Location` + points to a different origin, the poll drops `Authorization`, `Cookie`, and the `tokenSource`; + `x-functions-key` is **always** dropped; same-origin polls still forward headers and the + `tokenSource`. Mirrors the .NET extension + ([Azure/azure-functions-durable-extension#3443](https://github.com/Azure/azure-functions-durable-extension/pull/3443)). + - **The initial request follows redirects with `fetch` defaults**, which drop `Authorization` / + `Cookie` across origins but **not** custom credential headers like `x-functions-key`. + - **Default poll interval is 30 s** when a `202` carries no usable `Retry-After`. + - **Known incompatibility** -- a body on a `GET`/`HEAD` request throws (the Fetch Standard forbids + it, though v3, the .NET extension, and Python all send it). + - **Known incompatibility** -- `DurableHttpResponse` is a plain object, not a class, so + `response.getHeader(name)` is unavailable and existing calls **fail at runtime**; index + `response.headers[...]` by lower-cased key instead. + - A managed-identity `tokenSource` needs the optional `@azure/identity` package or it throws a clear + error. +- **`app.client.*` starter helpers** (`http`, `timer`, `storageBlob`, `storageQueue`, + `serviceBusQueue`, `serviceBusTopic`, `eventHub`, `eventGrid`, `cosmosDB`, `generic`) register a + normal trigger and inject the client as the handler's second argument, so + `(trigger, client, context)` works without manually wiring `df.input.durableClient()` + + `df.getClient(context)`. +- **`client.startNew()` supports the `version` option.** +- **`client.getStatus()` keeps the v3 shape** -- a non-optional `DurableOrchestrationStatus` that + throws when the instance is missing; `showInput` suppresses only the top-level input, `showHistory` + populates `history`, and `showHistoryOutput` toggles the per-entry input/result payloads; `history` + entries are core `HistoryEvent`s (v3 typed it `Array`). + +### Known limitations + +- This is a preview release; the API surface may change before `4.0.0`. diff --git a/packages/azure-functions-durable/README.md b/packages/azure-functions-durable/README.md index 3d642a08..3d2265f3 100644 --- a/packages/azure-functions-durable/README.md +++ b/packages/azure-functions-durable/README.md @@ -42,8 +42,8 @@ changed: `context.df.isLocked()` and the `DurableLock` / `LockState` / `LockingRulesViolationError` exports are removed. Acquire locks with the core `context.entities.lockEntities(...entityIds)` (returns a `LockHandle` — call `release()`, ideally in a `finally`) and query with - `context.entities.isInCriticalSection()`. Restoring the v3 `df.lock` / `isLocked` surface is tracked - in [#317](https://github.com/microsoft/durabletask-js/issues/317). + `context.entities.isInCriticalSection()`. The v3 `df.lock` / `isLocked` surface is **not supported + and not planned** — there is no tracking issue. - **`context.df.callHttp(...)` is restored** as a worker-side durable HTTP call ([#318](https://github.com/microsoft/durabletask-js/issues/318)) — though **not** as a drop-in, fully v3-equivalent replacement: the known incompatibilities and behavior differences listed below are @@ -106,6 +106,20 @@ changed: sync **generators** (`function*`) using `context.df.*` — are unaffected; convert any non-generator classic orchestrator to generator form, or to the core-native `ctx.*` API. +## Requirements + +This provider reaches the Durable Task backend over the Functions host's **gRPC** channel, which +exists only in newer durable-extension builds. Your app's `host.json` must reference one of: + +- GA bundle — `Microsoft.Azure.Functions.ExtensionBundle` at **`[4.36.0, 5.0.0)`**, or +- Preview bundle — `Microsoft.Azure.Functions.ExtensionBundle.Preview` at **`[4.29.0, 5.0.0)`**. + +Earlier GA v4 bundles (**<= 4.32.0**) predate that gRPC endpoint, so orchestration starters **hang +for ~60 seconds and time out with no error**. A fresh app on the default GA range (`[4.*, 5.0.0)`) +resolves to the latest GA (>= 4.36.0) and works — the trap is an **explicit** pin at or below +4.32.0. GA and Preview are independent feeds whose version numbers are **not comparable** (a higher +Preview number does not imply the GA bundle contains the same code). + ## Getting started ```typescript From a415bc33f1efa9cf66796b796ddb5a263c93a343 Mon Sep 17 00:00:00 2001 From: wangbill Date: Thu, 30 Jul 2026 11:08:37 -0700 Subject: [PATCH 2/2] docs(azure-functions-durable): consolidate preview info into README; revert changelogs per owner review Per repo-owner review on PR #339, the compat and root changelogs must not carry hand-authored narrative -- the release workflow/script generates their commit/message/PR entries at release time. Revert both to the origin/main baseline (root CHANGELOG.md and packages/azure-functions-durable/CHANGELOG.md are now byte-identical to origin/main; the compat file returns to the legacy `# Changelog` / `## TBD` skeleton that #337's updated script normalizes). Compat README (packages/azure-functions-durable/README.md): - Fix the entity-locking migration note. The classic `{ df, log }` context does not expose `entities`, so an orchestrator that needs locks must migrate to the core-native orchestrator/context shape first, then use `context.entities.lockEntities(...)` / `context.entities.isInCriticalSection()`. Link #317 (closed, not planned) as the decision record and drop the false "there is no tracking issue" claim. - Remove the verbose GA/Preview cross-feed comparison sentence from Requirements, keeping the required bundle ranges and the <= 4.32.0 gRPC warning. - Consolidate the preview/install guidance into `## Status`: the v4 provider is in preview under the `preview` npm dist-tag, install with `durable-functions@preview`, APIs may change before the GA `4.0.0` release. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d86f5f69-4e1a-4c1d-b017-5e290c85cc05 --- CHANGELOG.md | 25 ----- packages/azure-functions-durable/CHANGELOG.md | 100 +----------------- packages/azure-functions-durable/README.md | 18 ++-- 3 files changed, 14 insertions(+), 129 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5faa07b5..a725396a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,30 +1,5 @@ ## Upcoming -### Breaking changes - -- **`whenAll` no longer fails fast.** A `whenAll` task — and therefore the Durable Functions compat - `context.df.Task.all()`, which forwards straight to it — now completes only after **every** child - is terminal, instead of the moment the first child fails. Two user-visible effects: (1) **timing** — - the orchestrator resumes past the `whenAll` only once all siblings finish, not at the first failure; - (2) **error type** — on failure it throws a JS-native `AggregateError` (`.errors` populated, message - of the form `" of tasks in the whenAll failed: "`) instead of - re-throwing the first child's own exception. This fixes a lost-failure bug where a later failing - sibling was dropped against an already-terminal `whenAll` - ([#301](https://github.com/microsoft/durabletask-js/issues/301)). Fan-out/fan-in is the canonical - Durable Functions pattern, so review any `Task.all()` error handling that relied on early completion - or on catching a single child error. -- **Default sub-orchestration instance IDs now derive from the parent's execution ID.** When a - sub-orchestration is scheduled **without** an explicit `instanceId`, the auto-generated ID changed - from `${parentInstanceId}:${suffix}` to `${parentExecutionId}:${suffix}` (`suffix` is a 4-hex-digit - sequence number). Explicit `instanceId`s are untouched, and there is a **fallback**: backends that - do not populate an execution ID still get the legacy `${parentInstanceId}:${suffix}` form, so this - is not an unconditional format change. It fixes a continue-as-new collision — the sequence number - resets each work item and the parent instance ID is stable across generations, so a default-ID - sub-orchestration scheduled after continue-as-new (e.g. `callHttp`) re-derived the previous - generation's ID and failed with "instance already exists" — and keeps the ID constant-length - (~37 chars) at any nesting depth instead of concatenating every ancestor's ID, which would breach - the Durable Task Scheduler 100-character instance-ID limit at ~2 levels of nesting. - ### New ### Fixes diff --git a/packages/azure-functions-durable/CHANGELOG.md b/packages/azure-functions-durable/CHANGELOG.md index 60caa077..00858aea 100644 --- a/packages/azure-functions-durable/CHANGELOG.md +++ b/packages/azure-functions-durable/CHANGELOG.md @@ -1,99 +1,5 @@ -## Upcoming +# Changelog -First preview of the rewritten `durable-functions` provider. This is a **preview release**: it is -published under the `preview` npm dist-tag, and APIs may change before the stable `4.0.0`. +## TBD -Install with: - -```bash -npm install durable-functions@preview -``` - -### Why this is a new major version - -v4 is a rewrite on top of `@microsoft/durabletask-js`: replay, activities, entities, retries, and -instance-management all come from that shared core, so behavior matches the .NET, Python, and Java -Durable providers. Durable work items flow over a single gRPC channel instead of the legacy -out-of-process HTTP protocol -- the same consolidation `durabletask-python` shipped as -`azure-functions-durable` 2.0.0b1. It supersedes the legacy `durable-functions` v3 -([Azure/azure-functions-durable-js](https://github.com/Azure/azure-functions-durable-js)). Classic -`context.df.*` orchestrators and entities keep working through a compatibility layer, but several -surfaces changed (see below). - -### Requirements - -- **Node.js >= 22** (v3 supported Node 18 and 20; those are no longer supported). -- **Functions extension bundle** -- GA `Microsoft.Azure.Functions.ExtensionBundle` `[4.36.0, 5.0.0)` - or Preview `Microsoft.Azure.Functions.ExtensionBundle.Preview` `[4.29.0, 5.0.0)`. The provider needs - a durable extension that starts a gRPC server for Node - ([Azure/azure-functions-durable-extension#3260](https://github.com/Azure/azure-functions-durable-extension/pull/3260)); - on an earlier bundle the app starts normally but every orchestration starter hangs and times out - after ~60 s with no error. A fresh app on the default GA range works -- the trap is an explicit pin - at or below 4.32.0. GA and Preview version numbers are NOT comparable across feeds. - -### Underlying packages - -- `@microsoft/durabletask-js` `0.4.0` (exact pin). -- `@azure/functions` `^4.16.1`. -- `@azure/identity` `^4.0.0` as an **optional** peer dependency -- needed only for a `callHttp` - `tokenSource`, and not installed automatically. - -### Breaking changes from durable-functions v3 - -- **Node.js >= 22** is required. -- **Classic contexts no longer extend `InvocationContext`** -- only `df` plus replay-safe log helpers - are available (the classic entity context is just `{ df }`). -- **Task result shape follows the core SDK** -- use `isComplete` / `isFailed` / `getResult()` instead - of v3's `isCompleted` / `isFaulted` / `result`. `context.df.createTimer(...)` still returns a - cancelable `TimerTask`. -- **Entity locking moved to the core context.** `context.df.lock` / `context.df.isLocked` and the - `DurableLock` / `LockState` / `LockingRulesViolationError` exports are removed and will **not** be - restored. Acquire locks with `context.entities.lockEntities(...)` (returns a `LockHandle` with - `release()`) and query with `context.entities.isInCriticalSection()`. -- **A plain non-generator classic orchestrator is no longer supported.** A synchronous, - single-argument, non-generator function is now treated as core-native and receives the core - `OrchestrationContext` (which has no `.df`); sync generators (`function*`) using `context.df.*` are - unaffected. -- **Some v3 top-level exports were removed** -- `DummyOrchestrationContext`, `DummyEntityContext`, and - the entity-lock types above. `TaskFailedError` is re-exported from the core SDK, and aggregate - failures now surface as JS-native `AggregateError`; use the core `TestOrchestrationWorker` / - `TestOrchestrationClient` for orchestration unit tests. - -### Added - -- **`context.df.callHttp(...)` is restored** as a worker-side durable HTTP call. It accepts the v3 - `CallHttpOptions` (`method`, `url`, `body`, `headers`, `tokenSource`, `enablePolling`) and returns a - `Task` (`{ statusCode, headers, content }`), including automatic `202 Accepted` - polling that honors `Retry-After` via durable timers. Caveats: - - **Trust-boundary change** -- in v3 the Functions **host** extension ran the request; here it runs - as a durable **activity inside your worker** (via `fetch`), so egress path, source identity, and - firewall/VNet rules follow the worker process -- re-verify IP allow-lists. - - **Cross-origin `202` poll credentials are stripped** -- when the callee-controlled `Location` - points to a different origin, the poll drops `Authorization`, `Cookie`, and the `tokenSource`; - `x-functions-key` is **always** dropped; same-origin polls still forward headers and the - `tokenSource`. Mirrors the .NET extension - ([Azure/azure-functions-durable-extension#3443](https://github.com/Azure/azure-functions-durable-extension/pull/3443)). - - **The initial request follows redirects with `fetch` defaults**, which drop `Authorization` / - `Cookie` across origins but **not** custom credential headers like `x-functions-key`. - - **Default poll interval is 30 s** when a `202` carries no usable `Retry-After`. - - **Known incompatibility** -- a body on a `GET`/`HEAD` request throws (the Fetch Standard forbids - it, though v3, the .NET extension, and Python all send it). - - **Known incompatibility** -- `DurableHttpResponse` is a plain object, not a class, so - `response.getHeader(name)` is unavailable and existing calls **fail at runtime**; index - `response.headers[...]` by lower-cased key instead. - - A managed-identity `tokenSource` needs the optional `@azure/identity` package or it throws a clear - error. -- **`app.client.*` starter helpers** (`http`, `timer`, `storageBlob`, `storageQueue`, - `serviceBusQueue`, `serviceBusTopic`, `eventHub`, `eventGrid`, `cosmosDB`, `generic`) register a - normal trigger and inject the client as the handler's second argument, so - `(trigger, client, context)` works without manually wiring `df.input.durableClient()` + - `df.getClient(context)`. -- **`client.startNew()` supports the `version` option.** -- **`client.getStatus()` keeps the v3 shape** -- a non-optional `DurableOrchestrationStatus` that - throws when the instance is missing; `showInput` suppresses only the top-level input, `showHistory` - populates `history`, and `showHistoryOutput` toggles the per-entry input/result payloads; `history` - entries are core `HistoryEvent`s (v3 typed it `Array`). - -### Known limitations - -- This is a preview release; the API surface may change before `4.0.0`. +- Details to be finalized at release time. diff --git a/packages/azure-functions-durable/README.md b/packages/azure-functions-durable/README.md index 3d2265f3..801cf015 100644 --- a/packages/azure-functions-durable/README.md +++ b/packages/azure-functions-durable/README.md @@ -40,10 +40,13 @@ changed: **`client.startNew()` supports the `version` option.** - **Entity locking / critical sections moved to the core context.** v3's `context.df.lock(...)` / `context.df.isLocked()` and the `DurableLock` / `LockState` / `LockingRulesViolationError` exports - are removed. Acquire locks with the core `context.entities.lockEntities(...entityIds)` (returns a - `LockHandle` — call `release()`, ideally in a `finally`) and query with - `context.entities.isInCriticalSection()`. The v3 `df.lock` / `isLocked` surface is **not supported - and not planned** — there is no tracking issue. + are removed. Locks live on the core-native `context.entities` surface, which the classic + `{ df, log }` context does **not** expose — an orchestrator that needs locks must first migrate to + the core-native orchestrator/context shape, then acquire locks with + `context.entities.lockEntities(...entityIds)` (returns a `LockHandle` — call `release()`, ideally + in a `finally`) and query with `context.entities.isInCriticalSection()`. Reintroducing the v3 + `df.lock` / `isLocked` surface is **not supported and not planned** + ([#317](https://github.com/microsoft/durabletask-js/issues/317), closed as not planned). - **`context.df.callHttp(...)` is restored** as a worker-side durable HTTP call ([#318](https://github.com/microsoft/durabletask-js/issues/318)) — though **not** as a drop-in, fully v3-equivalent replacement: the known incompatibilities and behavior differences listed below are @@ -117,8 +120,7 @@ exists only in newer durable-extension builds. Your app's `host.json` must refer Earlier GA v4 bundles (**<= 4.32.0**) predate that gRPC endpoint, so orchestration starters **hang for ~60 seconds and time out with no error**. A fresh app on the default GA range (`[4.*, 5.0.0)`) resolves to the latest GA (>= 4.36.0) and works — the trap is an **explicit** pin at or below -4.32.0. GA and Preview are independent feeds whose version numbers are **not comparable** (a higher -Preview number does not imply the GA bundle contains the same code). +4.32.0. ## Getting started @@ -184,4 +186,6 @@ are `@deprecated`): ## Status -This package is an early preview (`4.0.0`); APIs may change before the stable release. +This rewritten `durable-functions` v4 provider is in **preview**, published under the `preview` npm +dist-tag — install it with `npm install durable-functions@preview`. APIs may change before the +GA `4.0.0` release.