Skip to content
Open
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
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,23 @@

This repo contains a JavaScript/TypeScript SDK for use with the [Azure Durable Task Scheduler](https://github.com/Azure/Durable-Task-Scheduler). With this SDK, you can define, schedule, and manage durable orchestrations using ordinary TypeScript/JavaScript code.

> Note that this SDK is **not** currently compatible with [Azure Durable Functions](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview). If you are looking for a JavaScript SDK for Azure Durable Functions, please see [this repo](https://github.com/Azure/azure-functions-durable-js).
> Note that this SDK does **not** provide the [Azure Durable Functions](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview) programming model, decorators, or worker-indexing metadata. If you are looking for a JavaScript SDK for Azure Durable Functions, please see [this repo](https://github.com/Azure/azure-functions-durable-js). This package exposes low-level TaskHubSidecarService gRPC/protobuf helpers that host integrations can reuse; those helpers follow this package's Node.js 22+ requirement.

## Low-level host integration APIs

Host integrations that already own trigger metadata and transport encoding can depend on the `@microsoft/durabletask-js` package directly. `TaskHubGrpcWorker` registers orchestrators, activities, and entities, and can process raw TaskHubSidecarService protobuf payloads without starting the long-running gRPC worker loop:

```typescript
const worker = new TaskHubGrpcWorker();
worker.addOrchestrator(myOrchestrator);
worker.addActivity(myActivity);
worker.addEntity(myEntity);

const orchestrationResponseBytes = await worker.processOrchestratorRequest(orchestrationRequestBytes);
const entityResponseBytes = await worker.processEntityBatchRequest(entityBatchRequestBytes);
```

`TaskHubGrpcClient` already exposes orchestration start/query/event/terminate/suspend/resume/purge APIs and entity signal/read/query/clean APIs through its existing `hostAddress` and `metadataGenerator` options. Host integrations that need task-hub routing metadata should provide it through `metadataGenerator`, keeping host-specific metadata policy outside the core client. Azure-managed scheduler connection strings remain in `@microsoft/durabletask-js-azuremanaged`.

## npm packages

Expand Down
72 changes: 72 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions packages/azure-functions-durable/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Changelog

## 4.0.0-alpha.0

- Added the initial gRPC-consolidated Azure Functions Durable provider package.
- Added `DurableFunctionsClient`, a direct `TaskHubGrpcClient` subclass for host-provided gRPC client bindings.
- Added Functions HTTP management payload helpers, worker byte-processing adapter, and `durableRequiresGrpc` binding metadata helper.
21 changes: 21 additions & 0 deletions packages/azure-functions-durable/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) Microsoft Corporation.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
81 changes: 81 additions & 0 deletions packages/azure-functions-durable/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# durable-functions

Azure Functions Durable provider for the Durable Task JavaScript SDK.

This package is the gRPC-consolidated Durable Functions provider for JavaScript. It builds on `@microsoft/durabletask-js` and is intended to supersede the legacy `durable-functions` package at a new major version.

## Phase 1 scope

This preview includes the low-level host integration pieces:

- `DurableFunctionsClient`, a direct subclass of `TaskHubGrpcClient`.
- HTTP management payload helpers for Durable HTTP starter responses.
- `DurableFunctionsWorker`, which accepts base64-encoded protobuf work-item payloads from the Functions host and delegates execution to the core worker byte processors.
- `addDurableGrpcMetadata`, which stamps `durableRequiresGrpc: true` onto durable trigger and client binding metadata.

The full Durable Functions JavaScript authoring model is not included yet. Use `@microsoft/durabletask-js` APIs directly for orchestrator, activity, and entity implementations in this phase.

## Client binding

The Functions host passes a JSON client-binding payload to the app. Construct the client from that payload:

```typescript
import { DurableFunctionsClient } from "durable-functions";

const client = new DurableFunctionsClient(clientBindingJson);
const instanceId = await client.scheduleNewOrchestration("hello", { name: "Durable" });
return client.createCheckStatusResponse(request, instanceId);
```

`DurableFunctionsClient` extends `TaskHubGrpcClient`, so orchestration and entity management methods come from the core SDK by inheritance. The only Functions-specific public helpers are:

- `createCheckStatusResponse(request, instanceId)`
- `createHttpManagementPayload(request, instanceId)`

Both helpers derive the management endpoint from the incoming HTTP request origin:

```text
{scheme}://{host}/runtime/webhooks/durabletask/instances/{instanceId}
```

## gRPC metadata

The client mirrors the Python Azure Functions Durable provider interceptor by adding per-call gRPC metadata:

- `taskhub`: the task hub name from the host client-binding payload.
- `x-user-agent`: the package user agent. gRPC reserves `user-agent`, so this package uses `x-user-agent`.

The host-provided `requiredQueryStringParameters` value is used for HTTP management URLs. Python PR #155 passes it to the interceptor constructor but does not emit it as gRPC metadata; this package keeps the same behavior.

## Serialization

This package intentionally does not port Python's `DEFAULT_FUNCTIONS_DATA_CONVERTER`. The JavaScript core client and worker already serialize payloads at the protobuf string boundary with plain `JSON.stringify` and `JSON.parse`, which matches the Azure Functions JavaScript worker's plain JSON payload contract for this gRPC path.

## Worker adapter

`DurableFunctionsWorker` extends `TaskHubGrpcWorker` and adds base64 helpers for the Functions host's middleware-passthrough payloads:

```typescript
const worker = new DurableFunctionsWorker();
worker.addOrchestrator(myOrchestrator);

const encodedResponse = await worker.handleOrchestratorRequest(encodedRequest);
```

## Phase 2 plan

Phase 2 will port the full Durable Functions JavaScript authoring surface onto the core SDK. Planned work:

- `src/app.ts`: add `DFApp` and `Blueprint` equivalents that mirror Python `decorators/durable_app.py` and register Azure Functions v4 handlers.
- `src/decorators/`: add durable trigger and durable client binding helpers that call `addDurableGrpcMetadata` and emit `durableRequiresGrpc: true`.
- `src/orchestrator.ts`: add an `Orchestrator` wrapper that converts Functions invocation payloads into `DurableFunctionsWorker.handleOrchestratorRequest` calls.
- `src/entity.ts`: add entity handler glue over `DurableFunctionsWorker.handleEntityBatchRequest`.
- `src/input.ts`: add a durable client input helper that constructs `DurableFunctionsClient` from the host binding payload.
- `test/authoring/`: add parity tests for `DFApp`, `Blueprint`, orchestration trigger registration, entity trigger registration, durable client input registration, and generated binding metadata.

Open questions for the Functions extension team:

- Confirm the exact JavaScript client-binding payload field set and whether `rpcBaseUrl` is always an absolute URL with scheme.
- Confirm whether `requiredQueryStringParameters` always includes any required `taskHub` and `connection` HTTP routing parameters. This Phase 1 port mirrors Python PR #155 and appends only that host-provided string to management URLs.
- Confirm whether `requiredQueryStringParameters` should ever be emitted as gRPC metadata; Python stores it on the interceptor but only sends `taskhub` and `x-user-agent`.
- Confirm whether the local gRPC sidecar remains plaintext-only for JavaScript (`useTLS: false`) in all supported Functions hosting modes.
12 changes: 12 additions & 0 deletions packages/azure-functions-durable/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
testMatch: ["**/test/**/*.spec.ts"],
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
transform: {
"^.+\\.ts$": "ts-jest",
},
moduleNameMapper: {
"^@microsoft/durabletask-js$": "<rootDir>/../durabletask-js/src/index.ts",
},
};
63 changes: 63 additions & 0 deletions packages/azure-functions-durable/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"name": "durable-functions",
"version": "4.0.0-alpha.0",
"description": "Azure Functions Durable provider for the Durable Task JavaScript SDK",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"require": "./dist/index.js",
"import": "./dist/index.js"
}
},
"files": [
"dist",
"LICENSE",
"README.md",
"CHANGELOG.md"
],
"scripts": {
"clean": "node -e \"require('fs').rmSync('dist', {recursive:true, force:true})\"",
"prebuild": "node -p \"'// Auto-generated by prebuild\\nexport const SDK_VERSION = ' + JSON.stringify(require('./package.json').version) + ';\\nexport const SDK_PACKAGE_NAME = ' + JSON.stringify(require('./package.json').name) + ';'\" > src/version.ts",
"build:core": "npm run build -w @microsoft/durabletask-js",
"build": "npm run prebuild && npm run clean && npm run build:core && tsc -p tsconfig.build.json",
"test": "jest --runInBand --detectOpenHandles",
"test:unit": "jest test/unit --runInBand --detectOpenHandles",
"prepublishOnly": "npm run build && npm run test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/microsoft/durabletask-js.git",
"directory": "packages/azure-functions-durable"
},
"keywords": [
"azure-functions",
"durable-functions",
"durabletask",
"orchestration",
"workflow",
"grpc"
],
"author": "Microsoft",
"license": "MIT",
"bugs": {
"url": "https://github.com/microsoft/durabletask-js/issues"
},
"homepage": "https://github.com/microsoft/durabletask-js/tree/main/packages/azure-functions-durable#readme",
"engines": {
"node": ">=22.0.0"
},
"dependencies": {
"@azure/functions": "^4.16.1",
"@grpc/grpc-js": "^1.14.4",
"@microsoft/durabletask-js": "0.3.0"
},
"devDependencies": {
"@types/jest": "^29.5.1",
"@types/node": "^18.16.1",
"jest": "^29.5.0",
"ts-jest": "^29.1.0",
"typescript": "^5.0.4"
}
}
Loading
Loading