v3.x 37332e2de5a0
194 files
710.1 KB
148.1k tokens
Showing preview only (760K chars total). The displayed content is truncated. Use the JSON API for full output.
Repository: Azure/azure-functions-durable-js
Branch: v3.x
Commit: 37332e2de5a0
Files: 194
Total size: 710.1 KB

Directory structure:
gitextract_0at6gbtx/

├── .azuredevops/
│   └── dependabot.yml
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── new-release-template.md
│   ├── fabricbot.json
│   └── workflows/
│       └── codeQL.yml
├── .gitignore
├── .prettierrc
├── .vscode/
│   ├── extensions.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── azure-pipelines/
│   ├── code-mirror.yml
│   ├── official-build.yml
│   ├── public-build.yml
│   ├── release.yml
│   └── templates/
│       ├── build.yml
│       └── test.yml
├── es-metadata.yml
├── package.json
├── samples-js/
│   ├── .funcignore
│   ├── .gitignore
│   ├── functions/
│   │   ├── backupSiteContent.js
│   │   ├── callActivityWithRetry.js
│   │   ├── callSubOrchestratorWithRetry.js
│   │   ├── cancelTimer.js
│   │   ├── continueAsNewCounter.js
│   │   ├── counter.js
│   │   ├── httpStart.js
│   │   ├── httpSyncStart.js
│   │   ├── listAzureSubscriptions.js
│   │   ├── sayHello.js
│   │   ├── smsPhoneVerification.js
│   │   └── weatherMonitor.js
│   ├── host.json
│   └── package.json
├── samples-ts/
│   ├── .funcignore
│   ├── .gitignore
│   ├── .vscode/
│   │   ├── extensions.json
│   │   ├── launch.json
│   │   ├── settings.json
│   │   └── tasks.json
│   ├── functions/
│   │   ├── backupSiteContent.ts
│   │   ├── callActivityWithRetry.ts
│   │   ├── callSubOrchestratorWithRetry.ts
│   │   ├── cancelTimer.ts
│   │   ├── continueAsNewCounter.ts
│   │   ├── counter.ts
│   │   ├── httpStart.ts
│   │   ├── httpSyncStart.ts
│   │   ├── listAzureSubscriptions.ts
│   │   ├── orchestrationVersion.ts
│   │   ├── sayHello.ts
│   │   ├── smsPhoneVerification.ts
│   │   └── weatherMonitor.ts
│   ├── host.json
│   ├── package.json
│   └── tsconfig.json
├── src/
│   ├── Constants.ts
│   ├── ManagedIdentityTokenSource.ts
│   ├── RetryOptions.ts
│   ├── actions/
│   │   ├── ActionType.ts
│   │   ├── CallActivityAction.ts
│   │   ├── CallActivityWithRetryAction.ts
│   │   ├── CallEntityAction.ts
│   │   ├── CallHttpAction.ts
│   │   ├── CallSubOrchestratorAction.ts
│   │   ├── CallSubOrchestratorWithRetryAction.ts
│   │   ├── ContinueAsNewAction.ts
│   │   ├── CreateTimerAction.ts
│   │   ├── ExternalEventType.ts
│   │   ├── IAction.ts
│   │   ├── SignalEntityAction.ts
│   │   ├── WaitForExternalEventAction.ts
│   │   ├── WhenAllAction.ts
│   │   └── WhenAnyAction.ts
│   ├── app.ts
│   ├── client.ts
│   ├── durableClient/
│   │   ├── DurableClient.ts
│   │   ├── OrchestrationClientInputData.ts
│   │   ├── PurgeHistoryResult.ts
│   │   └── getClient.ts
│   ├── entities/
│   │   ├── DurableEntityBindingInfo.ts
│   │   ├── DurableLock.ts
│   │   ├── Entity.ts
│   │   ├── EntityId.ts
│   │   ├── EntityState.ts
│   │   ├── EntityStateResponse.ts
│   │   ├── LockState.ts
│   │   ├── OperationResult.ts
│   │   ├── RequestMessage.ts
│   │   ├── ResponseMessage.ts
│   │   └── Signal.ts
│   ├── error/
│   │   ├── AggregatedError.ts
│   │   ├── DurableError.ts
│   │   └── OrchestrationFailureError.ts
│   ├── history/
│   │   ├── EventRaisedEvent.ts
│   │   ├── EventSentEvent.ts
│   │   ├── ExecutionStartedEvent.ts
│   │   ├── HistoryEvent.ts
│   │   ├── HistoryEventOptions.ts
│   │   ├── HistoryEventType.ts
│   │   ├── OrchestratorCompletedEvent.ts
│   │   ├── OrchestratorStartedEvent.ts
│   │   ├── SubOrchestrationInstanceCompletedEvent.ts
│   │   ├── SubOrchestrationInstanceCreatedEvent.ts
│   │   ├── SubOrchestrationInstanceFailedEvent.ts
│   │   ├── TaskCompletedEvent.ts
│   │   ├── TaskFailedEvent.ts
│   │   ├── TaskScheduledEvent.ts
│   │   ├── TimerCreatedEvent.ts
│   │   └── TimerFiredEvent.ts
│   ├── http/
│   │   ├── DurableHttpRequest.ts
│   │   ├── DurableHttpResponse.ts
│   │   ├── HttpCreationPayload.ts
│   │   └── HttpManagementPayload.ts
│   ├── index.ts
│   ├── input.ts
│   ├── orchestrations/
│   │   ├── DurableOrchestrationBindingInfo.ts
│   │   ├── DurableOrchestrationContext.ts
│   │   ├── DurableOrchestrationStatus.ts
│   │   ├── IOrchestratorState.ts
│   │   ├── OrchestrationRuntimeStatus.ts
│   │   ├── Orchestrator.ts
│   │   ├── OrchestratorState.ts
│   │   ├── ReplaySchema.ts
│   │   └── TaskOrchestrationExecutor.ts
│   ├── task/
│   │   ├── AtomicTask.ts
│   │   ├── CallHttpWithPollingTask.ts
│   │   ├── CompoundTask.ts
│   │   ├── DFTask.ts
│   │   ├── DFTimerTask.ts
│   │   ├── LongTimerTask.ts
│   │   ├── NoOpTask.ts
│   │   ├── RegisteredActivityTask.ts
│   │   ├── RegisteredOrchestrationTask.ts
│   │   ├── RetryableTask.ts
│   │   ├── TaskBase.ts
│   │   ├── WhenAllTask.ts
│   │   ├── WhenAnyTask.ts
│   │   └── index.ts
│   ├── trigger.ts
│   └── util/
│       ├── GuidManager.ts
│       ├── Utils.ts
│       ├── WebhookUtils.ts
│       └── testingUtils.ts
├── test/
│   ├── integration/
│   │   ├── entity-spec.ts
│   │   └── orchestrator-spec.ts
│   ├── test-app/
│   │   ├── .funcignore
│   │   ├── .gitignore
│   │   ├── .vscode/
│   │   │   ├── extensions.json
│   │   │   ├── launch.json
│   │   │   ├── settings.json
│   │   │   └── tasks.json
│   │   ├── host.json
│   │   ├── package.json
│   │   ├── src/
│   │   │   └── functions/
│   │   │       ├── counter1.ts
│   │   │       └── hello.ts
│   │   └── tsconfig.json
│   ├── testobjects/
│   │   ├── TestOrchestrations.ts
│   │   ├── testconstants.ts
│   │   ├── testentities.ts
│   │   ├── testentitybatches.ts
│   │   ├── testentityoperations.ts
│   │   ├── testhistories.ts
│   │   └── testutils.ts
│   └── unit/
│       ├── createtimeraction-spec.ts
│       ├── durableclient-spec.ts
│       ├── entityid-spec.ts
│       ├── getclient-spec.ts
│       ├── guidmanager-spec.ts
│       ├── orchestrationclient-spec.ts
│       ├── retryoptions-spec.ts
│       ├── shim-spec.ts
│       ├── timertask-spec.ts
│       └── utils-spec.ts
├── tsconfig.json
├── tsconfig.nocomments
└── types/
    ├── activity.d.ts
    ├── app.client.d.ts
    ├── app.d.ts
    ├── durableClient.d.ts
    ├── entity.d.ts
    ├── index.d.ts
    ├── input.d.ts
    ├── orchestration.d.ts
    ├── task.d.ts
    └── trigger.d.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .azuredevops/dependabot.yml
================================================
# Mirrored repository. We use dependabot via GitHub, not Azure DevOps.
version: 2
enable-security-updates: false
enable-campaigned-updates: false

================================================
FILE: .editorconfig
================================================
; editor configuration powered by http://editorconfig.org/
; Top-most EditorConfig file
root = true

[*]
trim_trailing_whitespace = true
end_of_line = crlf
indent_style = space
indent_size = 4


================================================
FILE: .eslintignore
================================================
node_modules/**
lib/**
samples/node_modules/**
test/test-app/node_modules/**


================================================
FILE: .eslintrc
================================================
{
    "parser": "@typescript-eslint/parser",
    "extends": [
        "plugin:@typescript-eslint/recommended",
        "prettier/@typescript-eslint",
        "plugin:prettier/recommended"
    ],
    "rules": {
        "@typescript-eslint/no-use-before-define": "off",
        "@typescript-eslint/no-explicit-any": "off",
        "@typescript-eslint/no-namespace": "off",
        "@typescript-eslint/interface-name-prefix": "off",
        "@typescript-eslint/ban-types": "off"
    },
    "overrides": [
        {
            "files": ["*.js"],
            "rules": {
                "@typescript-eslint/no-var-requires": "off"
            }
        }
    ]
}


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is. Please make an effort to fill in all the sections below; the information will help us investigate your issue.

**Investigative information**

- Durable Functions extension version:
- durable-functions npm module version:
- Language (JavaScript/TypeScript) and version:
- Node.js version:

***If deployed to Azure App Service***

- Timeframe issue observed:
- Function App name:
- Function name(s):
- Region:
- Orchestration instance ID(s):

> If you don't want to share your Function App name or Functions names on GitHub, please be sure to provide your Invocation ID, Timestamp, and Region - we can use this to look up your Function App/Function. Provide an invocation id per Function. See the [Functions Host wiki](https://github.com/Azure/azure-webjobs-sdk-script/wiki/Sharing-Your-Function-App-name-privately) for more details.

**To Reproduce**
Steps to reproduce the behavior:

1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

> While not required, providing your orchestrator's source code in anonymized form is often very helpful when investigating unexpected orchestrator behavior.

**Expected behavior**
A clear and concise description of what you expected to happen.

**Actual behavior**
A clear and concise description of what actually happened.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Known workarounds**
Provide a description of any known workarounds you used.

**Additional context**

- Development environment (ex. Visual Studio)
- Links to source
- Additional bindings used
- Function invocation IDs


================================================
FILE: .github/ISSUE_TEMPLATE/new-release-template.md
================================================
---
name: New release template
about: Template for creating new releases of the Durable Functions Node.js SDK

---
**Prep Release**
- [ ] Create a post in the Durable Functions Release Teams channel to let the team know that we are starting a DF Node SDK release.
- [ ] Check that [package.json](https://github.com/Azure/azure-functions-durable-js/blob/v3.x/package.json) has the correct package version.
- [ ] The [official pipeline](https://dev.azure.com/azfunc/internal/_build?definitionId=546) should automatically run after a PR is merged to v3.x so you don't have to run it manually. Check that the pipeline ran with the expected latest PR. Download the .tgz package from the drop folder.
- [ ] Draft the release notes.

**Testing**
- To test the package from the official pipeline, run the following commands from your test app
1. Uninstall the current durable-functions package: `npm uninstall durable-functions`
2. Clear all npm cache (optional): `npm cache clean --force` 
3. Install your local .tgz file: `npm install <path to .tgz>`
4. Verify the installation: `npm list durable-functions`

- [ ] Test that a JavaScript Durable Functions app works with the .tgz that we created above. Run `func host start` and trigger an orchestration.
- [ ] Test that a TypeScript Durable Functions app works with the .tgz that we created above. Run `func host start` and trigger an orchestration. If you see the error `Error: Worker was unable to load entry point "dist/src/{index.js,functions/.js}": Found zero files matching the supplied pattern`, then run `npm run build` and then try running `func host start`.

**SDK Release**
- [ ] Dry run (optional): Run the [release pipeline](https://dev.azure.com/azfunc/internal/_build?definitionId=848) with the "Dry Run" box checked so you can simulate the npm publish step. It won't actually publish, but it will let you know what version would have been published and list other metadata. Check that there are no errors or warnings in the npm publish step.
- [ ] Run the [release pipeline](https://dev.azure.com/azfunc/internal/_build?definitionId=848) from the v3.x branch without the "Dry Run" box checked. This should publish the durable-functions package to npm. If there is an error, check that the npm token hasn't expired. Currently, it's set to expire on 8/6/2026.

**Release Completion**
- [ ] Uninstall the existing durable-functions package from your test apps using `npm uninstall durable-functions`. Check that the package was uninstalled by running `npm list durable-functions`. Download the .tgz from the [durable-functions npm page](https://www.npmjs.com/package/durable-functions) by running `npm i durable-functions` from your test app. It should install the latest package with the new version. Test it in JS and TS apps and check that `func host start` and triggering an orchestration work.
- [ ] Publish the release notes.


================================================
FILE: .github/fabricbot.json
================================================
{
  "version": "1.0",
  "tasks": [
    {
      "taskType": "trigger",
      "capabilityId": "IssueResponder",
      "subCapability": "IssuesOnlyResponder",
      "version": "1.0",
      "config": {
        "taskName": "Add needs triage label to new issues",
        "conditions": {
          "operator": "and",
          "operands": [
            {
              "name": "isAction",
              "parameters": {
                "action": "opened"
              }
            },
            {
              "operator": "not",
              "operands": [
                {
                  "name": "isPartOfProject",
                  "parameters": {}
                }
              ]
            },
            {
              "operator": "not",
              "operands": [
                {
                  "name": "isAssignedToSomeone",
                  "parameters": {}
                }
              ]
            }
          ]
        },
        "actions": [
          {
            "name": "addLabel",
            "parameters": {
              "label": "Needs: Triage :mag:"
            }
          }
        ],
        "eventType": "issue",
        "eventNames": [
          "issues",
          "project_card"
        ]
      },
      "id": "Q2X6kH3i8"
    },
    {
      "taskType": "trigger",
      "capabilityId": "IssueResponder",
      "subCapability": "IssueCommentResponder",
      "version": "1.0",
      "config": {
        "taskName": "Replace needs author feedback label with needs attention label when the author comments on an issue",
        "conditions": {
          "operator": "and",
          "operands": [
            {
              "name": "isAction",
              "parameters": {
                "action": "created"
              }
            },
            {
              "name": "isActivitySender",
              "parameters": {
                "user": {
                  "type": "author"
                }
              }
            },
            {
              "name": "hasLabel",
              "parameters": {
                "label": "Needs: Author Feedback"
              }
            }
          ]
        },
        "actions": [
          {
            "name": "addLabel",
            "parameters": {
              "label": "Needs: Attention :wave:"
            }
          },
          {
            "name": "removeLabel",
            "parameters": {
              "label": "Needs: Author Feedback"
            }
          }
        ],
        "eventType": "issue",
        "eventNames": [
          "issue_comment"
        ]
      },
      "id": "HPyPg7vgiE"
    },
    {
      "taskType": "trigger",
      "capabilityId": "IssueResponder",
      "subCapability": "IssuesOnlyResponder",
      "version": "1.0",
      "config": {
        "taskName": "Remove no recent activity label from issues",
        "conditions": {
          "operator": "and",
          "operands": [
            {
              "operator": "not",
              "operands": [
                {
                  "name": "isAction",
                  "parameters": {
                    "action": "closed"
                  }
                }
              ]
            },
            {
              "name": "hasLabel",
              "parameters": {
                "label": "no-recent-activity"
              }
            }
          ]
        },
        "actions": [
          {
            "name": "removeLabel",
            "parameters": {
              "label": "no-recent-activity"
            }
          }
        ],
        "eventType": "issue",
        "eventNames": [
          "issues",
          "project_card"
        ]
      },
      "id": "NehFInt7Vy"
    },
    {
      "taskType": "scheduled",
      "capabilityId": "ScheduledSearch",
      "subCapability": "ScheduledSearch",
      "version": "1.1",
      "config": {
        "taskName": "Close stale issues",
        "frequency": [
          {
            "weekDay": 0,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 1,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 2,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 3,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 4,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 5,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 6,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          }
        ],
        "searchTerms": [
          {
            "name": "isIssue",
            "parameters": {}
          },
          {
            "name": "isOpen",
            "parameters": {}
          },
          {
            "name": "hasLabel",
            "parameters": {
              "label": "Needs: Author Feedback"
            }
          },
          {
            "name": "hasLabel",
            "parameters": {
              "label": "no-recent-activity"
            }
          },
          {
            "name": "noActivitySince",
            "parameters": {
              "days": 3
            }
          }
        ],
        "actions": [
          {
            "name": "closeIssue",
            "parameters": {}
          }
        ]
      },
      "id": "OFiBwmzJFC"
    },
    {
      "taskType": "scheduled",
      "capabilityId": "ScheduledSearch",
      "subCapability": "ScheduledSearch",
      "version": "1.1",
      "config": {
        "taskName": "Add no recent activity label to issues",
        "frequency": [
          {
            "weekDay": 0,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 1,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 2,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 3,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 4,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 5,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 6,
            "hours": [
              1,
              4,
              7,
              10,
              13,
              16,
              19,
              22
            ],
            "timezoneOffset": -8
          }
        ],
        "searchTerms": [
          {
            "name": "isIssue",
            "parameters": {}
          },
          {
            "name": "isOpen",
            "parameters": {}
          },
          {
            "name": "hasLabel",
            "parameters": {
              "label": "Needs: Author Feedback"
            }
          },
          {
            "name": "noActivitySince",
            "parameters": {
              "days": 4
            }
          },
          {
            "name": "noLabel",
            "parameters": {
              "label": "no-recent-activity"
            }
          }
        ],
        "actions": [
          {
            "name": "addLabel",
            "parameters": {
              "label": "no-recent-activity"
            }
          },
          {
            "name": "addReply",
            "parameters": {
              "comment": "This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**."
            }
          }
        ]
      },
      "id": "ksFO8A5VjG"
    },
    {
      "taskType": "scheduled",
      "capabilityId": "ScheduledSearch",
      "subCapability": "ScheduledSearch",
      "version": "1.1",
      "config": {
        "taskName": "Close duplicate issues",
        "frequency": [
          {
            "weekDay": 0,
            "hours": [
              2,
              5,
              8,
              11,
              14,
              17,
              20,
              23
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 1,
            "hours": [
              2,
              5,
              8,
              11,
              14,
              17,
              20,
              23
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 2,
            "hours": [
              2,
              5,
              8,
              11,
              14,
              17,
              20,
              23
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 3,
            "hours": [
              2,
              5,
              8,
              11,
              14,
              17,
              20,
              23
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 4,
            "hours": [
              2,
              5,
              8,
              11,
              14,
              17,
              20,
              23
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 5,
            "hours": [
              2,
              5,
              8,
              11,
              14,
              17,
              20,
              23
            ],
            "timezoneOffset": -8
          },
          {
            "weekDay": 6,
            "hours": [
              2,
              5,
              8,
              11,
              14,
              17,
              20,
              23
            ],
            "timezoneOffset": -8
          }
        ],
        "searchTerms": [
          {
            "name": "isIssue",
            "parameters": {}
          },
          {
            "name": "isOpen",
            "parameters": {}
          },
          {
            "name": "hasLabel",
            "parameters": {
              "label": "duplicate"
            }
          },
          {
            "name": "noActivitySince",
            "parameters": {
              "days": 1
            }
          }
        ],
        "actions": [
          {
            "name": "addReply",
            "parameters": {
              "comment": "This issue has been marked as duplicate and has not had any activity for **1 day**. It will be closed for housekeeping purposes."
            }
          },
          {
            "name": "closeIssue",
            "parameters": {}
          }
        ]
      },
      "id": "TBIOIQH7sE"
    },
    {
      "taskType": "trigger",
      "capabilityId": "IssueResponder",
      "subCapability": "IssueCommentResponder",
      "version": "1.0",
      "config": {
        "eventType": "issue",
        "eventNames": [
          "issue_comment"
        ],
        "conditions": {
          "operator": "and",
          "operands": [
            {
              "name": "hasLabel",
              "parameters": {
                "label": "no-recent-activity"
              }
            }
          ]
        },
        "taskName": "Remove no recent activity label when an issue is commented on",
        "actions": [
          {
            "name": "removeLabel",
            "parameters": {
              "label": "no-recent-activity"
            }
          }
        ]
      },
      "id": "wLypfSoaZ"
    }
  ],
  "userGroups": []
}


================================================
FILE: .github/workflows/codeQL.yml
================================================
# This workflow generates weekly CodeQL reports for this repo, a security requirements.
# The workflow is adapted from the following reference: https://github.com/Azure-Samples/azure-functions-python-stream-openai/pull/2/files
# Generic comments on how to modify these file are left intactfor future maintenance.

name: "CodeQL"

on:
  push:
    branches: [ "v3.x", "v2.x" ]
  pull_request:
    branches: [ "v3.x", "v2.x"]
  schedule:
    - cron: '0 0 * * 1' # Weekly Monday run, needed for weekly reports
  workflow_call: # allows to be invoked as part of a larger workflow
  workflow_dispatch: # allows for the workflow to run manually see: https://docs.github.com/en/actions/using-workflows/manually-running-a-workflow

jobs:

  analyze:
    name: Analyze
    runs-on: windows-latest
    permissions:
      actions: read
      contents: read
      security-events: write


    strategy:
      fail-fast: false
      matrix:
        language: ['typescript']
        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
        # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

    steps:
    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v3
      with:
        languages: ${{ matrix.language }}
        # If you wish to specify custom queries, you can do so here or in a config file.
        # By default, queries listed here will override any specified in a config file.
        # Prefix the list here with "+" to use these queries and those in the config file.

        # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
        # queries: security-extended,security-and-quality

    - uses: actions/checkout@v3
      with:
        submodules: true

    # Autobuild attempts to build any compiled languages  (C/C++, C#, Go, or Java).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v2

    # Run CodeQL analysis
    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v3
      with:
        category: "/language:${{matrix.language}}"

================================================
FILE: .gitignore
================================================
coverage/
node_modules/
npm-debug.log
lib/

================================================
FILE: .prettierrc
================================================
{
    "trailingComma": "es5",
    "tabWidth": 4,
    "true": false,
    "singleQuote": false,
    "printWidth": 100,
    "endOfLine": "auto"
}


================================================
FILE: .vscode/extensions.json
================================================
{
  "recommendations": [
    "ms-azuretools.vscode-azurefunctions",
    "editorconfig.editorconfig",
    "eg2.vscode-npm-script",
    "esbenp.prettier-vscode"
  ]
}


================================================
FILE: .vscode/launch.json
================================================
{
    // Use IntelliSense to learn about possible Node.js debug attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "program": "${workspaceRoot}\\test\\test.ts",
            "sourceMaps": true,
            "cwd": "${workspaceRoot}\\lib\\test",
            "outFiles": [
                "${workspaceRoot}/lib/**/*.js"
            ],
            "env": {
                "DEBUG": "*"
            },
            "preLaunchTask": "build"
        },
        {
            "type": "node",
            "request": "attach",
            "name": "Attach by Process ID",
            "outFiles": [
                "${workspaceRoot}/lib/**/*.js"
            ],
            "processId": "${command:PickProcess}"
        },
        {
            "type": "node",
            "request": "attach",
            "name": "Attach",
            "outFiles": [
                "${workspaceRoot}/lib/**/*.js"
            ],
            "port": 5858
        },
        {
            "type": "node",
            "request": "launch",
            "name": "Mocha Tests",
            "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
            "args": [
                "--colors",
                "${workspaceFolder}/lib/test/**/**-spec.js",
                "-g",
                ".*"
            ],
            "internalConsoleOptions": "openOnSessionStart",
            "sourceMaps": true,
            "outFiles": [
                "${workspaceFolder}/lib/**"
            ],
            "preLaunchTask": "build"
        },
        {
            "type": "node",
            "request": "launch",
            "name": "Mocha Tests Debug",
            "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
            "args": [
                "--colors",
                "${workspaceFolder}/lib/test/**/**-spec.js",
                "-g",
                ".*",
                "--timeout",
                "300000"
            ],
            "internalConsoleOptions": "openOnSessionStart",
            "sourceMaps": true,
            "outFiles": [
                "${workspaceFolder}/lib/**"
            ],
            "preLaunchTask": "build"
        },
        {
            "name": "Attach to Node Functions",
            "type": "node",
            "request": "attach",
            "port": 9229,
            "preLaunchTask": "func: host start"
        }
    ]
}


================================================
FILE: .vscode/settings.json
================================================
{
    "typescript.tsdk": "node_modules\\typescript\\lib",
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "files.exclude": {
        "obj": true,
        "bin": true
    },
    "azureFunctions.deploySubpath": "samples",
    "azureFunctions.postDeployTask": "npm install",
    "azureFunctions.projectLanguage": "TypeScript",
    "azureFunctions.projectRuntime": "~3",
    "debug.internalConsoleOptions": "neverOpen",
    "azureFunctions.preDeployTask": "npm prune",
    "mochaExplorer.require": "ts-node/register",
    "mochaExplorer.files": "test/**/*.ts"
}


================================================
FILE: .vscode/tasks.json
================================================
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "command": "npm",
    "tasks": [
        {
            "label": "install",
            "type": "shell",
            "args": [
                "install"
            ],
            "problemMatcher": []
        },
        {
            "label": "update",
            "type": "shell",
            "args": [
                "update"
            ],
            "problemMatcher": []
        },
        {
            "label": "test",
            "type": "shell",
            "args": [
                "run",
                "test"
            ],
            "problemMatcher": [],
            "group": "test"
        },
        {
            "label": "build",
            "type": "shell",
            "args": [
                "run",
                "build"
            ],
            "problemMatcher": [],
            "group": "build"
        },
        {
            "type": "func",
            "command": "host start",
            "problemMatcher": "$func-node-watch",
            "isBackground": true,
            "dependsOn": "npm build",
            "options": {
                "cwd": "${workspaceFolder}/samples"
            }
        },
        {
            "type": "shell",
            "label": "npm build",
            "command": "npm run build",
            "dependsOn": [
                "func: extensions install",
                "npm install"
            ],
            "problemMatcher": "$tsc",
            "options": {
                "cwd": "${workspaceFolder}/samples"
            }
        },
        {
            "type": "shell",
            "label": "npm install",
            "command": "npm install",
            "options": {
                "cwd": "${workspaceFolder}/samples"
            }
        },
        {
            "type": "shell",
            "label": "npm prune",
            "command": "npm prune --production",
            "dependsOn": "npm build",
            "problemMatcher": [],
            "options": {
                "cwd": "${workspaceFolder}/samples"
            }
        }
    ]
}

================================================
FILE: CONTRIBUTING.md
================================================
# Contributor Onboarding

## General

- Helps start contributions to Durable Functions in JavaScript
- Helps setup development environment across platforms for Durable Functions in JavaScript

## Pre-reqs

- OS
    - MacOS (or) Windows10
- Language Runtimes
    - [.NET Core 2.0](https://dotnet.microsoft.com/download/dotnet-core/2.0)
    - [Python 3.6.x](https://www.python.org/downloads/)
- Editor
    - [VSCode](https://code.visualstudio.com/) (or) [Visual Studio](https://visualstudio.microsoft.com/downloads/)
- Tools
    - [Azurite V2](https://github.com/Azure/Azurite/tree/legacy-master) (for MacOS) (or) [Azure Storage Emulator](https://azure.microsoft.com/en-us/features/storage-explorer/) (or) Storage account in Azure
    - [Azure Functions Core Tools](https://github.com/Azure/azure-functions-core-tools) v2.7.x and above.

## Change flow

The general flow for making a change to the script host is:
1. 🍴 Fork the repo (add the fork via `git remote add me <clone url here>`
2. 🌳 Create a branch for your change (generally branch from dev) (`git checkout -b my-change`)
3. 🛠 Make your change
4. ✔️ Test your changes
5. ⬆️ Push your changes to your fork (`git push me my-change`)
6. 💌 Open a PR to the dev branch
7. 📢 Address feedback and make sure tests pass (yes even if it's an "unrelated" test failure)
8. 📦 [Rebase](https://git-scm.com/docs/git-rebase) your changes into a meaningful commits (`git rebase -i HEAD~N` where `N` is commits you want to squash)
9. :shipit: Rebase and merge (This will be done for you if you don't have contributor access)
10. ✂️ Delete your branch (optional)

## End to End Development Setup: JavaScript library + Durable Extension (MacOS)

### Setting up Azurite V2

Note: [Azurite V3](https://github.com/Azure/Azurite) does not have support for Table Storage yet. So falling back to [Azurite V2](https://github.com/Azure/Azurite/tree/legacy-master) setup.

Create a folder say AzureWebJobsStorage

`npm install azurite@2.7.1 -g`

`azurite -l ./AzureWebJobsStorage`

```
 _______                   _
(_______)                 (_)  _
 _______ _____ _   _  ____ _ _| |_ _____
|  ___  (___  ) | | |/ ___) (_   _) ___ |
| |   | |/ __/| |_| | |   | | | |_| ____|
|_|   |_(_____)____/|_|   |_| \__)_____)

Azurite, Version 2.7.1
A lightweight server clone of Azure Storage

Azure Table Storage Emulator listening on port 10002
Azure Queue Storage Emulator listening on port 10001
Azure Blob Storage Emulator listening on port 10000
```

### Visual Studio Code Extensions

The following extensions should be installed if using Visual Studio Code for debugging:

- C# for Visual Studio Code (powered by OmniSharp)
- Azure Functions Extensions for Visual Studio Code v0.19.1 and above.

### Setting up Durable JavaScript using sample code

- Make your changes in the Durable Functions project and run `npm run build` to build the project.

- Create a Durable Functions Orchestrator for FunctionChaining pattern using [starter templates](https://docs.microsoft.com/en-us/azure/azure-functions/durable/quickstart-js-vscode)
  Note: In this starter template, ignore the line that says: "On a Mac or Linux computer, you must set the AzureWebJobsStorage property to the connection string of an existing Azure storage account". We will be setting up the AzureWebJobsStorage property to `UseDevelopmentStorage=true`

- Then, in your sample code, instead of requiring the `npm`-hosted version of the code, directly refer to your local changes. There are many ways of going about this, but a simple solution is changing a reference to `require("durable-functions")` to `require("<your-local-path-to-my-this-repo>")`.

- Finally, start your VSCode editor, click Debug -> Start Debugging. This will internally start `func host start` through core tools and provides the orchestrator client URL.
After doing this, you should be able to add breakpoints to test your changes for Durable JavaScript!


### Debugging end-to-end with the Durable Extension

In some advanced scenarios, you may want to inspect how your repo interacts with the underlying Durable Extension. In these settings, we recommend using Visual Studio.

Two changes are necessary in your JavaScript sample code to make this work.

- In host.json, remove the extensionsBundle portion to enable specific version debugging. Provide a hub name (else remove the entire extensions portion to default to DurableFunctionsHub) Here's how the host.json should look like:

```
{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": "{hubName}"
    }
  }
}
```

- Create an `extensions.csproj` file containing the version of the DurableTask extension that you wish to use. We recommend using the latest version on [nuget.org](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.DurableTask/). To do this, take the sample `extensions.csproj` shown below, update the version of the `Microsoft.Azure.WebJobs.Extensions.DurableTask` dependency, and save it at the root of your sample.

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  <WarningsAsErrors></WarningsAsErrors>
  <DefaultItemExcludes>**</DefaultItemExcludes>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.3.9" />
  </ItemGroup>
</Project>
```

- Finally, open a terminal and run `func extensions install`. This will install the dependencies listed in your `extensions.csproj` file.


Now you are ready to start debugging Durable Functions end-to-end. Follow the instructions below:
1. Open the Azure Storage Explorer and connect to the local storage emulator or the storage account you are using.
2. In the VSCode editor for durable-js click Debug -> Start Debugging. This will internally start `func host start` through core tools and provides the orchestrator client URL
3. In the Visual Studio editor for DurableTask, click Debug -> .NET Core Attach Process and search for `func host start` process and attach to it.
4. Add a breakpoint in both editors and continue debugging.

## Testing with emulated local storage (Windows)

When debugging your changes, you may want to use your local storage instead of an Azure account. To do this, follow all the steps above, use the Azure Storage Emulator for windows to simulate the storage account, and optionally use Visual Studio to debug the .NET Durable Extension.

## Getting help

 - Leave comments on your PR and @username for attention


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2017 Microsoft

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.


================================================
FILE: README.md
================================================
| Branch         | Status                                                                                                                                                                                                | Support level    | Programming model | Node.js versions |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ----------------- | ---------------- |
| v3.x (Default) | [![Build Status](https://azfunc.visualstudio.com/public/_apis/build/status/durable-js.public?branchName=v3.x)](https://azfunc.visualstudio.com/public/_build/latest?definitionId=563&branchName=v3.x) | GA (Recommended) | V4                | 18.x+            |
| v2.x           | [![Build Status](https://azfunc.visualstudio.com/public/_apis/build/status/durable-js.public?branchName=v2.x)](https://azfunc.visualstudio.com/public/_build/latest?definitionId=563&branchName=v2.x) | GA               | V3                | 14.x+            |

# Durable Functions for Node.js

The `durable-functions` npm package allows you to write [Durable Functions](https://docs.microsoft.com/azure/azure-functions/durable/durable-functions-overview?tabs=javascript-v4) for [Node.js](https://docs.microsoft.com/azure/azure-functions/functions-reference-node?pivots=nodejs-model-v4). Durable Functions is an extension of [Azure Functions](https://docs.microsoft.com/azure/azure-functions/functions-overview) that lets you write stateful functions and workflows in a serverless environment. The extension manages state, checkpoints, and restarts for you. Durable Functions' advantages include:

-   Define workflows in code. No JSON schemas or designers are needed.
-   Call other functions synchronously and asynchronously. Output from called functions can be saved to local variables.
-   Automatically checkpoint progress whenever the function schedules async work. Local state is never lost if the process recycles or the VM reboots.

You can find more information at the following links:

-   [Azure Functions overview](https://docs.microsoft.com/azure/azure-functions/functions-overview)
-   [Azure Functions JavaScript developers guide](https://docs.microsoft.com/azure/azure-functions/functions-reference-node?pivots=nodejs-model-v4)
-   [Durable Functions overview](https://docs.microsoft.com/azure/azure-functions/durable/durable-functions-overview?tabs=javascript-v4)

A durable function, or _orchestration_, is a solution made up of different types of Azure Functions:

-   **Activity:** the functions and tasks being orchestrated by your workflow.
-   **Orchestrator:** a function that describes the way and order actions are executed in code.
-   **Client:** the entry point for creating an instance of a durable orchestration.

Durable Functions' function types and features are documented in-depth [here.](https://docs.microsoft.com/azure/azure-functions/durable/durable-functions-types-features-overview)

Version `v3.x` of the Durable Functions package supports the new v4 Node.js programming model for Azure Functions, which is now generally available! Compared to the v3 model, the v4 model is designed to have a more idiomatic and intuitive experience for JavaScript and TypeScript developers. You can learn more about the v4 programming model at the following links:

-   [Durable Functions programming model v4 upgrade guide](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-node-model-upgrade)
-   [Azure Functions Node.js Developer Guide](https://docs.microsoft.com/azure/azure-functions/functions-reference-node?pivots=nodejs-model-v4)
-   [Node.js v4 programming model upgrade guide](https://learn.microsoft.com/azure/azure-functions/functions-node-upgrade-v4)

## Getting Started

You can follow the Visual Studio Code quickstart in [JavaScript](https://docs.microsoft.com/azure/azure-functions/durable/quickstart-js-vscode?pivots=nodejs-model-v4) or [TypeScript](https://docs.microsoft.com/azure/azure-functions/durable/quickstart-ts-vscode?pivots=nodejs-model-v4) to get started with a function chaining example, or follow the general checklist below:

1. Install prerequisites:

    - [Azure Functions Core Tools version 4.0.5382 (or higher)](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Cnode%2Cportal%2Cbash#install-the-azure-functions-core-tools)
    - [Azurite emulator](https://learn.microsoft.com/azure/storage/common/storage-use-azurite) or an actual Azure storage account
    - Node.js 18.x or later

2. [Create an Azure Functions app.](https://learn.microsoft.com/azure/azure-functions/create-first-function-vs-code-node?pivots=nodejs-model-v4) [Visual Studio Code's Azure Functions extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions) is recommended ([version 1.10.4](https://github.com/microsoft/vscode-azurefunctions/releases/tag/v1.10.4) or above is needed for the v4 programming model).

3. Install the Durable Functions extension

We recommend using Azure Functions [extension bundles](https://learn.microsoft.com/azure/azure-functions/functions-bindings-register#extension-bundles) to install the Durable Functions extension. Version 3.15 or higher of extension bundles is required for the v4 programming model. Make sure you add the following in your `host.json` file:

```json
"extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[3.15.0, 4.0.0)"
}
```

4. Install the `durable-functions` npm package at the root of your function app:

```bash
npm install durable-functions
```

5. Write an activity function (see sample in [JavaScript](./samples-js/functions/sayHello.js#L37)/[TypeScript](./samples-ts/functions/sayHello.ts#L44)):

```javascript
const df = require("durable-functions");
df.app.activity("myActivity", {
    handler: async function (input, context) {
        // your code here
    },
});
```

6. Write an orchestrator function (see sample in [JavaScript](./samples-js/functions/sayHello.js#L5)/[TypeScript](./samples-ts/functions/sayHello.ts#L6)):

```javascript
const df = require("durable-functions");
df.app.orchestration("myOrchestration", function* (context) {
    // your code here
});
```

**Note:** Orchestrator functions must follow certain [code constraints.](https://docs.microsoft.com/azure/azure-functions/durable-functions-checkpointing-and-replay#orchestrator-code-constraints)

7. Write your client function (see sample in [JavaScript](./samples-js/functions/httpStart.js)/[TypeScript](./samples-ts/functions/httpStart.ts)):

```javascript
const df = require("durable-functions");

df.app.client.http("httpStart", {
    route: "orchestrators/{orchestratorName}",
    handler: async (request, client, context) => {
        const body = await request.json();
        const instanceId = await client.startNew(request.params.orchestratorName, { input: body });

        context.log(`Started orchestration with ID = '${instanceId}'.`);

        return client.createCheckStatusResponse(request, instanceId);
    },
});
```

**Note:** Client functions can be started by any trigger binding supported in the Azure Functions runtime version 2.x+. Node.js v4 programming model apps require at least version 4.25 of the Azure Functions runtime. [Read more about trigger bindings and 2.x-supported bindings.](https://docs.microsoft.com/azure/azure-functions/functions-triggers-bindings#overview)

## Samples

The [Durable Functions samples](https://docs.microsoft.com/azure/azure-functions/durable-functions-install) demonstrate several common use cases. They are located in the samples directories ([JavaScript](./samples-js/)/[TypeScript](./samples-ts/)). Descriptive documentation is also available:

-   [Function Chaining - Hello Sequence](https://docs.microsoft.com/azure/azure-functions/durable-functions-sequence?tabs=javascript-v4)
-   [Fan-out/Fan-in - Cloud Backup](https://docs.microsoft.com/azure/azure-functions/durable-functions-cloud-backup?tabs=javascript-v4)
-   [Monitors - Weather Watcher](https://docs.microsoft.com/azure/azure-functions/durable-functions-monitor?tabs=javascript)
-   [Human Interaction & Timeouts - Phone Verification](https://docs.microsoft.com/azure/azure-functions/durable-functions-phone-verification?tabs=javascript-v4)

```javascript
const df = require("durable-functions");

const helloActivity = df.app.activity("hello", {
    handler: async function (input) {
        return `Hello, ${input}`;
    },
});

df.app.orchestration("helloSequence", function* (context) {
    context.log("Starting chain sample");

    const output = [];
    output.push(yield helloActivity("Tokyo"));
    output.push(yield helloActivity("Seattle"));
    output.push(yield helloActivity("Cairo"));

    return output;
});
```

## How it works

### Durable Functions

One of the key attributes of Durable Functions is reliable execution. Orchestrator functions and activity functions may be running on different VMs within a data center, and those VMs or the underlying networking infrastructure is not 100% reliable.

In spite of this, Durable Functions ensures reliable execution of orchestrations. It does so by using storage queues to drive function invocation and by periodically checkpointing execution history into storage tables (using a cloud design pattern known as [Event Sourcing](https://docs.microsoft.com/azure/architecture/patterns/event-sourcing)). That history can then be replayed to automatically rebuild the in-memory state of an orchestrator function.

[Read more about Durable Functions' reliable execution.](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-orchestrations?tabs=javascript-v4)

### Durable Functions JS

The `durable-functions` shim lets you express a workflow in code as a [generator function](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Iterators_and_Generators) wrapped by a call to the `app.orchestration` method. The Durable Functions SDK treats `yield`-ed calls, such as `yield helloActivity("Tokyo")`, as points where you want to schedule an asynchronous unit of work and wait for it to complete.

Calling `helloActivity("Tokyo")` returns a `Task` object signifying the outstanding work. `Task` objects can also be obtained by APIs on the `context.df` object, such as `context.df.callHttp()`. Only `Task` objects can be `yield`ed. The SDK appends the action(s) of the `Task` object to a list which it passes back to the Functions runtime, plus whether the function is completed, and any output or errors.

The Azure Functions extension schedules the desired actions. When the actions complete, the extension triggers the orchestrator function to replay up to the next incomplete asynchronous unit of work or its end, whichever comes first.


================================================
FILE: SECURITY.md
================================================
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.9 BLOCK -->

## Security

Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).

If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.

## Reporting Security Issues

**Please do not report security vulnerabilities through public GitHub issues.**

Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).

If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).

You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 

Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:

  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
  * Full paths of source file(s) related to the manifestation of the issue
  * The location of the affected source code (tag/branch/commit or direct URL)
  * Any special configuration required to reproduce the issue
  * Step-by-step instructions to reproduce the issue
  * Proof-of-concept or exploit code (if possible)
  * Impact of the issue, including how an attacker might exploit the issue

This information will help us triage your report more quickly.

If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.

## Preferred Languages

We prefer all communications to be in English.

## Policy

Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).

<!-- END MICROSOFT SECURITY.MD BLOCK -->


================================================
FILE: azure-pipelines/code-mirror.yml
================================================
trigger:
    branches:
        include:
            - v2.x
            - v3.x

schedules:
# Build weekly to ensure the pipeline isn't deactivated.
- cron: "0 0 1/7 * *"
  displayName: Weekly sync
  branches:
    include:
    - v3.x
  always: true

resources:
    repositories:
        - repository: eng
          type: git
          name: engineering
          ref: refs/tags/release

variables:
    - template: ci/variables/cfs.yml@eng

extends:
    template: ci/code-mirror.yml@eng


================================================
FILE: azure-pipelines/official-build.yml
================================================
trigger:
    branches:
        include:
            - v3.x
    batch: true

# CI only
pr: none

schedules:
# Build nightly to catch any new CVEs and report SDL often.
# We are also required to generated CodeQL reports weekly, so this
# helps us meet that.
- cron: "0 6 * * *"
  displayName: Nightly Build
  branches:
    include:
    - v3.x
  always: true

resources:
    repositories:
        - repository: 1esPipelines
          type: git
          name: 1ESPipelineTemplates/1ESPipelineTemplates
          ref: refs/tags/release

extends:
    template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines
    parameters:
        pool:
            name: 1es-pool-azfunc
            image: 1es-windows-2022
            os: windows
            ${{ if eq( variables['Build.Reason'], 'Schedule' ) }}:
              demands:
              - Priority -equals Low

        stages:
            - stage: WindowsUnitTests
              dependsOn: []
              jobs:
                  - template: /azure-pipelines/templates/test.yml@self

            - stage: LinuxUnitTests
              dependsOn: []
              jobs:
                  - template: /azure-pipelines/templates/test.yml@self
              pool:
                  name: 1es-pool-azfunc
                  image: 1es-ubuntu-22.04
                  os: linux

            - stage: Build
              dependsOn: []
              jobs:
                  - template: /azure-pipelines/templates/build.yml@self


================================================
FILE: azure-pipelines/public-build.yml
================================================
trigger:
    branches:
        include:
            - v3.x
    batch: true

pr:
    branches:
        include:
            - v3.x

resources:
    repositories:
        - repository: 1esPipelines
          type: git
          name: 1ESPipelineTemplates/1ESPipelineTemplates
          ref: refs/tags/release

extends:
    template: v1/1ES.Unofficial.PipelineTemplate.yml@1esPipelines
    parameters:
        pool:
            name: 1es-pool-azfunc-public
            image: 1es-windows-2022
            os: windows

        settings:
            # PR's from forks do not have sufficient permissions to set tags.
            skipBuildTagsForGitHubPullRequests: ${{ variables['System.PullRequest.IsFork'] }}

        stages:
            - stage: WindowsUnitTests
              dependsOn: []
              jobs:
                  - template: /azure-pipelines/templates/test.yml@self

            - stage: LinuxUnitTests
              dependsOn: []
              jobs:
                  - template: /azure-pipelines/templates/test.yml@self
              pool:
                  name: 1es-pool-azfunc-public
                  image: 1es-ubuntu-22.04
                  os: linux

            - stage: Build
              dependsOn: []
              jobs:
                  - template: /azure-pipelines/templates/build.yml@self


================================================
FILE: azure-pipelines/release.yml
================================================
parameters:
    - name: NpmPublishTag
      displayName: "Tag"
      type: string
      default: "latest"
    - name: NpmPublishDryRun
      displayName: "Dry Run"
      type: boolean
      default: true

trigger: none
pr: none

resources:
    repositories:
        - repository: 1es
          type: git
          name: 1ESPipelineTemplates/1ESPipelineTemplates
          ref: refs/tags/release
    pipelines:
        - pipeline: DurableJSCI
          project: internal
          source: durable-js.official
          branch: v3.x

extends:
    template: v1/1ES.Official.PipelineTemplate.yml@1es
    parameters:
        sdl:
            sourceAnalysisPool:
                name: 1es-pool-azfunc
                image: 1es-windows-2022
                os: windows
            codeql:
                runSourceLanguagesInSourceAnalysis: true

        stages:
            - stage: Release
              pool:
                  name: 1es-pool-azfunc
                  image: 1es-ubuntu-22.04
                  os: linux
              jobs:
                  - job: Release
                    steps:
                        - task: NodeTool@0
                          displayName: "Install Node.js"
                          inputs:
                              versionSpec: 14.x
                        - download: DurableJSCI
                        - script: mv *.tgz package.tgz
                          displayName: "Rename tgz file" # because the publish command below requires an exact path
                          workingDirectory: "$(Pipeline.Workspace)/DurableJSCI/drop"
                        - task: Npm@1
                          displayName: "npm publish"
                          inputs:
                              command: custom
                              workingDir: "$(Pipeline.Workspace)/DurableJSCI/drop"
                              verbose: true
                              customCommand: "publish package.tgz --tag ${{ parameters.NpmPublishTag }} --dry-run ${{ lower(parameters.NpmPublishDryRun) }}"
                              customEndpoint: "durable-functions npm (valid until Aug 4th 2026)"


================================================
FILE: azure-pipelines/templates/build.yml
================================================
jobs:
    - job:
      templateContext:
          outputs:
              - output: pipelineArtifact
                path: $(Build.ArtifactStagingDirectory)
                artifact: drop
                sbomBuildDropPath: "$(System.DefaultWorkingDirectory)"
                sbomPackageName: "Durable Functions for Node.js"
                # The list of components can't be determined from the webpacked file in the staging dir, so reference the original node_modules folder
                sbomBuildComponentPath: "$(Build.SourcesDirectory)/node_modules"
      steps:
          - task: NodeTool@0
            inputs:
                versionSpec: 20.x
            displayName: "Install Node.js"
          - script: npm ci
            displayName: "npm ci"
          - script: npm run-script build
            displayName: "npm run-script build"
          - script: npm prune --production
            displayName: "npm prune --production" # so that only production dependencies are included in SBOM
          - script: npm pack
            displayName: "pack npm package"
          - task: CopyFiles@2
            displayName: "Copy package to staging"
            inputs:
                SourceFolder: $(System.DefaultWorkingDirectory)
                Contents: "*.tgz"
                TargetFolder: $(Build.ArtifactStagingDirectory)


================================================
FILE: azure-pipelines/templates/test.yml
================================================
jobs:
    - job: UnitTests

      strategy:
          matrix:
              Node18:
                  NODE_VERSION: "18.x"
              Node20:
                  NODE_VERSION: "20.x"
              Node22:
                  NODE_VERSION: "22.x"
              Node24:
                  NODE_VERSION: "24.x"

      steps:
          - task: NodeTool@0
            inputs:
                versionSpec: $(NODE_VERSION)
            displayName: "Install Node dependencies"
          - script: npm ci
            displayName: "npm ci"
          - script: npm run test
            displayName: "npm build and test"
          - script: npm run test:nolint
            displayName: "npm build and test (no linting)"
          - script: npm run build
            displayName: "npm run build"
          - script: npm pack
            displayName: "npm pack"
          - script: mv durable-functions-*.tgz package.tgz
            displayName: "Rename package file"
          - task: CopyFiles@2
            displayName: "Create smoke test app"
            inputs:
                SourceFolder: "$(System.DefaultWorkingDirectory)/test/test-app"
                Contents: "**"
                TargetFolder: "$(Agent.BuildDirectory)/test-app"
                CleanTargetFolder: true
          - script: npm install $(System.DefaultWorkingDirectory)/package.tgz
            displayName: "Install packed durable-functions module (test app)"
            workingDirectory: $(Agent.BuildDirectory)/test-app
          - script: npm install
            displayName: "npm install (test app)"
            workingDirectory: $(Agent.BuildDirectory)/test-app
          - script: npm run build
            displayName: "Build smoke test app"
            workingDirectory: "$(Agent.BuildDirectory)/test-app"


================================================
FILE: es-metadata.yml
================================================
schemaVersion: 1.0.0
providers:
- provider: InventoryAsCode
  version: 1.0.0
  metadata:
    isProduction: true
    accountableOwners:
      service: c5281ccb-b379-4acf-9099-95a37f9805f3
    routing:
      defaultAreaPath:
        org: azfunc
        path: internal\DurableTask


================================================
FILE: package.json
================================================
{
    "name": "durable-functions",
    "version": "3.3.1",
    "description": "Durable Functions library for Node.js Azure Functions",
    "license": "MIT",
    "repository": {
        "type": "git",
        "url": "git+https://github.com/Azure/azure-functions-durable-js.git"
    },
    "author": "Microsoft Corporation",
    "keywords": [
        "azure-functions"
    ],
    "files": [
        "lib/src",
        "types/"
    ],
    "main": "lib/src/index.js",
    "types": "types/index.d.ts",
    "engines": {
        "node": ">=18.0"
    },
    "scripts": {
        "clean": "rimraf lib",
        "lint": "eslint --ext .ts,.json src/",
        "lint:test": "eslint --ext .ts,.json test/",
        "lint:samples": "eslint --ext .ts,.js samples/",
        "lint:srcfix": "eslint --ext .ts,.json src/ --fix",
        "lint:testfix": "eslint --ext .ts,.json test/ --fix",
        "lint:samplesfix": "eslint --ext .ts,.js samples/ --fix",
        "build": "npm install && npm run clean && npm run lint && npm run lint:test && npx tsc && npm run stripInternalDocs && echo Done",
        "build:samples": "npm --prefix samples run build",
        "build:prod": "npm install --production",
        "validate:samples": "npm run build && npm --prefix samples install && npm run build:samples",
        "build:nolint": "npm run clean && npm run stripInternalDocs && echo Done",
        "stripInternalDocs": "tsc --pretty -p tsconfig.nocomments",
        "test": "npm run build && mocha --recursive ./lib/test/**/*-spec.js",
        "test:nolint": "npm run build:nolint && mocha --recursive ./lib/test/**/*-spec.js",
        "watch": "tsc --watch",
        "watch:test": "npm run test -- --watch",
        "docs": "typedoc --excludePrivate --mode file --out ./lib/docs ./src",
        "e2etst": "npm run"
    },
    "dependencies": {
        "@azure/functions": "^4.14.0",
        "@opentelemetry/api": "^1.9.0",
        "axios": "^1.16.1",
        "debug": "~2.6.9",
        "lodash": "^4.18.1",
        "moment": "^2.29.2",
        "uuid": "^9.0.1",
        "validator": "~13.15.20"
    },
    "devDependencies": {
        "@types/chai": "~4.1.6",
        "@types/chai-as-promised": "~7.1.0",
        "@types/chai-string": "~1.4.1",
        "@types/debug": "0.0.29",
        "@types/lodash": "^4.14.119",
        "@types/mocha": "^7.0.2",
        "@types/nock": "^9.3.0",
        "@types/node": "^18.0.0",
        "@types/rimraf": "0.0.28",
        "@types/sinon": "~5.0.5",
        "@types/uuid": "^9.0.7",
        "@types/validator": "^9.4.3",
        "@typescript-eslint/eslint-plugin": "^5.4.0",
        "@typescript-eslint/parser": "^5.4.0",
        "chai": "~4.2.0",
        "chai-as-promised": "~7.1.1",
        "chai-string": "~1.5.0",
        "eslint": "^7.32.0",
        "eslint-config-prettier": "^6.15.0",
        "eslint-plugin-prettier": "^3.4.1",
        "mocha": "^11.2.2",
        "nock": "^10.0.6",
        "prettier": "^2.0.5",
        "rimraf": "~2.5.4",
        "sinon": "~7.1.1",
        "ts-node": "^10.0.0",
        "typedoc": "^0.22.11",
        "typescript": "~4.5.0"
    },
    "bugs": {
        "url": "https://github.com/Azure/azure-functions-durable-js/issues"
    },
    "homepage": "https://github.com/Azure/azure-functions-durable-js#readme",
    "directories": {
        "lib": "lib",
        "test": "test"
    }
}


================================================
FILE: samples-js/.funcignore
================================================
*.js.map
*.ts
.git*
.vscode
local.settings.json
test
tsconfig.json

================================================
FILE: samples-js/.gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# next.js build output
.next

# nuxt.js build output
.nuxt

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TypeScript output
dist
out

# Azure Functions artifacts
bin
obj
appsettings.json
local.settings.json

# Azurite artifacts
__blobstorage__
__queuestorage__
__azurite_db*__.json

================================================
FILE: samples-js/functions/backupSiteContent.js
================================================
const df = require("durable-functions");
const fs = require("fs/promises");
const readdirp = require("readdirp");
const path = require("path");
const { output } = require("@azure/functions");

const getFileListActivityName = "getFileList";
const copyFileToBlobActivityName = "copyFileToBlob";

df.app.orchestration("backupSiteContent", function* (context) {
    const rootDir = context.df.getInput();
    if (!rootDir) {
        throw new Error("A directory path is required as an input.");
    }

    const rootDirAbs = path.resolve(rootDir);
    const files = yield context.df.callActivity(getFileListActivityName, rootDirAbs);

    // Backup Files and save Tasks into array
    const tasks = [];
    for (const file of files) {
        const input = {
            backupPath: path.relative(rootDirAbs, file).replace(/\\/g, "/"),
            filePath: file,
        };
        tasks.push(context.df.callActivity(copyFileToBlobActivityName, input));
    }

    // wait for all the Backup Files Activities to complete, sum total bytes
    const results = yield context.df.Task.all(tasks);
    const totalBytes = results ? results.reduce((prev, curr) => prev + curr, 0) : 0;

    // return results;
    return totalBytes;
});

df.app.activity(getFileListActivityName, {
    handler: async function (rootDirectory, context) {
        context.log(`Searching for files under '${rootDirectory}'...`);

        const allFilePaths = [];
        for await (const entry of readdirp(rootDirectory, { type: "files" })) {
            allFilePaths.push(entry.fullPath);
        }
        context.log(`Found ${allFilePaths.length} under ${rootDirectory}.`);
        return allFilePaths;
    },
});

const blobOutput = output.storageBlob({
    path: "backups/{backupPath}",
    connection: "StorageConnString",
});

df.app.activity(copyFileToBlobActivityName, {
    extraOutputs: [blobOutput],
    handler: async function ({ backupPath, filePath }, context) {
        const outputLocation = `backups/${backupPath}`;
        const stats = await fs.stat(filePath);
        context.log(`Copying '${filePath}' to '${outputLocation}'. Total bytes = ${stats.size}.`);

        const fileContents = await fs.readFile(filePath);

        context.extraOutputs.set(blobOutput, fileContents);

        return stats.size;
    },
});


================================================
FILE: samples-js/functions/callActivityWithRetry.js
================================================
const df = require("durable-functions");

df.app.orchestration("callActivityWithRetry", function* (context) {
    const retryOptions = new df.RetryOptions(1000, 2);
    let returnValue;

    try {
        returnValue = yield context.df.callActivityWithRetry("flakyFunction", retryOptions);
    } catch (e) {
        context.log("Orchestrator caught exception. Flaky function is extremely flaky.");
    }

    return returnValue;
});

df.app.activity("flakyFunction", {
    handler: function (_input, context) {
        context.log("Flaky Function Flaking!");
        throw Error("FlakyFunction flaked");
    },
});


================================================
FILE: samples-js/functions/callSubOrchestratorWithRetry.js
================================================
const df = require("durable-functions");

const subOrchestratorName = "throwsErrorInLine";

df.app.orchestration("callSubOrchestratorWithRetry", function* (context) {
    const retryOptions = new df.RetryOptions(10000, 2);
    const childId = `${context.df.instanceId}:0`;

    let returnValue;

    try {
        returnValue = yield context.df.callSubOrchestratorWithRetry(
            subOrchestratorName,
            retryOptions,
            "Matter",
            childId
        );
    } catch (e) {
        context.log("Orchestrator caught exception. Sub-orchestrator failed.");
    }

    return returnValue;
});

df.app.orchestration(subOrchestratorName, function* () {
    throw Error(`${subOrchestratorName} does what it says on the tin.`);
});


================================================
FILE: samples-js/functions/cancelTimer.js
================================================
const df = require("durable-functions");
const { DateTime } = require("luxon");

df.app.orchestration("cancelTimer", function* (context) {
    const expiration = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({ minutes: 2 });
    const timeoutTask = context.df.createTimer(expiration.toJSDate());

    const hello = yield context.df.callActivity("sayHello", "from the other side");

    if (!timeoutTask.isCompleted) {
        timeoutTask.cancel();
    }

    return hello;
});


================================================
FILE: samples-js/functions/continueAsNewCounter.js
================================================
const df = require("durable-functions");
const { DateTime } = require("luxon");

df.app.orchestration("continueAsNewCounter", function* (context) {
    let currentValue = context.df.getInput() || 0;
    context.log(`Value is ${currentValue}`);
    currentValue++;

    const wait = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({ seconds: 30 });
    context.log("Counting up at" + wait.toString());
    yield context.df.createTimer(wait.toJSDate());

    if (currentValue < 10) {
        context.df.continueAsNew(currentValue);
    }

    return currentValue;
});


================================================
FILE: samples-js/functions/counter.js
================================================
const df = require("durable-functions");

const counterEntityName = "counterEntity";

df.app.entity(counterEntityName, async function (context) {
    await Promise.resolve();
    let currentValue = context.df.getState(() => 0);

    switch (context.df.operationName) {
        case "add":
            const amount = context.df.getInput();
            currentValue += amount;
            break;
        case "reset":
            currentValue = 0;
            break;
        case "get":
            context.df.return(currentValue);
            break;
    }

    context.df.setState(currentValue);
});

df.app.orchestration("counterOrchestration", function* (context) {
    const entityId = new df.EntityId(counterEntityName, "myCounter");

    currentValue = yield context.df.callEntity(entityId, "get");
    if (currentValue < 10) {
        yield context.df.callEntity(entityId, "add", 1);
    }
});


================================================
FILE: samples-js/functions/httpStart.js
================================================
const df = require("durable-functions");
const { app } = require("@azure/functions");

app.http("httpStart", {
    route: "orchestrators/{orchestratorName}",
    extraInputs: [df.input.durableClient()],
    handler: async (request, context) => {
        const client = df.getClient(context);
        const body = await request.json();
        const instanceId = await client.startNew(request.params.orchestratorName, { input: body });

        context.log(`Started orchestration with ID = '${instanceId}'.`);

        return client.createCheckStatusResponse(request, instanceId);
    },
});


================================================
FILE: samples-js/functions/httpSyncStart.js
================================================
const { app } = require("@azure/functions");
const df = require("durable-functions");

const timeout = "timeout";
const retryInterval = "retryInterval";

app.http("httpSyncStart", {
    methods: ["POST"],
    route: "orchestrators/wait/{orchestratorName}",
    authLevel: "anonymous",
    extraInputs: [df.input.durableClient()],
    handler: async function (request, context) {
        const client = df.getClient(context);
        const body = await request.json();
        const instanceId = await client.startNew(request.params.orchestratorName, { input: body });

        context.log(`Started orchestration with ID = '${instanceId}'.`);

        const timeoutInMilliseconds = getTimeInMilliseconds(request, timeout) || 30000;
        const retryIntervalInMilliseconds = getTimeInMilliseconds(request, retryInterval) || 1000;

        const response = await client.waitForCompletionOrCreateCheckStatusResponse(
            request,
            instanceId,
            {
                timeoutInMilliseconds,
                retryIntervalInMilliseconds,
            }
        );
        return response;
    },
});

function getTimeInMilliseconds(req, queryParameterName) {
    // parameters are passed in as seconds
    const queryValue = req.query.get(queryParameterName);
    // return as milliseconds
    return queryValue ? queryValue * 1000 : undefined;
}


================================================
FILE: samples-js/functions/listAzureSubscriptions.js
================================================
const df = require("durable-functions");

df.app.orchestration("listAzureSubscriptions", function* (context) {
    // More information on the use of managed identities in the callHttp API:
    // https://docs.microsoft.com/azure/azure-functions/durable/durable-functions-http-features#managed-identities
    const res = yield context.df.callHttp({
        method: "GET",
        url: "https://management.azure.com/subscriptions?api-version=2019-06-01",
        tokenSource: new df.ManagedIdentityTokenSource("https://management.core.windows.net"),
    });
    return res;
});


================================================
FILE: samples-js/functions/sayHello.js
================================================
const df = require("durable-functions");

const helloActivityName = "sayHello";

df.app.orchestration("helloSequence", function* (context) {
    context.log("Starting chain sample");

    const output = [];
    output.push(yield context.df.callActivity(helloActivityName, "Tokyo"));
    output.push(yield context.df.callActivity(helloActivityName, "Seattle"));
    output.push(yield context.df.callActivity(helloActivityName, "Cairo"));

    return output;
});

df.app.orchestration("sayHelloWithActivity", function* (context) {
    const input = context.df.getInput();

    const output = yield context.df.callActivity(helloActivityName, input);
    return output;
});

df.app.orchestration("sayHelloWithCustomStatus", function* (context) {
    const input = context.df.getInput();
    const output = yield context.df.callActivity(helloActivityName, input);
    context.df.setCustomStatus(output);
    return output;
});

df.app.orchestration("sayHelloWithSubOrchestrator", function* (context) {
    const input = context.df.getInput();

    const output = yield context.df.callSubOrchestrator("sayHelloWithActivity", input);
    return output;
});

df.app.activity(helloActivityName, {
    handler: function (input) {
        return `Hello ${input}`;
    },
});


================================================
FILE: samples-js/functions/smsPhoneVerification.js
================================================
const { output } = require("@azure/functions");
const df = require("durable-functions");
const { DateTime } = require("luxon");

const sendSmsChallengeActivityName = "sendSmsChallenge";

df.app.orchestration("smsPhoneVerification", function* (context) {
    const phoneNumber = context.df.getInput();
    if (!phoneNumber) {
        throw new Error("A phone number input is required.");
    }

    const challengeCode = yield context.df.callActivity(sendSmsChallengeActivityName, phoneNumber);

    // The user has 90 seconds to respond with the code they received in the SMS message.
    const expiration = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({ seconds: 90 });
    const timeoutTask = context.df.createTimer(expiration.toJSDate());

    let authorized = false;
    for (let i = 0; i <= 3; i++) {
        const challengeResponseTask = context.df.waitForExternalEvent("SmsChallengeResponse");

        const winner = yield context.df.Task.any([challengeResponseTask, timeoutTask]);

        if (winner === timeoutTask) {
            // Timeout expired
            break;
        }

        // We got back a response! Compare it to the challenge code.
        if (challengeResponseTask.result === challengeCode) {
            authorized = true;
            break;
        }
    }

    if (!timeoutTask.isCompleted) {
        // All pending timers must be complete or canceled before the function exits.
        timeoutTask.cancel();
    }

    return authorized;
});

const twilioOutput = output.generic({
    type: "twilioSms",
    from: "%TwilioPhoneNumber%",
    accountSidSetting: "TwilioAccountSid",
    authTokenSetting: "TwilioAuthToken",
});

df.app.activity(sendSmsChallengeActivityName, {
    extraOutputs: [twilioOutput],
    handler: function (phoneNumber, context) {
        // Get a random challenge code
        const challengeCode = Math.floor(Math.random() * 10000);

        context.log(`Sending verification code ${challengeCode} to ${phoneNumber}.`);

        context.extraOutputs.set(twilioOutput, {
            body: `Your verification code is ${challengeCode.toPrecision(4)}`,
            to: phoneNumber,
        });

        return challengeCode;
    },
});


================================================
FILE: samples-js/functions/weatherMonitor.js
================================================
const { output } = require("@azure/functions");
const df = require("durable-functions");
const { DateTime } = require("luxon");
const axios = require("axios").default;

const clearWeatherConditions = ["clear sky", "few clouds", "scattered clouds", "broken clouds"];

const getIsClearActivity = "getIsClear";
const sendGoodWeatherAlertActivity = "sendGoodWeatherAlert";

df.app.orchestration("weatherMonitor", function* (context) {
    // get input
    const input = context.df.getInput();
    context.log(`Received monitor request. Location: ${input.location}. Phone: ${input.phone}`);
    verifyRequest(input);

    // set expiry time to 6 hours from now
    const endTime = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({ hours: 6 });
    const locationString = `${input.location.city}${
        input.location.state ? `, ${input.location.state}` : ""
    }, ${input.location.country}`;
    context.log(`Instantiating monitor for ${locationString}. Expires: ${endTime.toString()}.`);

    // until the expiry time
    while (DateTime.fromJSDate(context.df.currentUtcDateTime) < endTime) {
        // Check the weather
        context.log(
            `Checking current weather conditions for ${locationString} at ${context.df.currentUtcDateTime}.`
        );
        const isClear = yield context.df.callActivity(getIsClearActivity, input.location);

        if (isClear) {
            // It's not raining! Or snowing. Or misting. Tell our user to take advantage of it.
            context.log(`Detected clear weather for ${locationString}. Notifying ${input.phone}.`);
            yield context.df.callActivity(sendGoodWeatherAlertActivity, input.phone);
            break;
        } else {
            // Wait for the next checkpoint
            const nextCheckpoint = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({
                seconds: 30,
            });

            context.log(`Next check for ${locationString} at ${nextCheckpoint.toString()}`);

            yield context.df.createTimer(nextCheckpoint.toJSDate());
        }
    }

    context.log("Monitor expiring.");
});

function verifyRequest(request) {
    if (!request) {
        throw new Error("An input object is required.");
    }
    if (!request.location) {
        throw new Error("A location input is required.");
    }
    if (!request.location.city) {
        throw new Error("A city is required on the location input.");
    }
    if (!request.location.country) {
        throw new Error("A country code is required on location input.");
    }
    if (
        (request.location.country === "USA" || request.location.country === "US") &&
        !request.location.state
    ) {
        throw new Error("A state code is required on location input for US locations.");
    }
    if (!request.phone) {
        throw new Error("A phone number input is required.");
    }
}

df.app.activity(getIsClearActivity, {
    handler: async function (location, context) {
        try {
            // get current conditions from OpenWeatherMap API
            const currentConditions = await getCurrentConditions(location);
            // compare against known clear conditions
            return clearWeatherConditions.includes(currentConditions.description);
        } catch (err) {
            context.log(`${getIsClearActivity} encountered an error: ${err}`);
            throw err;
        }
    },
});

async function getCurrentConditions(location) {
    try {
        // get current conditions from OpenWeatherMap API
        const url = location.state
            ? `https://api.openweathermap.org/data/2.5/weather?q=${location.city},${location.state},${location.country}&appid=${process.env.OpenWeatherMapApiKey}`
            : `https://api.openweathermap.org/data/2.5/weather?q=${location.city},${location.country}&appid=${process.env.OpenWeatherMapApiKey}`;

        const response = await axios.get(url);
        return response.data.weather[0];
    } catch (err) {
        throw err;
    }
}

// configure twilio output
const twilioOutput = output.generic({
    type: "twilioSms",
    from: "%TwilioPhoneNumber%",
    accountSidSetting: "TwilioAccountSid",
    authTokenSetting: "TwilioAuthToken",
});

df.app.activity(sendGoodWeatherAlertActivity, {
    extraOutputs: [twilioOutput], // register twilio output
    handler: function (phoneNumber, context) {
        // send message to phone number
        context.extraOutputs.set(twilioOutput, {
            body: "The weather's clear outside! Go talk a walk!",
            to: phoneNumber,
        });
    },
});


================================================
FILE: samples-js/host.json
================================================
{
    "version": "2.0",
    "logging": {
        "applicationInsights": {
            "samplingSettings": {
                "isEnabled": true,
                "excludedTypes": "Request"
            }
        }
    },
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[3.15.0, 4.0.0)"
    }
}


================================================
FILE: samples-js/package.json
================================================
{
    "name": "samples-js",
    "version": "1.0.0",
    "description": "",
    "main": "functions/*.js",
    "scripts": {
        "start": "func start",
        "test": "echo \"No tests yet...\""
    },
    "dependencies": {
        "@azure/functions": "^4.14.0",
        "axios": "^1.16.1",
        "durable-functions": "file:../durable-functions",
        "luxon": "^3.2.1",
        "readdirp": "^3.6.0"
    }
}


================================================
FILE: samples-ts/.funcignore
================================================
*.js.map
*.ts
.git*
.vscode
local.settings.json
test
tsconfig.json

================================================
FILE: samples-ts/.gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# next.js build output
.next

# nuxt.js build output
.nuxt

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TypeScript output
dist
out

# Azure Functions artifacts
bin
obj
appsettings.json
local.settings.json

# Azurite artifacts
__blobstorage__
__queuestorage__
__azurite_db*__.json

================================================
FILE: samples-ts/.vscode/extensions.json
================================================
{
  "recommendations": [
    "ms-azuretools.vscode-azurefunctions"
  ]
}

================================================
FILE: samples-ts/.vscode/launch.json
================================================
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Attach to Node Functions",
            "type": "node",
            "request": "attach",
            "port": 9229,
            "preLaunchTask": "func: host start"
        }
    ]
}


================================================
FILE: samples-ts/.vscode/settings.json
================================================
{
    "azureFunctions.deploySubpath": ".",
    "azureFunctions.postDeployTask": "npm install (functions)",
    "azureFunctions.projectLanguage": "TypeScript",
    "azureFunctions.projectRuntime": "~4",
    "debug.internalConsoleOptions": "neverOpen",
    "azureFunctions.preDeployTask": "npm prune (functions)"
}


================================================
FILE: samples-ts/.vscode/tasks.json
================================================
{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "func",
            "label": "func: host start",
            "command": "host start",
            "problemMatcher": "$func-node-watch",
            "isBackground": true,
            "dependsOn": "npm build (functions)"
        },
        {
            "type": "shell",
            "label": "npm build (functions)",
            "command": "npm run build",
            "dependsOn": "npm install (functions)",
            "problemMatcher": "$tsc"
        },
        {
            "type": "shell",
            "label": "npm install (functions)",
            "command": "npm install"
        },
        {
            "type": "shell",
            "label": "npm prune (functions)",
            "command": "npm prune --production",
            "dependsOn": "npm build (functions)",
            "problemMatcher": []
        }
    ]
}


================================================
FILE: samples-ts/functions/backupSiteContent.ts
================================================
import * as df from "durable-functions";
import * as fs from "fs/promises";
import * as readdirp from "readdirp";
import * as path from "path";
import { InvocationContext, output } from "@azure/functions";
import {
    OrchestrationHandler,
    OrchestrationContext,
    ActivityHandler,
    Task,
} from "durable-functions";
import { Stats } from "fs";

const getFileListActivityName = "getFileList";
const copyFileToBlobActivityName = "copyFileToBlob";

const backupSiteContentOrchestration: OrchestrationHandler = function* (
    context: OrchestrationContext
) {
    const rootDir: string = context.df.getInput<string>();
    if (!rootDir) {
        throw new Error("A directory path is required as an input.");
    }

    const rootDirAbs: string = path.resolve(rootDir);
    const files: string[] = yield context.df.callActivity(getFileListActivityName, rootDirAbs);

    // Backup Files and save Tasks into array
    const tasks: Task[] = [];
    for (const file of files) {
        const input = {
            backupPath: path.relative(rootDirAbs, file).replace(/\\/g, "/"),
            filePath: file,
        };
        tasks.push(context.df.callActivity(copyFileToBlobActivityName, input));
    }

    // wait for all the Backup Files Activities to complete, sum total bytes
    const results: number[] = yield context.df.Task.all(tasks);
    const totalBytes: number = results ? results.reduce((prev, curr) => prev + curr, 0) : 0;

    // return results;
    return totalBytes;
};
df.app.orchestration("backupSiteContent", backupSiteContentOrchestration);

const getFileListActivity: ActivityHandler = async function (
    rootDirectory: string,
    context: InvocationContext
): Promise<string[]> {
    context.log(`Searching for files under '${rootDirectory}'...`);

    const allFilePaths = [];
    for await (const entry of readdirp(rootDirectory, { type: "files" })) {
        allFilePaths.push(entry.fullPath);
    }
    context.log(`Found ${allFilePaths.length} under ${rootDirectory}.`);
    return allFilePaths;
};

df.app.activity(getFileListActivityName, {
    handler: getFileListActivity,
});

const blobOutput = output.storageBlob({
    path: "backups/{backupPath}",
    connection: "StorageConnString",
});

const copyFileToBlobActivity: ActivityHandler = async function (
    { backupPath, filePath }: { backupPath: string; filePath: string },
    context: InvocationContext
): Promise<number> {
    const outputLocation = `backups/${backupPath}`;
    const stats: Stats = await fs.stat(filePath);
    context.log(`Copying '${filePath}' to '${outputLocation}'. Total bytes = ${stats.size}.`);

    const fileContents = await fs.readFile(filePath);

    context.extraOutputs.set(blobOutput, fileContents);

    return stats.size;
};
df.app.activity(copyFileToBlobActivityName, {
    extraOutputs: [blobOutput],
    handler: copyFileToBlobActivity,
});


================================================
FILE: samples-ts/functions/callActivityWithRetry.ts
================================================
import { InvocationContext } from "@azure/functions";
import * as df from "durable-functions";
import {
    ActivityHandler,
    OrchestrationContext,
    OrchestrationHandler,
    RetryOptions,
} from "durable-functions";

const callActivityWithRetry: OrchestrationHandler = function* (context: OrchestrationContext) {
    const retryOptions: RetryOptions = new df.RetryOptions(1000, 2);

    let returnValue: any;
    try {
        returnValue = yield context.df.callActivityWithRetry("flakyFunction", retryOptions);
    } catch (e) {
        context.log("Orchestrator caught exception. Flaky function is extremely flaky.");
    }

    return returnValue;
};
df.app.orchestration("callActivityWithRetry", callActivityWithRetry);

const flakyFunction: ActivityHandler = function (_input: any, context: InvocationContext): void {
    context.log("Flaky Function Flaking!");
    throw new Error("FlakyFunction flaked");
};
df.app.activity("flakyFunction", {
    handler: flakyFunction,
});


================================================
FILE: samples-ts/functions/callSubOrchestratorWithRetry.ts
================================================
import * as df from "durable-functions";
import { OrchestrationContext, OrchestrationHandler } from "durable-functions";

const subOrchestratorName = "throwsErrorInLine";

const callSubOrchestratorWithRetry: OrchestrationHandler = function* (
    context: OrchestrationContext
) {
    const retryOptions: df.RetryOptions = new df.RetryOptions(10000, 2);
    const childId = `${context.df.instanceId}:0`;

    let returnValue: any;

    try {
        returnValue = yield context.df.callSubOrchestratorWithRetry(
            subOrchestratorName,
            retryOptions,
            {
                input: "Input",
                instanceId: childId,
            }
        );
    } catch (e) {
        context.log("Orchestrator caught exception. Sub-orchestrator failed.");
    }

    return returnValue;
};
df.app.orchestration("callSubOrchestratorWithRetry", callSubOrchestratorWithRetry);

const flakyOrchestrator: OrchestrationHandler = function* () {
    throw new Error(`${subOrchestratorName} does what it says on the tin.`);
};
df.app.orchestration(subOrchestratorName, flakyOrchestrator);


================================================
FILE: samples-ts/functions/cancelTimer.ts
================================================
import * as df from "durable-functions";
import { OrchestrationContext, OrchestrationHandler, TimerTask } from "durable-functions";
import { DateTime } from "luxon";

const cancelTimer: OrchestrationHandler = function* (context: OrchestrationContext) {
    const expiration: DateTime = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({
        minutes: 2,
    });
    const timeoutTask: TimerTask = context.df.createTimer(expiration.toJSDate());

    const hello: string = yield context.df.callActivity("sayHello", "from the other side");

    if (!timeoutTask.isCompleted) {
        timeoutTask.cancel();
    }

    return hello;
};
df.app.orchestration("cancelTimer", cancelTimer);


================================================
FILE: samples-ts/functions/continueAsNewCounter.ts
================================================
import * as df from "durable-functions";
import { OrchestrationContext, OrchestrationHandler } from "durable-functions";
import { DateTime } from "luxon";

const continueAsNewCounter: OrchestrationHandler = function* (context: OrchestrationContext) {
    let currentValue: number = context.df.getInput() || 0;
    context.log(`Value is ${currentValue}`);
    currentValue++;

    const wait: DateTime = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({ seconds: 30 });
    context.log("Counting up at" + wait.toString());
    yield context.df.createTimer(wait.toJSDate());

    if (currentValue < 10) {
        context.df.continueAsNew(currentValue);
    }

    return currentValue;
};

df.app.orchestration("continueAsNewCounter", continueAsNewCounter);


================================================
FILE: samples-ts/functions/counter.ts
================================================
import * as df from "durable-functions";
import {
    EntityHandler,
    EntityContext,
    OrchestrationContext,
    OrchestrationHandler,
    EntityId,
} from "durable-functions";

const counterEntityName = "counterEntity";

const counterEntity: EntityHandler<number> = async function (
    context: EntityContext<number>
): Promise<void> {
    await Promise.resolve();
    let currentValue: number = context.df.getState(() => 0);

    switch (context.df.operationName) {
        case "add":
            const amount: number = context.df.getInput();
            currentValue += amount;
            break;
        case "reset":
            currentValue = 0;
            break;
        case "get":
            context.df.return(currentValue);
            break;
    }

    context.df.setState(currentValue);
};
df.app.entity(counterEntityName, counterEntity);

const counterOrchestration: OrchestrationHandler = function* (context: OrchestrationContext) {
    const entityId: EntityId = new df.EntityId(counterEntityName, "myCounter");

    const currentValue: number = yield context.df.callEntity(entityId, "get");
    if (currentValue < 10) {
        yield context.df.callEntity(entityId, "add", 1);
    }
};
df.app.orchestration("counterOrchestration", counterOrchestration);


================================================
FILE: samples-ts/functions/httpStart.ts
================================================
import * as df from "durable-functions";
import { app, HttpHandler, HttpRequest, HttpResponse, InvocationContext } from "@azure/functions";

const httpStart: HttpHandler = async (
    request: HttpRequest,
    context: InvocationContext
): Promise<HttpResponse> => {
    const client = df.getClient(context);
    const body: unknown = await request.json();

    // Get optional version from query parameter
    const version = request.query.get("version");

    let instanceId: string;
    if (version) {
        // Override the orchestration version
        instanceId = await client.startNew(request.params.orchestratorName, {
            input: body,
            version: version,
        });
        context.log(`Started orchestration with ID = '${instanceId}' and version = '${version}'.`);
    } else {
        // Use defaultVersion from host.json
        instanceId = await client.startNew(request.params.orchestratorName, {
            input: body,
        });
        context.log(`Started orchestration with ID = '${instanceId}'.`);
    }

    return client.createCheckStatusResponse(request, instanceId);
};
app.http("httpStart", {
    route: "orchestrators/{orchestratorName}",
    extraInputs: [df.input.durableClient()],
    handler: httpStart,
});


================================================
FILE: samples-ts/functions/httpSyncStart.ts
================================================
import {
    app,
    HttpHandler,
    HttpRequest,
    HttpResponse,
    HttpResponseInit,
    InvocationContext,
} from "@azure/functions";
import * as df from "durable-functions";

const timeout = "timeout";
const retryInterval = "retryInterval";

const httpSyncStart: HttpHandler = async function (
    request: HttpRequest,
    context: InvocationContext
): Promise<HttpResponse> {
    const client = df.getClient(context);
    const body: unknown = await request.json();
    const instanceId: string = await client.startNew(request.params.orchestratorName, {
        input: body,
    });

    context.log(`Started orchestration with ID = '${instanceId}'.`);

    const timeoutInMilliseconds: number = getTimeInMilliseconds(request, timeout) || 30000;
    const retryIntervalInMilliseconds: number =
        getTimeInMilliseconds(request, retryInterval) || 1000;

    const response = await client.waitForCompletionOrCreateCheckStatusResponse(
        request,
        instanceId,
        {
            timeoutInMilliseconds,
            retryIntervalInMilliseconds,
        }
    );
    return response;
};

app.http("httpSyncStart", {
    methods: ["POST"],
    route: "orchestrators/wait/{orchestratorName}",
    authLevel: "anonymous",
    extraInputs: [df.input.durableClient()],
    handler: httpSyncStart,
});

function getTimeInMilliseconds(req: HttpRequest, queryParameterName: string): number {
    // parameters are passed in as seconds
    const queryValue: number = parseInt(req.query.get(queryParameterName));
    // return as milliseconds
    return queryValue ? queryValue * 1000 : undefined;
}


================================================
FILE: samples-ts/functions/listAzureSubscriptions.ts
================================================
import * as df from "durable-functions";
import { OrchestrationContext, OrchestrationHandler } from "durable-functions";

const listAzureSubscriptions: OrchestrationHandler = function* (context: OrchestrationContext) {
    // More information on the use of managed identities in the callHttp API:
    // https://docs.microsoft.com/azure/azure-functions/durable/durable-functions-http-features#managed-identities
    const res = yield context.df.callHttp({
        method: "GET",
        url: "https://management.azure.com/subscriptions?api-version=2019-06-01",
        tokenSource: new df.ManagedIdentityTokenSource("https://management.core.windows.net"),
    });
    return res;
};
df.app.orchestration("listAzureSubscriptions", listAzureSubscriptions);


================================================
FILE: samples-ts/functions/orchestrationVersion.ts
================================================
import * as df from "durable-functions";
import { ActivityHandler, OrchestrationContext, OrchestrationHandler } from "durable-functions";

const versionedOrchestrator: OrchestrationHandler = function* (context: OrchestrationContext) {
    // context.df.version contains the value of defaultVersion in host.json
    // at the moment when the orchestration was created.
    let activityResult;
    if (context.df.version === "1.0") {
        // Legacy code path
        activityResult = yield context.df.callActivity("ActivityA");
    } else {
        // New code path
        activityResult = yield context.df.callActivity("ActivityB");
    }

    // Provide an opportunity to update and restart the app
    context.df.setCustomStatus("Waiting for Continue event...");
    yield context.df.waitForExternalEvent("Continue");
    context.df.setCustomStatus("Continue event received");

    // You can explicitly pass a version to sub-orchestrators
    const subOrchestratorWithVersionResult = yield context.df.callSubOrchestrator(
        "versionedSuborchestrator",
        undefined, // input
        undefined, // instanceId
        "0.9" // version override
    );

    // Without specifying version, the sub-orchestrator will use the current defaultVersion
    const subOrchestratorResult = yield context.df.callSubOrchestrator("versionedSuborchestrator");

    return [
        `Orchestration version: ${context.df.version}`,
        `Suborchestration version (explicit): ${subOrchestratorWithVersionResult}`,
        `Suborchestration version (default): ${subOrchestratorResult}`,
        `Activity result: ${activityResult}`,
    ];
};
df.app.orchestration("versionedOrchestrator", versionedOrchestrator);

const versionedSuborchestrator: OrchestrationHandler = function* (context: OrchestrationContext) {
    return context.df.version;
};
df.app.orchestration("versionedSuborchestrator", versionedSuborchestrator);

const ActivityA: ActivityHandler = (): string => {
    return `Hello from A`;
};
df.app.activity("ActivityA", { handler: ActivityA });

const ActivityB: ActivityHandler = (): string => {
    return `Hello from B`;
};
df.app.activity("ActivityB", { handler: ActivityB });


================================================
FILE: samples-ts/functions/sayHello.ts
================================================
import * as df from "durable-functions";
import { ActivityHandler, OrchestrationContext, OrchestrationHandler } from "durable-functions";

const helloActivityName = "sayHello";

const helloSequence: OrchestrationHandler = function* (context: OrchestrationContext) {
    context.log("Starting chain sample");

    const output: string[] = [];
    output.push(yield context.df.callActivity(helloActivityName, "Tokyo"));
    output.push(yield context.df.callActivity(helloActivityName, "Seattle"));
    output.push(yield context.df.callActivity(helloActivityName, "Cairo"));

    return output;
};
df.app.orchestration("helloSequence", helloSequence);

const sayHelloWithActivity: OrchestrationHandler = function* (context: OrchestrationContext) {
    const input: unknown = context.df.getInput();

    const output: string = yield context.df.callActivity(helloActivityName, input);
    return output;
};
df.app.orchestration("sayHelloWithActivity", sayHelloWithActivity);

const sayHelloWithCustomStatus: OrchestrationHandler = function* (context: OrchestrationContext) {
    const input: unknown = context.df.getInput();
    const output: string = yield context.df.callActivity(helloActivityName, input);
    context.df.setCustomStatus(output);
    return output;
};
df.app.orchestration("sayHelloWithCustomStatus", sayHelloWithCustomStatus);

const sayHelloWithSubOrchestrator: OrchestrationHandler = function* (
    context: OrchestrationContext
) {
    const input: unknown = context.df.getInput();

    const output: string = yield context.df.callSubOrchestrator("sayHelloWithActivity", { input });
    return output;
};
df.app.orchestration("sayHelloWithSubOrchestrator", sayHelloWithSubOrchestrator);

const helloActivity: ActivityHandler = function (input: unknown): string {
    return `Hello ${input}`;
};
df.app.activity(helloActivityName, {
    handler: helloActivity,
});


================================================
FILE: samples-ts/functions/smsPhoneVerification.ts
================================================
import { InvocationContext, output } from "@azure/functions";
import * as df from "durable-functions";
import {
    ActivityHandler,
    OrchestrationContext,
    OrchestrationHandler,
    Task,
    TimerTask,
} from "durable-functions";
import { DateTime } from "luxon";

const sendSmsChallengeActivityName = "sendSmsChallenge";

const smsPhoneVerification: OrchestrationHandler = function* (context: OrchestrationContext) {
    const phoneNumber: string = context.df.getInput();
    if (!phoneNumber) {
        throw new Error("A phone number input is required.");
    }

    const challengeCode: number = yield context.df.callActivity(
        sendSmsChallengeActivityName,
        phoneNumber
    );

    // The user has 90 seconds to respond with the code they received in the SMS message.
    const expiration: DateTime = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({
        seconds: 90,
    });
    const timeoutTask: TimerTask = context.df.createTimer(expiration.toJSDate());

    let authorized = false;
    for (let i = 0; i <= 3; i++) {
        const challengeResponseTask: Task = context.df.waitForExternalEvent("SmsChallengeResponse");

        const winner: Task = yield context.df.Task.any([challengeResponseTask, timeoutTask]);

        if (winner === timeoutTask) {
            // Timeout expired
            break;
        }

        // We got back a response! Compare it to the challenge code.
        if (challengeResponseTask.result === challengeCode) {
            authorized = true;
            break;
        }
    }

    if (!timeoutTask.isCompleted) {
        // All pending timers must be complete or canceled before the function exits.
        timeoutTask.cancel();
    }

    return authorized;
};
df.app.orchestration("smsPhoneVerification", smsPhoneVerification);

const twilioOutput = output.generic({
    type: "twilioSms",
    from: "%TwilioPhoneNumber%",
    accountSidSetting: "TwilioAccountSid",
    authTokenSetting: "TwilioAuthToken",
});

const sendSmsChallenge: ActivityHandler = function (
    phoneNumber: string,
    context: InvocationContext
): number {
    // Get a random challenge code
    const challengeCode: number = Math.floor(Math.random() * 10000);

    context.log(`Sending verification code ${challengeCode} to ${phoneNumber}.`);

    context.extraOutputs.set(twilioOutput, {
        body: `Your verification code is ${challengeCode.toPrecision(4)}`,
        to: phoneNumber,
    });

    return challengeCode;
};

df.app.activity(sendSmsChallengeActivityName, {
    extraOutputs: [twilioOutput],
    handler: sendSmsChallenge,
});


================================================
FILE: samples-ts/functions/weatherMonitor.ts
================================================
import { InvocationContext, output } from "@azure/functions";
import * as df from "durable-functions";
import { DateTime } from "luxon";
import axios from "axios";
import { ActivityHandler, OrchestrationContext, OrchestrationHandler } from "durable-functions";

const clearWeatherConditions = ["clear sky", "few clouds", "scattered clouds", "broken clouds"];

const getIsClearActivityName = "getIsClear";
const sendGoodWeatherAlertActivityName = "sendGoodWeatherAlert";

interface Location {
    city: string;
    state?: string;
    country: string;
}

interface WeatherMonitorInput {
    location: Location;
    phone: string;
}

interface WeatherApiResponse {
    data: {
        weather: WeatherData[];
    };
}

interface WeatherData {
    description: string;
}

const weatherMonitor: OrchestrationHandler = function* (context: OrchestrationContext) {
    // get input
    const input: WeatherMonitorInput = context.df.getInput();
    context.log(`Received monitor request. Location: ${input.location}. Phone: ${input.phone}`);
    verifyRequest(input);

    // set expiry time to 6 hours from now
    const endTime: DateTime = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({
        hours: 6,
    });
    const locationString = `${input.location.city}${
        input.location.state ? `, ${input.location.state}` : ""
    }, ${input.location.country}`;
    context.log(`Instantiating monitor for ${locationString}. Expires: ${endTime.toString()}.`);

    // until the expiry time
    while (DateTime.fromJSDate(context.df.currentUtcDateTime) < endTime) {
        // Check the weather
        context.log(
            `Checking current weather conditions for ${locationString} at ${context.df.currentUtcDateTime}.`
        );
        const isClear: boolean = yield context.df.callActivity(
            getIsClearActivityName,
            input.location
        );

        if (isClear) {
            // It's not raining! Or snowing. Or misting. Tell our user to take advantage of it.
            context.log(`Detected clear weather for ${locationString}. Notifying ${input.phone}.`);
            yield context.df.callActivity(sendGoodWeatherAlertActivityName, input.phone);
            break;
        } else {
            // Wait for the next checkpoint
            const nextCheckpoint: DateTime = DateTime.fromJSDate(
                context.df.currentUtcDateTime
            ).plus({
                seconds: 30,
            });

            context.log(`Next check for ${locationString} at ${nextCheckpoint.toString()}`);

            yield context.df.createTimer(nextCheckpoint.toJSDate());
        }
    }

    context.log("Monitor expiring.");
};
df.app.orchestration("weatherMonitor", weatherMonitor);

function verifyRequest(request: any): void {
    if (!request) {
        throw new Error("An input object is required.");
    }
    if (!request.location) {
        throw new Error("A location input is required.");
    }
    if (!request.location.city) {
        throw new Error("A city is required on the location input.");
    }
    if (!request.location.country) {
        throw new Error("A country code is required on location input.");
    }
    if (
        (request.location.country === "USA" || request.location.country === "US") &&
        !request.location.state
    ) {
        throw new Error("A state code is required on location input for US locations.");
    }
    if (!request.phone) {
        throw new Error("A phone number input is required.");
    }
}

const getIsClearActivity: ActivityHandler = async function (
    location: Location,
    context: InvocationContext
): Promise<boolean> {
    try {
        // get current conditions from OpenWeatherMap API
        const currentConditions = await getCurrentConditions(location);
        // compare against known clear conditions
        return clearWeatherConditions.includes(currentConditions.description);
    } catch (err) {
        context.log(`${getIsClearActivityName} encountered an error: ${err}`);
        throw err;
    }
};
df.app.activity(getIsClearActivityName, {
    handler: getIsClearActivity,
});

async function getCurrentConditions(location: Location): Promise<WeatherData> {
    try {
        // get current conditions from OpenWeatherMap API
        const url = location.state
            ? `https://api.openweathermap.org/data/2.5/weather?q=${location.city},${location.state},${location.country}&appid=${process.env.OpenWeatherMapApiKey}`
            : `https://api.openweathermap.org/data/2.5/weather?q=${location.city},${location.country}&appid=${process.env.OpenWeatherMapApiKey}`;

        const response: WeatherApiResponse = await axios.get(url);
        return response.data.weather[0];
    } catch (err) {
        throw err;
    }
}

// configure twilio output
const twilioOutput = output.generic({
    type: "twilioSms",
    from: "%TwilioPhoneNumber%",
    accountSidSetting: "TwilioAccountSid",
    authTokenSetting: "TwilioAuthToken",
});

const sendGoodWeatherAlertActivity: ActivityHandler = function (
    phoneNumber: string,
    context: InvocationContext
): void {
    // send message to phone number
    context.extraOutputs.set(twilioOutput, {
        body: "The weather's clear outside! Go talk a walk!",
        to: phoneNumber,
    });
};

df.app.activity(sendGoodWeatherAlertActivityName, {
    extraOutputs: [twilioOutput], // register twilio output
    handler: sendGoodWeatherAlertActivity,
});


================================================
FILE: samples-ts/host.json
================================================
{
    "version": "2.0",
    "logging": {
        "applicationInsights": {
            "samplingSettings": {
                "isEnabled": true,
                "excludedTypes": "Request"
            }
        }
    },
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.26.0, 5.0.0)"
    },
    "extensions": {
        "durableTask": {
            "defaultVersion": "1.0"
        }
    }
}


================================================
FILE: samples-ts/package.json
================================================
{
    "name": "samples-ts",
    "version": "1.0.0",
    "description": "",
    "main": "dist/functions/*.js",
    "scripts": {
        "build": "tsc",
        "watch": "tsc -w",
        "prestart": "npm run build",
        "start": "func start",
        "test": "echo \"No tests yet...\""
    },
    "devDependencies": {
        "@types/luxon": "^3.2.0",
        "@types/node": "16.x",
        "typescript": "^4.0.0"
    },
    "dependencies": {
        "@azure/functions": "^4.14.0",
        "axios": "^1.16.1",
        "durable-functions": "file:../durable-functions",
        "luxon": "^3.2.1",
        "readdirp": "^3.6.0"
    }
}


================================================
FILE: samples-ts/tsconfig.json
================================================
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "outDir": "dist",
        "rootDir": ".",
        "sourceMap": true,
        "strict": false
    }
}


================================================
FILE: src/Constants.ts
================================================
/** @hidden */
export class Constants {
    public static readonly DefaultLocalHost: string = "localhost:7071";
    public static readonly DefaultLocalOrigin: string = `http://${Constants.DefaultLocalHost}`;
}


================================================
FILE: src/ManagedIdentityTokenSource.ts
================================================
import * as types from "durable-functions";

export class ManagedIdentityTokenSource implements types.ManagedIdentityTokenSource {
    /** @hidden */
    public readonly kind: string = "AzureManagedIdentity";

    constructor(public readonly resource: string) {}
}


================================================
FILE: src/RetryOptions.ts
================================================
import { Utils } from "./util/Utils";
import * as types from "durable-functions";

export class RetryOptions implements types.RetryOptions {
    public backoffCoefficient: number;
    public maxRetryIntervalInMilliseconds: number;
    public retryTimeoutInMilliseconds: number;

    constructor(
        public readonly firstRetryIntervalInMilliseconds: number,
        public readonly maxNumberOfAttempts: number
    ) {
        Utils.throwIfNotNumber(
            firstRetryIntervalInMilliseconds,
            "firstRetryIntervalInMilliseconds"
        );
        Utils.throwIfNotNumber(maxNumberOfAttempts, "maxNumberOfAttempts");

        if (firstRetryIntervalInMilliseconds <= 0) {
            throw new RangeError("firstRetryIntervalInMilliseconds value must be greater than 0.");
        }
    }
}


================================================
FILE: src/actions/ActionType.ts
================================================
/**
 * @hidden
 *
 * The type of asynchronous behavior the Durable Functions extension should
 * perform on behalf of the language shim. For internal use only as part of the
 * [out-of-proc execution schema.](https://github.com/Azure/azure-functions-durable-extension/wiki/Out-of-Proc-Orchestrator-Execution-Schema-Reference)
 *
 * Corresponds to internal type AsyncActionType in [Durable Functions extension.](https://github.com/Azure/azure-functions-durable-extension)
 */
export enum ActionType {
    CallActivity = 0,
    CallActivityWithRetry = 1,
    CallSubOrchestrator = 2,
    CallSubOrchestratorWithRetry = 3,
    ContinueAsNew = 4,
    CreateTimer = 5,
    WaitForExternalEvent = 6,
    CallEntity = 7,
    CallHttp = 8,
    SignalEntity = 9,
    // ActionType 10 corresponds to ScheduledSignalEntity, which is not supported yet
    WhenAny = 11,
    WhenAll = 12,
}


================================================
FILE: src/actions/CallActivityAction.ts
================================================
import { Utils } from "../util/Utils";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class CallActivityAction implements IAction {
    public readonly actionType: ActionType = ActionType.CallActivity;
    public readonly input: unknown;

    constructor(public readonly functionName: string, input?: unknown) {
        this.input = Utils.processInput(input);
        Utils.throwIfEmpty(functionName, "functionName");
    }
}


================================================
FILE: src/actions/CallActivityWithRetryAction.ts
================================================
import { Utils } from "../util/Utils";
import { RetryOptions } from "../RetryOptions";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class CallActivityWithRetryAction implements IAction {
    public readonly actionType: ActionType = ActionType.CallActivityWithRetry;
    public readonly input: unknown;

    constructor(
        public readonly functionName: string,
        public readonly retryOptions: RetryOptions,
        input?: unknown
    ) {
        this.input = Utils.processInput(input);
        Utils.throwIfEmpty(functionName, "functionName");

        Utils.throwIfNotInstanceOf<RetryOptions>(
            retryOptions,
            "retryOptions",
            new RetryOptions(1, 1),
            "RetryOptions"
        );
    }
}


================================================
FILE: src/actions/CallEntityAction.ts
================================================
import { EntityId } from "../entities/EntityId";
import { Utils } from "../util/Utils";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class CallEntityAction implements IAction {
    public readonly actionType: ActionType = ActionType.CallEntity;
    public readonly instanceId: string;
    public readonly input: unknown;

    constructor(entityId: EntityId, public readonly operation: string, input?: unknown) {
        if (!entityId) {
            throw new Error("Must provide EntityId to CallEntityAction constructor");
        }
        this.input = input;
        Utils.throwIfEmpty(operation, "operation");
        this.instanceId = EntityId.getSchedulerIdFromEntityId(entityId);
    }
}


================================================
FILE: src/actions/CallHttpAction.ts
================================================
import { DurableHttpRequest } from "../http/DurableHttpRequest";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class CallHttpAction implements IAction {
    public readonly actionType: ActionType = ActionType.CallHttp;

    constructor(public readonly httpRequest: DurableHttpRequest) {}
}


================================================
FILE: src/actions/CallSubOrchestratorAction.ts
================================================
import { Utils } from "../util/Utils";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class CallSubOrchestratorAction implements IAction {
    public readonly actionType: ActionType = ActionType.CallSubOrchestrator;
    public readonly input: unknown;

    constructor(
        public readonly functionName: string,
        public readonly instanceId?: string,
        input?: unknown,
        public readonly version?: string
    ) {
        this.input = input;
        Utils.throwIfEmpty(functionName, "functionName");

        if (instanceId) {
            Utils.throwIfEmpty(instanceId, "instanceId");
        }
    }
}


================================================
FILE: src/actions/CallSubOrchestratorWithRetryAction.ts
================================================
import { RetryOptions } from "../RetryOptions";
import { Utils } from "../util/Utils";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class CallSubOrchestratorWithRetryAction implements IAction {
    public readonly actionType: ActionType = ActionType.CallSubOrchestratorWithRetry;
    public readonly input: unknown;

    constructor(
        public readonly functionName: string,
        public readonly retryOptions: RetryOptions,
        input?: unknown,
        public readonly instanceId?: string,
        public readonly version?: string
    ) {
        this.input = input;
        Utils.throwIfEmpty(functionName, "functionName");

        Utils.throwIfNotInstanceOf<RetryOptions>(
            retryOptions,
            "retryOptions",
            new RetryOptions(1, 1),
            "RetryOptions"
        );

        if (instanceId) {
            Utils.throwIfEmpty(instanceId, "instanceId");
        }
    }
}


================================================
FILE: src/actions/ContinueAsNewAction.ts
================================================
import { Utils } from "../util/Utils";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class ContinueAsNewAction implements IAction {
    public readonly actionType: ActionType = ActionType.ContinueAsNew;
    public readonly input: unknown;

    constructor(input: unknown) {
        this.input = Utils.processInput(input);
    }
}


================================================
FILE: src/actions/CreateTimerAction.ts
================================================
import { types } from "util";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class CreateTimerAction implements IAction {
    public readonly actionType: ActionType = ActionType.CreateTimer;

    constructor(public readonly fireAt: Date, public isCanceled: boolean = false) {
        if (!types.isDate(fireAt)) {
            throw new TypeError(`fireAt: Expected valid Date object but got ${fireAt}`);
        }
    }
}


================================================
FILE: src/actions/ExternalEventType.ts
================================================
/**
 * @hidden
 * Represents the options that can be provided for the "reason" field of events in
 * Durable Functions 2.0.
 */
export enum ExternalEventType {
    ExternalEvent = "ExternalEvent",
    LockAcquisitionCompleted = "LockAcquisitionCompleted",
    EntityResponse = "EntityResponse",
}


================================================
FILE: src/actions/IAction.ts
================================================
import { ActionType } from "./ActionType";

/** @hidden */
export interface IAction {
    actionType: ActionType;
}


================================================
FILE: src/actions/SignalEntityAction.ts
================================================
import { EntityId } from "../entities/EntityId";
import { Utils } from "../util/Utils";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class SignalEntityAction implements IAction {
    public readonly actionType: ActionType = ActionType.SignalEntity;
    public readonly instanceId: string;
    public readonly input: unknown;

    constructor(entityId: EntityId, public readonly operation: string, input?: unknown) {
        if (!entityId) {
            throw new Error("Must provide EntityId to SignalEntityAction constructor");
        }
        this.input = input;
        Utils.throwIfEmpty(operation, "operation");
        this.instanceId = EntityId.getSchedulerIdFromEntityId(entityId);
    }
}


================================================
FILE: src/actions/WaitForExternalEventAction.ts
================================================
import { Utils } from "../util/Utils";
import { ActionType } from "./ActionType";
import { ExternalEventType } from "./ExternalEventType";
import { IAction } from "./IAction";

/** @hidden */
export class WaitForExternalEventAction implements IAction {
    public readonly actionType: ActionType = ActionType.WaitForExternalEvent;

    constructor(
        public readonly externalEventName: string,
        public readonly reason = ExternalEventType.ExternalEvent
    ) {
        Utils.throwIfEmpty(externalEventName, "externalEventName");
    }
}


================================================
FILE: src/actions/WhenAllAction.ts
================================================
import { DFTask } from "../task";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class WhenAllAction implements IAction {
    public readonly actionType: ActionType = ActionType.WhenAll;
    public readonly compoundActions: IAction[];

    constructor(tasks: DFTask[]) {
        this.compoundActions = tasks.map((t) => t.actionObj);
    }
}


================================================
FILE: src/actions/WhenAnyAction.ts
================================================
import { DFTask } from "../task";
import { ActionType } from "./ActionType";
import { IAction } from "./IAction";

/** @hidden */
export class WhenAnyAction implements IAction {
    public readonly actionType: ActionType = ActionType.WhenAny;
    public readonly compoundActions: IAction[];

    constructor(tasks: DFTask[]) {
        this.compoundActions = tasks.map((t) => t.actionObj);
    }
}


================================================
FILE: src/app.ts
================================================
import {
    ActivityOptions,
    EntityHandler,
    EntityOptions,
    OrchestrationHandler,
    OrchestrationOptions,
    RegisteredActivity,
    RegisteredOrchestration,
} from "durable-functions";
import * as trigger from "./trigger";
import { createOrchestrator, createEntityFunction } from "./util/testingUtils";
import { app as azFuncApp } from "@azure/functions";
import { RegisteredOrchestrationTask } from "./task/RegisteredOrchestrationTask";
import { RegisteredActivityTask } from "./task/RegisteredActivityTask";

export function orchestration(
    functionName: string,
    handlerOrOptions: OrchestrationHandler | OrchestrationOptions
): RegisteredOrchestration {
    const options: OrchestrationOptions =
        typeof handlerOrOptions === "function" ? { handler: handlerOrOptions } : handlerOrOptions;

    azFuncApp.generic(functionName, {
        trigger: trigger.orchestration(),
        ...options,
        handler: createOrchestrator(options.handler),
    });

    const result: RegisteredOrchestration = (
        input?: unknown,
        instanceId?: string
    ): RegisteredOrchestrationTask => {
        return new RegisteredOrchestrationTask(functionName, input, instanceId);
    };

    return result;
}

export function entity<T = unknown>(
    functionName: string,
    handlerOrOptions: EntityHandler<T> | EntityOptions<T>
): void {
    const options: EntityOptions<T> =
        typeof handlerOrOptions === "function" ? { handler: handlerOrOptions } : handlerOrOptions;

    azFuncApp.generic(functionName, {
        trigger: trigger.entity(),
        ...options,
        handler: createEntityFunction(options.handler),
    });
}

export function activity(functionName: string, options: ActivityOptions): RegisteredActivity {
    azFuncApp.generic(functionName, {
        trigger: trigger.activity(),
        ...options,
    });

    const result: RegisteredActivity = (input?: unknown): RegisteredActivityTask => {
        return new RegisteredActivityTask(functionName, input);
    };

    return result;
}

export * as client from "./client";


================================================
FILE: src/client.ts
================================================
import * as input from "./input";
import {
    CosmosDBDurableClientOptions,
    DurableClientHandler,
    DurableClientOptions,
    EventGridDurableClientOptions,
    EventHubDurableClientOptions,
    HttpDurableClientOptions,
    ServiceBusQueueDurableClientOptions,
    ServiceBusTopicDurableClientOptions,
    StorageBlobDurableClientOptions,
    StorageQueueDurableClientOptions,
    TimerDurableClientOptions,
} from "durable-functions";
import {
    FunctionHandler,
    FunctionResult,
    InvocationContext,
    app as azFuncApp,
} from "@azure/functions";
import { DurableClient } from "./durableClient/DurableClient";
import { getClient, isDurableClientInput } from "./durableClient/getClient";

export function http(functionName: string, options: HttpDurableClientOptions): void {
    addClientInput(options);
    azFuncApp.http(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

export function timer(functionName: string, options: TimerDurableClientOptions): void {
    addClientInput(options);
    azFuncApp.timer(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

export function storageBlob(functionName: string, options: StorageBlobDurableClientOptions): void {
    addClientInput(options);
    azFuncApp.storageBlob(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

export function storageQueue(
    functionName: string,
    options: StorageQueueDurableClientOptions
): void {
    addClientInput(options);
    azFuncApp.storageQueue(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

export function serviceBusQueue(
    functionName: string,
    options: ServiceBusQueueDurableClientOptions
): void {
    addClientInput(options);
    azFuncApp.serviceBusQueue(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

export function serviceBusTopic(
    functionName: string,
    options: ServiceBusTopicDurableClientOptions
): void {
    addClientInput(options);
    azFuncApp.serviceBusTopic(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

export function eventHub(functionName: string, options: EventHubDurableClientOptions): void {
    addClientInput(options);
    azFuncApp.eventHub(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

export function eventGrid(functionName: string, options: EventGridDurableClientOptions): void {
    addClientInput(options);
    azFuncApp.eventGrid(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

export function cosmosDB(functionName: string, options: CosmosDBDurableClientOptions): void {
    addClientInput(options);
    azFuncApp.cosmosDB(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

export function generic(functionName: string, options: DurableClientOptions): void {
    addClientInput(options);
    azFuncApp.generic(functionName, {
        ...options,
        handler: convertToFunctionHandler(options.handler),
    });
}

function addClientInput(options: Partial<DurableClientOptions>): void {
    options.extraInputs = options.extraInputs ?? [];
    if (!options.extraInputs.find(isDurableClientInput)) {
        options.extraInputs.push(input.durableClient());
    }
}

function convertToFunctionHandler(clientHandler: DurableClientHandler): FunctionHandler {
    return (trigger: unknown, context: InvocationContext): FunctionResult<any> => {
        const client: DurableClient = getClient(context);
        return clientHandler(trigger, client, context);
    };
}


================================================
FILE: src/durableClient/DurableClient.ts
================================================
// tslint:disable:member-access

import { HttpRequest, HttpResponse } from "@azure/functions";
import OpenTelemetryApi = require("@opentelemetry/api");
import axios, { AxiosInstance, AxiosResponse } from "axios";
/** @hidden */
import process = require("process");
/** @hidden */
import url = require("url");
import { isURL } from "validator";
import {
    StartNewOptions,
    GetStatusOptions,
    OrchestrationFilter,
    TaskHubOptions,
    WaitForCompletionOptions,
} from "durable-functions";
import * as types from "durable-functions";
import { WebhookUtils } from "../util/WebhookUtils";
import { OrchestrationClientInputData } from "./OrchestrationClientInputData";
import { HttpManagementPayload } from "../http/HttpManagementPayload";
import { DurableOrchestrationStatus } from "../orchestrations/DurableOrchestrationStatus";
import { PurgeHistoryResult } from "./PurgeHistoryResult";
import { EntityId } from "../entities/EntityId";
import { EntityStateResponse } from "../entities/EntityStateResponse";
import { OrchestrationRuntimeStatus } from "../orchestrations/OrchestrationRuntimeStatus";
import { Utils } from "../util/Utils";

/**
 * Client for starting, querying, terminating and raising events to
 * orchestration instances.
 */
export class DurableClient implements types.DurableClient {
    public readonly taskHubName: string;
    /** @hidden */
    public readonly uniqueWebhookOrigins: string[];

    private readonly axiosInstance: AxiosInstance;

    private readonly eventNamePlaceholder = "{eventName}";
    private readonly functionNamePlaceholder = "{functionName}";
    private readonly instanceIdPlaceholder = "[/{instanceId}]";
    private readonly reasonPlaceholder = "{text}";

    private readonly createdTimeFromQueryKey = "createdTimeFrom";
    private readonly createdTimeToQueryKey = "createdTimeTo";
    private readonly runtimeStatusQueryKey = "runtimeStatus";
    private readonly showHistoryQueryKey = "showHistory";
    private readonly showHistoryOutputQueryKey = "showHistoryOutput";
    private readonly showInputQueryKey = "showInput";

    private urlValidationOptions: ValidatorJS.IsURLOptions = {
        protocols: ["http", "https"],
        require_tld: false,
        require_protocol: true,
        require_valid_protocol: true,
    };

    /**
     * @param clientData The object representing the orchestrationClient input
     *  binding of the Azure function that will use this client.
     */
    constructor(private readonly clientData: OrchestrationClientInputData) {
        if (!clientData) {
            throw new TypeError(
                `clientData: Expected OrchestrationClientInputData but got ${typeof clientData}`
            );
        }

        this.axiosInstance = axios.create({
            validateStatus: (status: number) => status < 600,
            headers: {
                post: {
                    "Content-Type": "application/json",
                },
            },
            maxContentLength: Infinity,
        });
        this.taskHubName = this.clientData.taskHubName;
        this.uniqueWebhookOrigins = this.extractUniqueWebhookOrigins(this.clientData);
    }

    public createCheckStatusResponse(
        request: HttpRequest | undefined,
        instanceId: string
    ): HttpResponse {
        const httpManagementPayload: HttpManagementPayload = this.getClientResponseLinks(
            request,
            instanceId
        );

        return new HttpResponse({
            status: 202,
            jsonBody: httpManagementPayload,
            headers: {
                "Content-Type": "application/json",
                Location: httpManagementPayload.statusQueryGetUri,
                "Retry-After": "10",
            },
        });
    }

    public createHttpManagementPayload(instanceId: string): HttpManagementPayload {
        return this.getClientResponseLinks(undefined, instanceId);
    }

    public async getStatus(
        instanceId: string,
        options: GetStatusOptions = {}
    ): Promise<DurableOrchestrationStatus> {
        const internalOptions: GetStatusInternalOptions = {
            instanceId,
            ...options,
        };
        const response: AxiosResponse = await this.getStatusInternal(internalOptions);

        switch (response.status) {
            case 200: // instance completed, failed or terminated
            case 202: // instance running or pending
            case 400:
                if (!response.data) {
                    throw new Error(
                        `DurableClient error: the Durable Functions extension replied with an empty HTTP ${response.status} response.`
                    );
                }

                try {
                    return new DurableOrchestrationStatus(response.data);
                } catch (error) {
                    throw new Error(
                        `DurableClient error: could not construct a DurableOrchestrationStatus object using the data received from the Durable Functions extension: ${error.message}`
                    );
                }

            case 404: // instance not found
                let msg =
                    `DurableClient error: Durable Functions extension replied with HTTP 404 response. ` +
                    `This usually means we could not find any data associated with the instanceId provided: ${instanceId}.`;
                if (response.data) {
                    msg += ` Details: ${JSON.stringify(response.data)}`;
                }
                throw new Error(msg);
            case 500: // request failed with unhandled exception (response data contains exception details)
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async getStatusAll(): Promise<DurableOrchestrationStatus[]> {
        const response = await this.getStatusInternal({});
        switch (response.status) {
            case 200:
                return response.data as DurableOrchestrationStatus[];
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async getStatusBy(filter: OrchestrationFilter): Promise<DurableOrchestrationStatus[]> {
        const response = await this.getStatusInternal(filter);
        switch (response.status) {
            case 200:
                return response.data as DurableOrchestrationStatus[];
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async purgeInstanceHistory(instanceId: string): Promise<PurgeHistoryResult> {
        let requestUrl: string;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            requestUrl = new URL(`instances/${instanceId}`, this.clientData.rpcBaseUrl).href;
        } else {
            // Legacy app frontend path
            const template = this.clientData.managementUrls.purgeHistoryDeleteUri;
            const idPlaceholder = this.clientData.managementUrls.id;
            requestUrl = template.replace(idPlaceholder, instanceId);
        }

        const response = await this.axiosInstance.delete(requestUrl);
        switch (response.status) {
            case 200: // instance found
                return response.data as PurgeHistoryResult;
            case 404: // instance not found
                return new PurgeHistoryResult(0);
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async purgeInstanceHistoryBy(filter: OrchestrationFilter): Promise<PurgeHistoryResult> {
        let requestUrl: string;
        const { createdTimeFrom, createdTimeTo, runtimeStatus } = filter;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            let path = new URL("instances/", this.clientData.rpcBaseUrl).href;
            const query: string[] = [];
            if (createdTimeFrom) {
                query.push(`createdTimeFrom=${createdTimeFrom.toISOString()}`);
            }
            if (createdTimeTo) {
                query.push(`createdTimeTo=${createdTimeTo.toISOString()}`);
            }
            if (runtimeStatus && runtimeStatus.length > 0) {
                const statusList: string = runtimeStatus.map((value) => value.toString()).join(",");
                query.push(`runtimeStatus=${statusList}`);
            }

            if (query.length > 0) {
                path += "?" + query.join("&");
            }

            requestUrl = new URL(path, this.clientData.rpcBaseUrl).href;
        } else {
            // Legacy app frontend path
            const idPlaceholder = this.clientData.managementUrls.id;
            requestUrl = this.clientData.managementUrls.statusQueryGetUri.replace(
                idPlaceholder,
                ""
            );

            if (!(createdTimeFrom instanceof Date)) {
                throw new Error("createdTimeFrom must be a valid Date");
            }

            if (createdTimeFrom) {
                requestUrl += `&${this.createdTimeFromQueryKey}=${createdTimeFrom.toISOString()}`;
            }

            if (createdTimeTo) {
                requestUrl += `&${this.createdTimeToQueryKey}=${createdTimeTo.toISOString()}`;
            }

            if (runtimeStatus && runtimeStatus.length > 0) {
                const statusesString = runtimeStatus
                    .map((value) => value.toString())
                    .reduce((acc, curr, i) => {
                        return acc + (i > 0 ? "," : "") + curr;
                    });

                requestUrl += `&${this.runtimeStatusQueryKey}=${statusesString}`;
            }
        }

        const response = await this.axiosInstance.delete(requestUrl);
        switch (response.status) {
            case 200: // instance found
                return response.data as PurgeHistoryResult;
            case 404: // instance not found
                return new PurgeHistoryResult(0);
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async raiseEvent(
        instanceId: string,
        eventName: string,
        eventData: unknown,
        options: TaskHubOptions = {}
    ): Promise<void> {
        const { taskHubName, connectionName } = options;
        if (!eventName) {
            throw new Error("eventName must be a valid string.");
        }

        let requestUrl: string;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            let path = `instances/${instanceId}/raiseEvent/${eventName}`;
            const query: string[] = [];
            if (taskHubName) {
                query.push(`taskHub=${taskHubName}`);
            }
            if (connectionName) {
                query.push(`connection=${connectionName}`);
            }

            if (query.length > 0) {
                path += "?" + query.join("&");
            }

            requestUrl = new URL(path, this.clientData.rpcBaseUrl).href;
        } else {
            // Legacy app frontend path
            const idPlaceholder = this.clientData.managementUrls.id;
            requestUrl = this.clientData.managementUrls.sendEventPostUri
                .replace(idPlaceholder, instanceId)
                .replace(this.eventNamePlaceholder, eventName);

            if (taskHubName) {
                requestUrl = requestUrl.replace(this.clientData.taskHubName, taskHubName);
            }

            if (connectionName) {
                requestUrl = requestUrl.replace(/(connection=)([\w]+)/gi, "$1" + connectionName);
            }
        }

        const response = await this.axiosInstance.post(requestUrl, JSON.stringify(eventData));
        switch (response.status) {
            case 202: // event accepted
            case 410: // instance completed or failed
                return;
            case 404:
                return Promise.reject(new Error(`No instance with ID '${instanceId}' found.`));
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async readEntityState<T>(
        entityId: EntityId,
        options: TaskHubOptions = {}
    ): Promise<EntityStateResponse<T>> {
        let requestUrl: string;
        const { taskHubName, connectionName } = options;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            let path = `entities/${entityId.name}/${entityId.key}`;
            const query: string[] = [];
            if (taskHubName) {
                query.push(`taskHub=${taskHubName}`);
            }
            if (connectionName) {
                query.push(`connection=${connectionName}`);
            }

            if (query.length > 0) {
                path += "?" + query.join("&");
            }

            requestUrl = new URL(path, this.clientData.rpcBaseUrl).href;
        } else {
            // Legacy app frontend path
            if (!(this.clientData.baseUrl && this.clientData.requiredQueryStringParameters)) {
                throw new Error(
                    "Cannot use the readEntityState API with this version of the Durable Task Extension."
                );
            }

            requestUrl = WebhookUtils.getReadEntityUrl(
                this.clientData.baseUrl,
                this.clientData.requiredQueryStringParameters,
                entityId.name,
                entityId.key,
                taskHubName,
                connectionName
            );
        }

        const response = await this.axiosInstance.get<T>(requestUrl);
        switch (response.status) {
            case 200: // entity exists
                return new EntityStateResponse(true, response.data);
            case 404: // entity does not exist
                return new EntityStateResponse(false);
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async rewind(
        instanceId: string,
        reason: string,
        options: TaskHubOptions = {}
    ): Promise<void> {
        const { taskHubName, connectionName } = options;
        const idPlaceholder = this.clientData.managementUrls.id;

        let requestUrl: string;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            let path = `instances/${instanceId}/rewind?reason=${reason}`;
            const query: string[] = [];
            if (taskHubName) {
                query.push(`taskHub=${taskHubName}`);
            }
            if (connectionName) {
                query.push(`connection=${connectionName}`);
            }

            if (query.length > 0) {
                path += "&" + query.join("&");
            }

            requestUrl = new URL(path, this.clientData.rpcBaseUrl).href;
        } else {
            // Legacy app frontend path
            requestUrl = this.clientData.managementUrls.rewindPostUri
                .replace(idPlaceholder, instanceId)
                .replace(this.reasonPlaceholder, reason);
        }

        const response = await this.axiosInstance.post(requestUrl);
        switch (response.status) {
            case 202:
                return;
            case 404:
                return Promise.reject(
                    new Error(response.data || `No instance with ID '${instanceId}' found.`)
                );
            case 412:
                return Promise.reject(
                    new Error(
                        response.data ||
                            "The rewind operation is only supported on failed orchestration instances."
                    )
                );
            case 501:
                return Promise.reject(
                    new Error(
                        response.data ||
                            "The rewind operation is not supported by the underlying storage provider."
                    )
                );
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async signalEntity(
        entityId: EntityId,
        operationName?: string,
        operationContent?: unknown,
        options: TaskHubOptions = {}
    ): Promise<void> {
        const { taskHubName, connectionName } = options;
        let requestUrl: string;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            let path = `entities/${entityId.name}/${entityId.key}`;
            const query: string[] = [];
            if (operationName) {
                query.push(`op=${operationName}`);
            }
            if (taskHubName) {
                query.push(`taskHub=${taskHubName}`);
            }
            if (connectionName) {
                query.push(`connection=${connectionName}`);
            }

            if (query.length > 0) {
                path += "?" + query.join("&");
            }

            requestUrl = new URL(path, this.clientData.rpcBaseUrl).href;
        } else {
            // Legacy app frontend path
            if (!(this.clientData.baseUrl && this.clientData.requiredQueryStringParameters)) {
                throw new Error(
                    "Cannot use the signalEntity API with this version of the Durable Task Extension."
                );
            }

            requestUrl = WebhookUtils.getSignalEntityUrl(
                this.clientData.baseUrl,
                this.clientData.requiredQueryStringParameters,
                entityId.name,
                entityId.key,
                operationName,
                taskHubName,
                connectionName
            );
        }

        const headers = this.getDistributedTracingHeaders();

        const response = await this.axiosInstance.post(
            requestUrl,
            JSON.stringify(operationContent),
            { headers }
        );
        switch (response.status) {
            case 202: // signal accepted
                return;
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async startNew(
        orchestratorFunctionName: string,
        options?: StartNewOptions
    ): Promise<string> {
        if (!orchestratorFunctionName) {
            throw new Error("orchestratorFunctionName must be a valid string.");
        }

        // TODO: Add support for specifying a task hub and a connection name
        let requestUrl: string;
        const instanceIdPath: string = options?.instanceId ? `/${options.instanceId}` : "";
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            const urlObj = new URL(
                `orchestrators/${orchestratorFunctionName}${instanceIdPath}`,
                this.clientData.rpcBaseUrl
            );
            if (options?.version) {
                urlObj.searchParams.append("version", options.version);
            }
            requestUrl = urlObj.href;
        } else {
            // Legacy app frontend path
            requestUrl = this.clientData.creationUrls.createNewInstancePostUri;
            requestUrl = requestUrl
                .replace(this.functionNamePlaceholder, orchestratorFunctionName)
                .replace(this.instanceIdPlaceholder, instanceIdPath);
            if (options?.version) {
                const separator = requestUrl.includes("?") ? "&" : "?";
                requestUrl = `${requestUrl}${separator}version=${encodeURIComponent(
                    options.version
                )}`;
            }
        }

        const headers = this.getDistributedTracingHeaders();

        const input: unknown = options?.input !== undefined ? JSON.stringify(options.input) : "";
        const response = await this.axiosInstance.post(requestUrl, input, { headers });
        if (response.data && response.status <= 202) {
            return (response.data as HttpManagementPayload).id;
        } else {
            return Promise.reject(this.createGenericError(response));
        }
    }

    public async terminate(instanceId: string, reason: string): Promise<void> {
        const idPlaceholder = this.clientData.managementUrls.id;
        let requestUrl: string;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            requestUrl = new URL(
                `instances/${instanceId}/terminate?reason=${reason}`,
                this.clientData.rpcBaseUrl
            ).href;
        } else {
            // Legacy app frontend path
            requestUrl = this.clientData.managementUrls.terminatePostUri
                .replace(idPlaceholder, instanceId)
                .replace(this.reasonPlaceholder, reason);
        }

        const response = await this.axiosInstance.post(requestUrl);
        switch (response.status) {
            case 202: // terminate accepted
            case 410: // instance completed or failed
                return;
            case 404:
                return Promise.reject(new Error(`No instance with ID '${instanceId}' found.`));
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async suspend(instanceId: string, reason: string): Promise<void> {
        const idPlaceholder = this.clientData.managementUrls.id;
        let requestUrl: string;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            requestUrl = new URL(
                `instances/${instanceId}/suspend?reason=${reason}`,
                this.clientData.rpcBaseUrl
            ).href;
        } else {
            // Legacy app frontend path
            requestUrl = this.clientData.managementUrls.suspendPostUri
                .replace(idPlaceholder, instanceId)
                .replace(this.reasonPlaceholder, reason);
        }

        const response = await this.axiosInstance.post(requestUrl);
        switch (response.status) {
            case 202: // suspend accepted
            case 410: // instance completed or failed
                return;
            case 404:
                return Promise.reject(new Error(`No instance with ID '${instanceId}' found.`));
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async resume(instanceId: string, reason: string): Promise<void> {
        const idPlaceholder = this.clientData.managementUrls.id;
        let requestUrl: string;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            requestUrl = new URL(
                `instances/${instanceId}/resume?reason=${reason}`,
                this.clientData.rpcBaseUrl
            ).href;
        } else {
            // Legacy app frontend path
            requestUrl = this.clientData.managementUrls.resumePostUri
                .replace(idPlaceholder, instanceId)
                .replace(this.reasonPlaceholder, reason);
        }

        const response = await this.axiosInstance.post(requestUrl);
        switch (response.status) {
            case 202: // resume accepted
            case 410: // instance completed or failed
                return;
            case 404:
                return Promise.reject(new Error(`No instance with ID '${instanceId}' found.`));
            default:
                return Promise.reject(this.createGenericError(response));
        }
    }

    public async waitForCompletionOrCreateCheckStatusResponse(
        request: HttpRequest,
        instanceId: string,
        waitOptions: WaitForCompletionOptions = {}
    ): Promise<HttpResponse> {
        const timeoutInMilliseconds: number =
            waitOptions.timeoutInMilliseconds !== undefined
                ? waitOptions.timeoutInMilliseconds
                : 10000;
        const retryIntervalInMilliseconds: number =
            waitOptions.retryIntervalInMilliseconds !== undefined
                ? waitOptions.retryIntervalInMilliseconds
                : 1000;

        if (retryIntervalInMilliseconds > timeoutInMilliseconds) {
            throw new Error(
                `Total timeout ${timeoutInMilliseconds} (ms) should be bigger than retry timeout ${retryIntervalInMilliseconds} (ms)`
            );
        }

        const hrStart = process.hrtime();
        while (true) {
            const status = await this.getStatus(instanceId);

            if (status) {
                switch (status.runtimeStatus) {
                    case OrchestrationRuntimeStatus.Completed:
                        return this.createHttpResponse(200, status.output);
                    case OrchestrationRuntimeStatus.Canceled:
                    case OrchestrationRuntimeStatus.Terminated:
                        return this.createHttpResponse(200, status);
                    case OrchestrationRuntimeStatus.Failed:
                        return this.createHttpResponse(500, status);
                }
            }

            const hrElapsed = process.hrtime(hrStart);
            const hrElapsedMilliseconds = Utils.getHrMilliseconds(hrElapsed);

            if (hrElapsedMilliseconds < timeoutInMilliseconds) {
                const remainingTime = timeoutInMilliseconds - hrElapsedMilliseconds;
                await Utils.sleep(
                    remainingTime > retryIntervalInMilliseconds
                        ? retryIntervalInMilliseconds
                        : remainingTime
                );
            } else {
                return this.createCheckStatusResponse(request, instanceId);
            }
        }
    }

    private getDistributedTracingHeaders(): Record<string, string> {
        // Get the current active span
        const currentSpan = OpenTelemetryApi.trace.getSpan(OpenTelemetryApi.context.active());

        // Create the headers object and inject the current span context if it exists
        const headers: Record<string, string> = {};
        if (currentSpan) {
            OpenTelemetryApi.propagation.inject(OpenTelemetryApi.context.active(), headers);
        }

        return headers;
    }

    private createHttpResponse(statusCode: number, body: unknown): HttpResponse {
        return new HttpResponse({
            status: statusCode,
            jsonBody: body,
            headers: {
                "Content-Type": "application/json",
            },
        });
    }

    private getClientResponseLinks(
        request: HttpRequest | undefined,
        instanceId: string
    ): HttpManagementPayload {
        const payload = { ...this.clientData.managementUrls };

        (Object.keys(payload) as Array<keyof HttpManagementPayload>).forEach((key) => {
            if (
                this.hasValidRequestUrl(request) &&
                isURL(payload[key], this.urlValidationOptions)
            ) {
                const requestUrl = new url.URL((request as HttpRequest).url);
                const dataUrl = new url.URL(payload[key]);
                payload[key] = payload[key].replace(dataUrl.origin, requestUrl.origin);
            }

            payload[key] = payload[key].replace(this.clientData.managementUrls.id, instanceId);
        });

        return payload;
    }

    private hasValidRequestUrl(request: HttpRequest | undefined): boolean {
        return request !== undefined && (request as HttpRequest).url !== undefined;
    }

    private extractUniqueWebhookOrigins(clientData: OrchestrationClientInputData): string[] {
        const origins = this.extractWebhookOrigins(clientData.creationUrls).concat(
            this.extractWebhookOrigins(clientData.managementUrls)
        );

        const uniqueOrigins = origins.reduce<string[]>((acc, curr) => {
            if (acc.indexOf(curr) === -1) {
                acc.push(curr);
            }
            return acc;
        }, []);

        return uniqueOrigins;
    }

    private extractWebhookOrigins(obj: { [key: string]: string }): string[] {
        const origins: string[] = [];

        const keys = Object.getOwnPropertyNames(obj);
        keys.forEach((key) => {
            const value = obj[key];

            if (isURL(value, this.urlValidationOptions)) {
                const valueAsUrl = new url.URL(value);
                const origin = valueAsUrl.origin;
                origins.push(origin);
            }
        });

        return origins;
    }

    /**
     * Internal method that gets the status of all orchestration instances that
     * match the specified conditions. It handles pagination automatically by
     * calling itself recursively until no more continuation tokens are found.
     * @param options Return orchestration instances which were created
     *  after this Date.
     * @param [continuationToken] Continuation token corresponding to the
     * `x-ms-continuation-token` header, for getting the next batch
     * of results. Used for recursion.
     * @param [prevData] Results of a previous request, used internally
     * to aggregate results during recursion.
     */
    private async getStatusInternal(
        options: GetStatusInternalOptions,
        continuationToken?: string,
        prevData?: unknown[]
    ): Promise<AxiosResponse> {
        let requestUrl: string;
        if (this.clientData.rpcBaseUrl) {
            // Fast local RPC path
            let path = new URL(`instances/${options.instanceId || ""}`, this.clientData.rpcBaseUrl)
                .href;
            const query: string[] = [];
            if (options.taskHubName) {
                query.push(`taskHub=${options.taskHubName}`);
            }
            if (options.connectionName) {
                query.push(`connection=${options.connectionName}`);
            }
            if (options.showHistory) {
                query.push(`showHistory=${options.showHistory}`);
            }
            if (options.showHistoryOutput) {
                query.push(`showHistoryOutput=${options.showHistoryOutput}`);
            }
            if (options.showInput) {
                query.push(`showInput=${options.showInput}`);
            }
            if (options.createdTimeFrom) {
                query.push(`createdTimeFrom=${options.createdTimeFrom.toISOString()}`);
            }
            if (options.createdTimeTo) {
                query.push(`createdTimeTo=${options.createdTimeTo.toISOString()}`);
            }
            if (options.runtimeStatus && options.runtimeStatus.length > 0) {
                const statusList: string = options.runtimeStatus
                    .map((value) => value.toString())
                    .join(",");
                query.push(`runtimeStatus=${statusList}`);
            }

            if (query.length > 0) {
                path += "?" + query.join("&");
            }

            requestUrl = new URL(path, this.clientData.rpcBaseUrl).href;
        } else {
            // Legacy app frontend code path
            const template = this.clientData.managementUrls.statusQueryGetUri;
            const idPlaceholder = this.clientData.managementUrls.id;

            requestUrl = template.replace(
                idPlaceholder,
                typeof options.instanceId === "string" ? options.instanceId : ""
            );
            if (options.taskHubName) {
                requestUrl = requestUrl.replace(this.clientData.taskHubName, options.taskHubName);
            }
            if (options.connectionName) {
                requestUrl = requestUrl.replace(
                    /(connection=)([\w]+)/gi,
                    "$1" + options.connectionName
                );
            }
            if (options.showHistory) {
                requestUrl += `&${this.showHistoryQueryKey}=${options.showHistory}`;
            }
            if (options.showHistoryOutput) {
                requestUrl += `&${this.showHistoryOutputQueryKey}=${options.showHistoryOutput}`;
            }
            if (options.createdTimeFrom) {
                requestUrl += `&${
                    this.createdTimeFromQueryKey
                }=${options.createdTimeFrom.toISOString()}`;
            }
            if (options.createdTimeTo) {
                requestUrl += `&${
                    this.createdTimeToQueryKey
                }=${options.createdTimeTo.toISOString()}`;
            }
            if (options.runtimeStatus && options.runtimeStatus.length > 0) {
                const statusesString = options.runtimeStatus
                    .map((value) => value.toString())
                    .reduce((acc, curr, i) => {
                        return acc + (i > 0 ? "," : "") + curr;
                    });

                requestUrl += `&${this.runtimeStatusQueryKey}=${statusesString}`;
            }
            if (typeof options.showInput === "boolean") {
                requestUrl += `&${this.showInputQueryKey}=${options.showInput}`;
            }
        }

        // If a continuation token is provided, we add it to the request's header
        let axiosConfig = undefined;
        if (continuationToken) {
            axiosConfig = {
                headers: {
                    "x-ms-continuation-token": continuationToken,
                },
            };
        }

        // We call the getStatus endpoint and construct a promise callback to handle the recursion
        // This assumes that, so long as continuation tokens are found, that the http response status
        // can be safely ignored (either 200 or 202).
        const response = this.axiosInstance.get(requestUrl, axiosConfig).then((httpResponse) => {
            // Aggregate results so far
            const headers = httpResponse.headers;
            if (prevData) {
                httpResponse.data = prevData.concat(httpResponse.data);
            }
            // If a new continuation token is found, recurse. Otherwise, return the results
            const token = headers["x-ms-continuation-token"];
            if (token) {
                return this.getStatusInternal(options, token, httpResponse.data);
            }
            return httpResponse;
        });

        return response;
    }

    private createGenericError(response: AxiosResponse<any>): Error {
        return new Error(
            `The operation failed with an unexpected status code: ${
                response.status
            }. Details: ${JSON.stringify(response.data)}`
        );
    }
}

interface GetStatusInternalOptions {
    instanceId?: string;
    taskHubName?: string;
    connectionName?: string;
    showHistory?: boolean;
    showHistoryOutput?: boolean;
    createdTimeFrom?: Date;
    createdTimeTo?: Date;
    runtimeStatus?: OrchestrationRuntimeStatus[];
    showInput?: boolean;
}


================================================
FILE: src/durableClient/OrchestrationClientInputData.ts
================================================
import { HttpCreationPayload } from "../http/HttpCreationPayload";
import { HttpManagementPayload } from "../http/HttpManagementPayload";

/** @hidden */
export class OrchestrationClientInputData {
    public static isOrchestrationClientInputData(obj: unknown): boolean {
        const typedInstance = obj as { [index: string]: unknown };
        if (typedInstance) {
            // Only check for required fields.
            if (
                typedInstance.taskHubName !== undefined &&
                typedInstance.creationUrls !== undefined &&
                typedInstance.managementUrls !== undefined
            ) {
                return true;
            }
            return false;
        }
        return false;
    }

    constructor(
        public taskHubName: string,
        public creationUrls: HttpCreationPayload,
        public managementUrls: HttpManagementPayload,
        public baseUrl?: string,
        public requiredQueryStringParameters?: string,
        public rpcBaseUrl?: string
    ) {}
}


================================================
FILE: src/durableClient/PurgeHistoryResult.ts
================================================
import * as types from "durable-functions";

export class PurgeHistoryResult implements types.PurgeHistoryResult {
    constructor(public readonly instancesDeleted: number) {}
}


================================================
FILE: src/durableClient/getClient.ts
================================================
import { FunctionInput, InvocationContext } from "@azure/functions";
import { DurableClientInput } from "durable-functions";
import { DurableClient } from "./DurableClient";
import { OrchestrationClientInputData } from "./OrchestrationClientInputData";
/** @hidden */
import cloneDeep = require("lodash/cloneDeep");
/** @hidden */
import url = require("url");
import { HttpCreationPayload } from "../http/HttpCreationPayload";
import { HttpManagementPayload } from "../http/HttpManagementPayload";
import { isURL } from "validator";
import { Constants } from "../Constants";

export function getClient(context: InvocationContext): DurableClient {
    const foundInput: FunctionInput | undefined = context.options.extraInputs.find(
        isDurableClientInput
    );
    if (!foundInput) {
        throw new Error(
            "Could not find a registered durable client input binding. Check your extraInputs definition when registering your function."
        );
    }

    const clientInputOptions = foundInput as DurableClientInput;
    let clientData = getClientData(context, clientInputOptions);

    if (!process.env.WEBSITE_HOSTNAME || process.env.WEBSITE_HOSTNAME.includes("0.0.0.0")) {
        clientData = correctClientData(clientData);
    }

    return new DurableClient(clientData);
}

/** @hidden */
export function isDurableClientInput(input: FunctionInput): boolean {
    return input.type === "durableClient" || input.type === "orchestrationClient";
}

/** @hidden */
function getClientData(
    context: InvocationContext,
    clientInput: DurableClientInput
): OrchestrationClientInputData {
    const clientData: unknown = context.extraInputs.get(clientInput);
    if (clientData && OrchestrationClientInputData.isOrchestrationClientInputData(clientData)) {
        return clientData as OrchestrationClientInputData;
    }

    throw new Error(
        "Received input is not a valid durable client input. Check your extraInputs definition when registering your function."
    );
}

/** @hidden */
function correctClientData(clientData: OrchestrationClientInputData): OrchestrationClientInputData {
    const returnValue = cloneDeep(clientData);

    returnValue.creationUrls = correctUrls(clientData.creationUrls) as HttpCreationPayload;
    returnValue.managementUrls = correctUrls(clientData.managementUrls) as HttpManagementPayload;

    return returnValue;
}

function correctUrls(obj: { [key: string]: string }): { [key: string]: string } {
    const returnValue = cloneDeep(obj);

    const keys = Object.getOwnPropertyNames(obj);
    keys.forEach((key) => {
        const value = obj[key];

        if (
            isURL(value, {
                protocols: ["http", "https"],
                require_tld: false,
                require_protocol: true,
            })
        ) {
            const valueAsUrl = new url.URL(value);
            returnValue[key] = value.replace(valueAsUrl.origin, Constants.DefaultLocalOrigin);
        }
    });

    return returnValue;
}


================================================
FILE: src/entities/DurableEntityBindingInfo.ts
================================================
import { EntityId } from "./EntityId";
import { RequestMessage } from "./RequestMessage";

/** @hidden */
export class DurableEntityBindingInfoReqFields {
    constructor(
        public readonly self: EntityId,
        public readonly exists: boolean,
        public readonly batch: RequestMessage[]
    ) {}
}

/** @hidden */
export class DurableEntityBindingInfo extends DurableEntityBindingInfoReqFields {
    constructor(
        public readonly self: EntityId,
        public readonly exists: boolean,
        public readonly state: string | undefined,
        public readonly batch: RequestMessage[]
    ) {
        super(self, exists, batch);
    }
}


================================================
FILE: src/entities/DurableLock.ts
================================================
/**
 * @hidden
 * For use with locking operations.
 * TODO: improve this
 */
export class DurableLock {}


================================================
FILE: src/entities/Entity.ts
================================================
import * as debug from "debug";
import {
    DurableEntityBindingInfoReqFields,
    DurableEntityBindingInfo,
} from "./DurableEntityBindingInfo";
import { DurableEntityContext, EntityContext } from "durable-functions";
import { Utils } from "../util/Utils";
import { EntityState } from "./EntityState";
import { OperationResult } from "./OperationResult";
import { RequestMessage } from "./RequestMessage";
import { Signal } from "./Signal";
import { EntityId } from "./EntityId";

/** @hidden */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const log = debug("orchestrator");

/** @hidden */
export class Entity<T> {
    constructor(public fn: (context: EntityContext<T>) => void) {}

    public listen(): (
        entityTrigger: DurableEntityBindingInfo,
        context: EntityContext<T>
    ) => Promise<EntityState> {
        return this.handle.bind(this);
    }

    private async handle(
        entityTrigger: DurableEntityBindingInfo,
        context: EntityContext<T>
    ): Promise<EntityState> {
        const entityBinding = Utils.getInstancesOf<DurableEntityBindingInfo>(
            { trigger: entityTrigger },
            new DurableEntityBindingInfoReqFields(
                new EntityId("samplename", "samplekey"),
                true,
                []
            ) as DurableEntityBindingInfo
        )[0];

        if (entityBinding === undefined) {
            throw new Error("Could not find an entityTrigger binding on context.");
        }

        // Setup
        const returnState: EntityState = new EntityState([], []);
        returnState.entityExists = entityBinding.exists;
        returnState.entityState = entityBinding.state;
        for (let i = 0; i < entityBinding.batch.length; i++) {
            const startTime = new Date();
            context.df = this.getCurrentDurableEntityContext(
                entityBinding,
                returnState,
                i,
                startTime
            );

            try {
                await Promise.resolve(this.fn(context));
                if (!returnState.results[i]) {
                    const elapsedMs = this.computeElapsedMilliseconds(startTime);
                    returnState.results[i] = new OperationResult(
                        false,
                        elapsedMs,
                        startTime.getTime()
                    );
                }
            } catch (error) {
                const elapsedMs = this.computeElapsedMilliseconds(startTime);
                returnState.results[i] = new OperationResult(
                    true,
                    elapsedMs,
                    startTime.getTime(),
                    JSON.stringify(error)
                );
            }
        }

        return returnState;
    }

    private getCurrentDurableEntityContext(
        bindingInfo: DurableEntityBindingInfo,
        batchState: EntityState,
        requestIndex: number,
        startTime: Date
    ): DurableEntityContext<T> {
        const currentRequest = bindingInfo.batch[requestIndex];
        return {
            entityName: bindingInfo.self.name,
            entityKey: bindingInfo.self.key,
            entityId: bindingInfo.self,
            operationName: currentRequest.name,
            isNewlyConstructed: !batchState.entityExists,
            getState: this.getState.bind(this, batchState),
            setState: this.setState.bind(this, batchState),
            getInput: this.getInput.bind(this, currentRequest) as <TInput>() => TInput | undefined,
            return: this.return.bind(this, batchState, startTime) as <TResult = T>(
                value: TResult
            ) => void,
            destructOnExit: this.destructOnExit.bind(this, batchState),
            signalEntity: this.signalEntity.bind(this, batchState, currentRequest),
        };
    }

    private destructOnExit(batchState: EntityState): void {
        batchState.entityExists = false;
        batchState.entityState = undefined;
    }

    private getInput<TInput>(currentRequest: RequestMessage): TInput | undefined {
        if (currentRequest.input) {
            return JSON.parse(currentRequest.input) as TInput;
        }
        return undefined;
    }

    private getState(returnState: EntityState, initializer?: () => T): T | undefined {
        if (returnState.entityState) {
            return JSON.parse(returnState.entityState) as T;
        } else if (initializer) {
            return initializer();
        }
        return undefined;
    }

    private return(returnState: EntityState, startTime: Date, result: T): void {
        returnState.entityExists = true;
        returnState.results.push(
            new OperationResult(
                false,
                this.computeElapsedMilliseconds(startTime),
                startTime.getTime(),
                JSON.stringify(result)
            )
        );
    }

    private setState(returnState: EntityState, state: T): void {
        returnState.entityExists = true;
        returnState.entityState = JSON.stringify(state);
    }

    private signalEntity(
        returnState: EntityState,
        request: RequestMessage,
        entity: EntityId,
        operationName: string,
        operationInput?: unknown
    ): void {
        returnState.signals.push(
            new Signal(
                entity,
                operationName,
                operationInput ? JSON.stringify(operationInput) : "",
                request.id,
                new Date().getTime()
            )
        );
    }

    private computeElapsedMilliseconds(startTime: Date): number {
        const endTime = new Date();
        return endTime.getTime() - startTime.getTime();
    }
}


================================================
FILE: src/entities/EntityId.ts
================================================
// tslint:disable:member-access

import { Utils } from "../util/Utils";
import * as types from "durable-functions";

export class EntityId implements types.EntityId {
    /** @hidden */
    static getEntityIdFromSchedulerId(schedulerId: string): EntityId {
        const pos = schedulerId.indexOf("@", 1);
        const entityName = schedulerId.substring(1, pos);
        const entityKey = schedulerId.substring(pos + 1);
        return new EntityId(entityName, entityKey);
    }

    /** @hidden */
    static getSchedulerIdFromEntityId(entityId: EntityId): string {
        return `@${entityId.name.toLowerCase()}@${entityId.key}`;
    }

    constructor(
        // TODO: consider how to name these fields more accurately without interfering with JSON serialization
        public readonly name: string,
        public readonly key: string
    ) {
        Utils.throwIfEmpty(name, "name");
        Utils.throwIfEmpty(key, "key");
    }

    public toString(): string {
        return EntityId.getSchedulerIdFromEntityId(this);
    }
}


================================================
FILE: src/entities/EntityState.ts
================================================
import { OperationResult } from "./OperationResult";
import { Signal } from "./Signal";

/** @hidden */
export class EntityState {
    public entityExists: boolean;
    public entityState: string | undefined;
    public readonly results: OperationResult[];
    public readonly signals: Signal[];

    constructor(results: OperationResult[], signals: Signal[]) {
        this.results = results;
        this.signals = signals;
    }
}


================================================
FILE: src/entities/EntityStateResponse.ts
================================================
import * as types from "durable-functions";

export class EntityStateResponse<T> implements types.EntityStateResponse<T> {
    constructor(public entityExists: boolean, public entityState?: T) {}
}


================================================
FILE: src/entities/LockState.ts
================================================
import { EntityId } from "./EntityId";

/**
 * @hidden
 * Returned by [DurableOrchestrationContext].[isLocked] and
 * [DurableEntityContext].[isLocked].
 */
export class LockState {
    constructor(
        /** Whether the context already holds some locks. */
        public readonly isLocked: boolean,
        /** The locks held by the context. */
        public readonly ownedLocks: EntityId[]
    ) {}
}


================================================
FILE: src/entities/OperationResult.ts
================================================
/** @hidden */
export class OperationResult {
    constructor(
        readonly isError: boolean,
        readonly duration: number,
        readonly startTime: number,
        readonly result?: string
    ) {}
}


================================================
FILE: src/entities/RequestMessage.ts
================================================
import { EntityId } from "./EntityId";

/** @hidden */
export class RequestMessage {
    /** A unique identifier for this operation. */
    public id: string; // Id

    /**
     * The name of the operation being called (if this is an operation message)
     * or undefined (if this is a lock request).
     */
    public name?: string; // Operation

    /** Whether or not this is a one-way message. */
    public signal?: boolean; // IsSignal

    /** The operation input. */
    public input?: string; // Input

    /** The content the operation was called with. */
    public arg?: unknown; // Content

    /** The parent instance that called this operation. */
    public parent?: string; // ParentInstanceId

    /**
     * For lock requests, the set of locks being acquired. Is sorted,
     * contains at least one element, and has no repetitions.
     */
    public lockset?: EntityId[]; // LockSet

    /** For lock requests involving multiple locks, the message number. */
    public pos?: number; // Position
}


================================================
FILE: src/entities/ResponseMessage.ts
================================================
import { Utils } from "../util/Utils";

/** @hidden */
export class ResponseMessage {
    public result?: string; // Result
    public exceptionType?: string; // ExceptionType

    public constructor(event: unknown) {
        if (typeof event === "object" && event !== null) {
            if (Utils.hasStringProperty(event, "result")) {
                this.result = event.result;
            }
            if (Utils.hasStringProperty(event, "exceptionType")) {
                this.exceptionType = event.exceptionType;
            }
        } else {
            throw Error(
                "Attempted to construct ResponseMessage event from incompatible History event. " +
                    "This is probably a bug in History-replay. Please file a bug report."
            );
        }
    }
}

// TODO: error deserialization


================================================
FILE: src/entities/Signal.ts
================================================
import { EntityId } from "./EntityId";

/** @hidden */
export class Signal {
    constructor(
        public readonly target: EntityId,
        public readonly name: string,
        public readonly input: string,
        public readonly requestId: string,
        public readonly requestTime: number
    ) {}
}


================================================
FILE: src/error/AggregatedError.ts
================================================
import * as types from "durable-functions";

/** @hidden */
const separator = "-----------------------------------";

export class AggregatedError extends Error implements types.AggregatedError {
    public errors: Error[];

    constructor(errors: Error[]) {
        const errorStrings = errors.map(
            (error) => `Name: ${error.name}\nMessage: ${error.message}\nStackTrace: ${error.stack}`
        );
        const message = `context.df.Task.all() encountered the below error messages:\n\n${errorStrings.join(
            `\n${separator}\n`
        )}`;
        super(message);
        this.errors = errors;
    }
}


================================================
FILE: src/error/DurableError.ts
================================================
import * as types from "durable-functions";

export class DurableError extends Error implements types.DurableError {
    constructor(message: string | undefined) {
        super(message);
    }
}


================================================
FILE: src/error/OrchestrationFailureError.ts
================================================
import { OrchestratorState } from "../orchestrations/OrchestratorState";

/** @hidden */
const outOfProcDataLabel = "\n\n$OutOfProcData$:";

/**
 * @hidden
 * A wrapper for all errors thrown within an orchestrator function. This exception will embed
 * the orchestrator state in a way that the C# extension knows how to read so that it can replay the
 * actions scheduled before throwing an exception. This prevents non-determinism errors in Durable Task.
 *
 * Note that making any changes to the following schema to OrchestrationFailureError.message could be considered a breaking change:
 *
 * "<error message as a string>\n\n$OutOfProcData$<json representation of state>"
 */
export class OrchestrationFailureError extends Error {
    constructor(error: any, state: OrchestratorState) {
        let errorMessage: string;
        if (error instanceof Error) {
            errorMessage = error.message;
        } else if (typeof error === "string") {
            errorMessage = error;
        } else {
            errorMessage = JSON.stringify(error);
        }

        const message = `${errorMessage}${outOfProcDataLabel}${JSON.stringify(state)}`;
        super(message);
        this.stack = error.stack;
    }
}


================================================
FILE: src/history/EventRaisedEvent.ts
================================================
import { HistoryEvent } from "./HistoryEvent";
import { HistoryEventOptions } from "./HistoryEventOptions";
import { HistoryEventType } from "./HistoryEventType";

/** @hidden */
export class EventRaisedEvent extends HistoryEvent {
    public Name: string;
    public Input: string | undefined;

    constructor(options: HistoryEventOptions) {
        super(HistoryEventType.EventRaised, options.eventId, options.isPlayed, options.timestamp);

        if (options.name === undefined) {
            throw new Error("EventRaisedEvent needs a name provided.");
        } else {
            this.Name = options.name;
        }

        this.Input = options.input;
    }
}


================================================
FILE: src/history/EventSentEvent.ts
================================================
import { HistoryEvent } from "./HistoryEvent";
import { HistoryEventOptions } from "./HistoryEventOptions";
import { HistoryEventType } from "./HistoryEventType";

/** @hidden */
export class EventSentEvent extends HistoryEvent {
    public Name: string;
    public Input: string | undefined;
    public InstanceId: string;

    constructor(options: HistoryEventOptions) {
        super(HistoryEventType.EventSent, options.eventId, options.isPlayed, options.timestamp);

        if (options.name === undefined) {
            throw new Error("EventSentEvent needs a name provided.");
        }

        if (options.instanceId === undefined) {
            throw new Error("EventSentEvent needs an instance id provided.");
        }

        this.Input = options.input;
        this.Name = options.name;
        this.InstanceId = options.instanceId;
    }
}


================================================
FILE: src/history/ExecutionStartedEvent.ts
================================================
import { HistoryEvent } from "./HistoryEvent";
import { HistoryEventOptions } from "./HistoryEventOptions";
import { HistoryEventType } from "./HistoryEventType";

/** @hidden */
export class ExecutionStartedEvent extends HistoryEvent {
    public Name: string;
    public Input: string | undefined;
    public Version: string | undefined;

    constructor(options: HistoryEventOptions) {
        super(
            HistoryEventType.ExecutionStarted,
            options.eventId,
            options.isPlayed,
            options.timestamp
        );

        if (options.name === undefined) {
            throw new Error("ExecutionStartedEvent needs a name provided.");
        } else {
            this.Name = options.name;
        }

        this.Input = options.input;
        this.Version = options.version;
    }
}


================================================
FILE: src/history/HistoryEvent.ts
================================================
import { HistoryEventType } from "./HistoryEventType";

/** @hidden */
export abstract class HistoryEvent {
    constructor(
        public EventType: HistoryEventType,
        public EventId: number,
        public IsPlayed: boolean,
        public Timestamp: Date,
        public IsProcessed: boolean = false
    ) {}
}


================================================
FILE: src/history/HistoryEventOptions.ts
================================================
/** @hidden */
export class HistoryEventOptions {
    public details?: string;
    public fireAt?: Date;
    public input?: string;
    public instanceId?: string;
    public name?: string;
    public reason?: string;
    public result?: string;
    public taskScheduledId?: number;
    public timerId?: number;
    public version?: string;

    constructor(public eventId: number, public timestamp: Date, public isPlayed: boolean = false) {}
}


================================================
FILE: src/history/HistoryEventType.ts
================================================
/**
 * @hidden
 * Corresponds to subclasses of HistoryEvent type in [Durable Task framework.](https://github.com/Azure/durabletask)
 */
export enum HistoryEventType {
    ExecutionStarted = 0,
    ExecutionCompleted = 1,
    ExecutionFailed = 2,
    ExecutionTerminated = 3,
    TaskScheduled = 4,
    TaskCompleted = 5,
    TaskFailed = 6,
    SubOrchestrationInstanceCreated = 7,
    SubOrchestrationInstanceCompleted = 8,
    SubOrchestrationInstanceFailed = 9,
    TimerCreated = 10,
    TimerFired = 11,
    OrchestratorStarted = 12,
    OrchestratorCompleted = 13,
    EventSent = 14,
    EventRaised = 15,
    ContinueAsNew = 16,
    GenericEvent = 17,
    HistoryState = 18,
    ExecutionSuspended = 19,
    ExecutionResumed = 20,
}


================================================
FILE: src/history/OrchestratorCompletedEvent.ts
================================================
import { HistoryEvent } from "./HistoryEvent";
import { HistoryEventOptions } from "./HistoryEventOptions";
import { HistoryEventType } from "./HistoryEventType";

/** @hidden */
export class OrchestratorCompletedEvent extends HistoryEvent {
    construct
gitextract_0at6gbtx/

├── .azuredevops/
│   └── dependabot.yml
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── new-release-template.md
│   ├── fabricbot.json
│   └── workflows/
│       └── codeQL.yml
├── .gitignore
├── .prettierrc
├── .vscode/
│   ├── extensions.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── azure-pipelines/
│   ├── code-mirror.yml
│   ├── official-build.yml
│   ├── public-build.yml
│   ├── release.yml
│   └── templates/
│       ├── build.yml
│       └── test.yml
├── es-metadata.yml
├── package.json
├── samples-js/
│   ├── .funcignore
│   ├── .gitignore
│   ├── functions/
│   │   ├── backupSiteContent.js
│   │   ├── callActivityWithRetry.js
│   │   ├── callSubOrchestratorWithRetry.js
│   │   ├── cancelTimer.js
│   │   ├── continueAsNewCounter.js
│   │   ├── counter.js
│   │   ├── httpStart.js
│   │   ├── httpSyncStart.js
│   │   ├── listAzureSubscriptions.js
│   │   ├── sayHello.js
│   │   ├── smsPhoneVerification.js
│   │   └── weatherMonitor.js
│   ├── host.json
│   └── package.json
├── samples-ts/
│   ├── .funcignore
│   ├── .gitignore
│   ├── .vscode/
│   │   ├── extensions.json
│   │   ├── launch.json
│   │   ├── settings.json
│   │   └── tasks.json
│   ├── functions/
│   │   ├── backupSiteContent.ts
│   │   ├── callActivityWithRetry.ts
│   │   ├── callSubOrchestratorWithRetry.ts
│   │   ├── cancelTimer.ts
│   │   ├── continueAsNewCounter.ts
│   │   ├── counter.ts
│   │   ├── httpStart.ts
│   │   ├── httpSyncStart.ts
│   │   ├── listAzureSubscriptions.ts
│   │   ├── orchestrationVersion.ts
│   │   ├── sayHello.ts
│   │   ├── smsPhoneVerification.ts
│   │   └── weatherMonitor.ts
│   ├── host.json
│   ├── package.json
│   └── tsconfig.json
├── src/
│   ├── Constants.ts
│   ├── ManagedIdentityTokenSource.ts
│   ├── RetryOptions.ts
│   ├── actions/
│   │   ├── ActionType.ts
│   │   ├── CallActivityAction.ts
│   │   ├── CallActivityWithRetryAction.ts
│   │   ├── CallEntityAction.ts
│   │   ├── CallHttpAction.ts
│   │   ├── CallSubOrchestratorAction.ts
│   │   ├── CallSubOrchestratorWithRetryAction.ts
│   │   ├── ContinueAsNewAction.ts
│   │   ├── CreateTimerAction.ts
│   │   ├── ExternalEventType.ts
│   │   ├── IAction.ts
│   │   ├── SignalEntityAction.ts
│   │   ├── WaitForExternalEventAction.ts
│   │   ├── WhenAllAction.ts
│   │   └── WhenAnyAction.ts
│   ├── app.ts
│   ├── client.ts
│   ├── durableClient/
│   │   ├── DurableClient.ts
│   │   ├── OrchestrationClientInputData.ts
│   │   ├── PurgeHistoryResult.ts
│   │   └── getClient.ts
│   ├── entities/
│   │   ├── DurableEntityBindingInfo.ts
│   │   ├── DurableLock.ts
│   │   ├── Entity.ts
│   │   ├── EntityId.ts
│   │   ├── EntityState.ts
│   │   ├── EntityStateResponse.ts
│   │   ├── LockState.ts
│   │   ├── OperationResult.ts
│   │   ├── RequestMessage.ts
│   │   ├── ResponseMessage.ts
│   │   └── Signal.ts
│   ├── error/
│   │   ├── AggregatedError.ts
│   │   ├── DurableError.ts
│   │   └── OrchestrationFailureError.ts
│   ├── history/
│   │   ├── EventRaisedEvent.ts
│   │   ├── EventSentEvent.ts
│   │   ├── ExecutionStartedEvent.ts
│   │   ├── HistoryEvent.ts
│   │   ├── HistoryEventOptions.ts
│   │   ├── HistoryEventType.ts
│   │   ├── OrchestratorCompletedEvent.ts
│   │   ├── OrchestratorStartedEvent.ts
│   │   ├── SubOrchestrationInstanceCompletedEvent.ts
│   │   ├── SubOrchestrationInstanceCreatedEvent.ts
│   │   ├── SubOrchestrationInstanceFailedEvent.ts
│   │   ├── TaskCompletedEvent.ts
│   │   ├── TaskFailedEvent.ts
│   │   ├── TaskScheduledEvent.ts
│   │   ├── TimerCreatedEvent.ts
│   │   └── TimerFiredEvent.ts
│   ├── http/
│   │   ├── DurableHttpRequest.ts
│   │   ├── DurableHttpResponse.ts
│   │   ├── HttpCreationPayload.ts
│   │   └── HttpManagementPayload.ts
│   ├── index.ts
│   ├── input.ts
│   ├── orchestrations/
│   │   ├── DurableOrchestrationBindingInfo.ts
│   │   ├── DurableOrchestrationContext.ts
│   │   ├── DurableOrchestrationStatus.ts
│   │   ├── IOrchestratorState.ts
│   │   ├── OrchestrationRuntimeStatus.ts
│   │   ├── Orchestrator.ts
│   │   ├── OrchestratorState.ts
│   │   ├── ReplaySchema.ts
│   │   └── TaskOrchestrationExecutor.ts
│   ├── task/
│   │   ├── AtomicTask.ts
│   │   ├── CallHttpWithPollingTask.ts
│   │   ├── CompoundTask.ts
│   │   ├── DFTask.ts
│   │   ├── DFTimerTask.ts
│   │   ├── LongTimerTask.ts
│   │   ├── NoOpTask.ts
│   │   ├── RegisteredActivityTask.ts
│   │   ├── RegisteredOrchestrationTask.ts
│   │   ├── RetryableTask.ts
│   │   ├── TaskBase.ts
│   │   ├── WhenAllTask.ts
│   │   ├── WhenAnyTask.ts
│   │   └── index.ts
│   ├── trigger.ts
│   └── util/
│       ├── GuidManager.ts
│       ├── Utils.ts
│       ├── WebhookUtils.ts
│       └── testingUtils.ts
├── test/
│   ├── integration/
│   │   ├── entity-spec.ts
│   │   └── orchestrator-spec.ts
│   ├── test-app/
│   │   ├── .funcignore
│   │   ├── .gitignore
│   │   ├── .vscode/
│   │   │   ├── extensions.json
│   │   │   ├── launch.json
│   │   │   ├── settings.json
│   │   │   └── tasks.json
│   │   ├── host.json
│   │   ├── package.json
│   │   ├── src/
│   │   │   └── functions/
│   │   │       ├── counter1.ts
│   │   │       └── hello.ts
│   │   └── tsconfig.json
│   ├── testobjects/
│   │   ├── TestOrchestrations.ts
│   │   ├── testconstants.ts
│   │   ├── testentities.ts
│   │   ├── testentitybatches.ts
│   │   ├── testentityoperations.ts
│   │   ├── testhistories.ts
│   │   └── testutils.ts
│   └── unit/
│       ├── createtimeraction-spec.ts
│       ├── durableclient-spec.ts
│       ├── entityid-spec.ts
│       ├── getclient-spec.ts
│       ├── guidmanager-spec.ts
│       ├── orchestrationclient-spec.ts
│       ├── retryoptions-spec.ts
│       ├── shim-spec.ts
│       ├── timertask-spec.ts
│       └── utils-spec.ts
├── tsconfig.json
├── tsconfig.nocomments
└── types/
    ├── activity.d.ts
    ├── app.client.d.ts
    ├── app.d.ts
    ├── durableClient.d.ts
    ├── entity.d.ts
    ├── index.d.ts
    ├── input.d.ts
    ├── orchestration.d.ts
    ├── task.d.ts
    └── trigger.d.ts
Condensed preview — 194 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (775K chars).
[
  {
    "path": ".azuredevops/dependabot.yml",
    "chars": 145,
    "preview": "# Mirrored repository. We use dependabot via GitHub, not Azure DevOps.\nversion: 2\nenable-security-updates: false\nenable-..."
  },
  {
    "path": ".editorconfig",
    "chars": 193,
    "preview": "; editor configuration powered by http://editorconfig.org/\n; Top-most EditorConfig file\nroot = true\n\n[*]\ntrim_trailing_w..."
  },
  {
    "path": ".eslintignore",
    "chars": 81,
    "preview": "node_modules/**\r\nlib/**\r\nsamples/node_modules/**\r\ntest/test-app/node_modules/**\r\n"
  },
  {
    "path": ".eslintrc",
    "chars": 681,
    "preview": "{\r\n    \"parser\": \"@typescript-eslint/parser\",\r\n    \"extends\": [\r\n        \"plugin:@typescript-eslint/recommended\",..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 1759,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b..."
  },
  {
    "path": ".github/ISSUE_TEMPLATE/new-release-template.md",
    "chars": 2890,
    "preview": "---\nname: New release template\nabout: Template for creating new releases of the Durable Functions Node.js SDK\n\n---\n**Pre..."
  },
  {
    "path": ".github/fabricbot.json",
    "chars": 13639,
    "preview": "{\n  \"version\": \"1.0\",\n  \"tasks\": [\n    {\n      \"taskType\": \"trigger\",\n      \"capabilityId\": \"IssueResponder\",\n      \"sub..."
  },
  {
    "path": ".github/workflows/codeQL.yml",
    "chars": 2430,
    "preview": "# This workflow generates weekly CodeQL reports for this repo, a security requirements.\r\n# The workflow is adapted from..."
  },
  {
    "path": ".gitignore",
    "chars": 42,
    "preview": "coverage/\nnode_modules/\nnpm-debug.log\nlib/"
  },
  {
    "path": ".prettierrc",
    "chars": 151,
    "preview": "{\r\n    \"trailingComma\": \"es5\",\r\n    \"tabWidth\": 4,\r\n    \"true\": false,\r\n    \"singleQuote\": false,\r\n    \"printWidth\": 100..."
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 165,
    "preview": "{\n  \"recommendations\": [\n    \"ms-azuretools.vscode-azurefunctions\",\n    \"editorconfig.editorconfig\",\n    \"eg2.vscode-npm..."
  },
  {
    "path": ".vscode/launch.json",
    "chars": 2626,
    "preview": "{\n    // Use IntelliSense to learn about possible Node.js debug attributes.\n    // Hover to view descriptions of existin..."
  },
  {
    "path": ".vscode/settings.json",
    "chars": 604,
    "preview": "{\n    \"typescript.tsdk\": \"node_modules\\\\typescript\\\\lib\",\n    \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n    \"..."
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 2168,
    "preview": "{\n    // See https://go.microsoft.com/fwlink/?LinkId=733558\n    // for the documentation about the tasks.json format..."
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 6506,
    "preview": "# Contributor Onboarding\n\n## General\n\n- Helps start contributions to Durable Functions in JavaScript\n- Helps setup devel..."
  },
  {
    "path": "LICENSE",
    "chars": 1076,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaini..."
  },
  {
    "path": "README.md",
    "chars": 10925,
    "preview": "| Branch         | Status..."
  },
  {
    "path": "SECURITY.md",
    "chars": 2656,
    "preview": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.9 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products an..."
  },
  {
    "path": "azure-pipelines/code-mirror.yml",
    "chars": 484,
    "preview": "trigger:\n    branches:\n        include:\n            - v2.x\n            - v3.x\n\nschedules:\n# Build weekly to ensure the p..."
  },
  {
    "path": "azure-pipelines/official-build.yml",
    "chars": 1465,
    "preview": "trigger:\n    branches:\n        include:\n            - v3.x\n    batch: true\n\n# CI only\npr: none\n\nschedules:\n# Build night..."
  },
  {
    "path": "azure-pipelines/public-build.yml",
    "chars": 1319,
    "preview": "trigger:\n    branches:\n        include:\n            - v3.x\n    batch: true\n\npr:\n    branches:\n        include:..."
  },
  {
    "path": "azure-pipelines/release.yml",
    "chars": 2134,
    "preview": "parameters:\n    - name: NpmPublishTag\n      displayName: \"Tag\"\n      type: string\n      default: \"latest\"\n    - name: Np..."
  },
  {
    "path": "azure-pipelines/templates/build.yml",
    "chars": 1333,
    "preview": "jobs:\n    - job:\n      templateContext:\n          outputs:\n              - output: pipelineArtifact\n                path..."
  },
  {
    "path": "azure-pipelines/templates/test.yml",
    "chars": 1778,
    "preview": "jobs:\n    - job: UnitTests\n\n      strategy:\n          matrix:\n              Node18:\n                  NODE_VERSION: \"18...."
  },
  {
    "path": "es-metadata.yml",
    "chars": 278,
    "preview": "schemaVersion: 1.0.0\nproviders:\n- provider: InventoryAsCode\n  version: 1.0.0\n  metadata:\n    isProduction: true\n    acco..."
  },
  {
    "path": "package.json",
    "chars": 3437,
    "preview": "{\r\n    \"name\": \"durable-functions\",\r\n    \"version\": \"3.3.1\",\r\n    \"description\": \"Durable Functions library for Node.js..."
  },
  {
    "path": "samples-js/.funcignore",
    "chars": 66,
    "preview": "*.js.map\n*.ts\n.git*\n.vscode\nlocal.settings.json\ntest\ntsconfig.json"
  },
  {
    "path": "samples-js/.gitignore",
    "chars": 1445,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs...."
  },
  {
    "path": "samples-js/functions/backupSiteContent.js",
    "chars": 2306,
    "preview": "const df = require(\"durable-functions\");\nconst fs = require(\"fs/promises\");\nconst readdirp = require(\"readdirp\");\nconst..."
  },
  {
    "path": "samples-js/functions/callActivityWithRetry.js",
    "chars": 615,
    "preview": "const df = require(\"durable-functions\");\n\ndf.app.orchestration(\"callActivityWithRetry\", function* (context) {\n    const..."
  },
  {
    "path": "samples-js/functions/callSubOrchestratorWithRetry.js",
    "chars": 755,
    "preview": "const df = require(\"durable-functions\");\n\nconst subOrchestratorName = \"throwsErrorInLine\";\n\ndf.app.orchestration(\"callSu..."
  },
  {
    "path": "samples-js/functions/cancelTimer.js",
    "chars": 487,
    "preview": "const df = require(\"durable-functions\");\nconst { DateTime } = require(\"luxon\");\n\ndf.app.orchestration(\"cancelTimer\", fun..."
  },
  {
    "path": "samples-js/functions/continueAsNewCounter.js",
    "chars": 574,
    "preview": "const df = require(\"durable-functions\");\nconst { DateTime } = require(\"luxon\");\n\ndf.app.orchestration(\"continueAsNewCoun..."
  },
  {
    "path": "samples-js/functions/counter.js",
    "chars": 899,
    "preview": "const df = require(\"durable-functions\");\n\nconst counterEntityName = \"counterEntity\";\n\ndf.app.entity(counterEntityName, a..."
  },
  {
    "path": "samples-js/functions/httpStart.js",
    "chars": 591,
    "preview": "const df = require(\"durable-functions\");\nconst { app } = require(\"@azure/functions\");\n\napp.http(\"httpStart\", {\n    route..."
  },
  {
    "path": "samples-js/functions/httpSyncStart.js",
    "chars": 1366,
    "preview": "const { app } = require(\"@azure/functions\");\nconst df = require(\"durable-functions\");\n\nconst timeout = \"timeout\";\nconst..."
  },
  {
    "path": "samples-js/functions/listAzureSubscriptions.js",
    "chars": 576,
    "preview": "const df = require(\"durable-functions\");\n\ndf.app.orchestration(\"listAzureSubscriptions\", function* (context) {\n    // Mo..."
  },
  {
    "path": "samples-js/functions/sayHello.js",
    "chars": 1264,
    "preview": "const df = require(\"durable-functions\");\n\nconst helloActivityName = \"sayHello\";\n\ndf.app.orchestration(\"helloSequence\", f..."
  },
  {
    "path": "samples-js/functions/smsPhoneVerification.js",
    "chars": 2201,
    "preview": "const { output } = require(\"@azure/functions\");\nconst df = require(\"durable-functions\");\nconst { DateTime } = require(\"l..."
  },
  {
    "path": "samples-js/functions/weatherMonitor.js",
    "chars": 4567,
    "preview": "const { output } = require(\"@azure/functions\");\nconst df = require(\"durable-functions\");\nconst { DateTime } = require(\"l..."
  },
  {
    "path": "samples-js/host.json",
    "chars": 346,
    "preview": "{\n    \"version\": \"2.0\",\n    \"logging\": {\n        \"applicationInsights\": {\n            \"samplingSettings\": {..."
  },
  {
    "path": "samples-js/package.json",
    "chars": 414,
    "preview": "{\n    \"name\": \"samples-js\",\n    \"version\": \"1.0.0\",\n    \"description\": \"\",\n    \"main\": \"functions/*.js\",\n    \"scripts\":..."
  },
  {
    "path": "samples-ts/.funcignore",
    "chars": 66,
    "preview": "*.js.map\n*.ts\n.git*\n.vscode\nlocal.settings.json\ntest\ntsconfig.json"
  },
  {
    "path": "samples-ts/.gitignore",
    "chars": 1445,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs...."
  },
  {
    "path": "samples-ts/.vscode/extensions.json",
    "chars": 72,
    "preview": "{\n  \"recommendations\": [\n    \"ms-azuretools.vscode-azurefunctions\"\n  ]\n}"
  },
  {
    "path": "samples-ts/.vscode/launch.json",
    "chars": 261,
    "preview": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Attach to Node Functions\",..."
  },
  {
    "path": "samples-ts/.vscode/settings.json",
    "chars": 313,
    "preview": "{\n    \"azureFunctions.deploySubpath\": \".\",\n    \"azureFunctions.postDeployTask\": \"npm install (functions)\",\n    \"azureFun..."
  },
  {
    "path": "samples-ts/.vscode/tasks.json",
    "chars": 896,
    "preview": "{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"type\": \"func\",\n            \"label\": \"func: host start\",..."
  },
  {
    "path": "samples-ts/functions/backupSiteContent.ts",
    "chars": 2879,
    "preview": "import * as df from \"durable-functions\";\nimport * as fs from \"fs/promises\";\nimport * as readdirp from \"readdirp\";\nimport..."
  },
  {
    "path": "samples-ts/functions/callActivityWithRetry.ts",
    "chars": 989,
    "preview": "import { InvocationContext } from \"@azure/functions\";\nimport * as df from \"durable-functions\";\nimport {\n    ActivityHand..."
  },
  {
    "path": "samples-ts/functions/callSubOrchestratorWithRetry.ts",
    "chars": 1100,
    "preview": "import * as df from \"durable-functions\";\nimport { OrchestrationContext, OrchestrationHandler } from \"durable-functions\";..."
  },
  {
    "path": "samples-ts/functions/cancelTimer.ts",
    "chars": 692,
    "preview": "import * as df from \"durable-functions\";\nimport { OrchestrationContext, OrchestrationHandler, TimerTask } from \"durable-..."
  },
  {
    "path": "samples-ts/functions/continueAsNewCounter.ts",
    "chars": 763,
    "preview": "import * as df from \"durable-functions\";\nimport { OrchestrationContext, OrchestrationHandler } from \"durable-functions\";..."
  },
  {
    "path": "samples-ts/functions/counter.ts",
    "chars": 1279,
    "preview": "import * as df from \"durable-functions\";\nimport {\n    EntityHandler,\n    EntityContext,\n    OrchestrationContext,\n    Or..."
  },
  {
    "path": "samples-ts/functions/httpStart.ts",
    "chars": 1262,
    "preview": "import * as df from \"durable-functions\";\nimport { app, HttpHandler, HttpRequest, HttpResponse, InvocationContext } from..."
  },
  {
    "path": "samples-ts/functions/httpSyncStart.ts",
    "chars": 1616,
    "preview": "import {\n    app,\n    HttpHandler,\n    HttpRequest,\n    HttpResponse,\n    HttpResponseInit,\n    InvocationContext,\n} fro..."
  },
  {
    "path": "samples-ts/functions/listAzureSubscriptions.ts",
    "chars": 755,
    "preview": "import * as df from \"durable-functions\";\nimport { OrchestrationContext, OrchestrationHandler } from \"durable-functions\";..."
  },
  {
    "path": "samples-ts/functions/orchestrationVersion.ts",
    "chars": 2193,
    "preview": "import * as df from \"durable-functions\";\nimport { ActivityHandler, OrchestrationContext, OrchestrationHandler } from \"du..."
  },
  {
    "path": "samples-ts/functions/sayHello.ts",
    "chars": 1883,
    "preview": "import * as df from \"durable-functions\";\nimport { ActivityHandler, OrchestrationContext, OrchestrationHandler } from \"du..."
  },
  {
    "path": "samples-ts/functions/smsPhoneVerification.ts",
    "chars": 2602,
    "preview": "import { InvocationContext, output } from \"@azure/functions\";\nimport * as df from \"durable-functions\";\nimport {\n    Acti..."
  },
  {
    "path": "samples-ts/functions/weatherMonitor.ts",
    "chars": 5444,
    "preview": "import { InvocationContext, output } from \"@azure/functions\";\nimport * as df from \"durable-functions\";\nimport { DateTime..."
  },
  {
    "path": "samples-ts/host.json",
    "chars": 444,
    "preview": "{\n    \"version\": \"2.0\",\n    \"logging\": {\n        \"applicationInsights\": {\n            \"samplingSettings\": {..."
  },
  {
    "path": "samples-ts/package.json",
    "chars": 635,
    "preview": "{\n    \"name\": \"samples-ts\",\n    \"version\": \"1.0.0\",\n    \"description\": \"\",\n    \"main\": \"dist/functions/*.js\",\n    \"scrip..."
  },
  {
    "path": "samples-ts/tsconfig.json",
    "chars": 191,
    "preview": "{\n    \"compilerOptions\": {\n        \"module\": \"commonjs\",\n        \"target\": \"es6\",\n        \"outDir\": \"dist\",\n        \"roo..."
  },
  {
    "path": "src/Constants.ts",
    "chars": 210,
    "preview": "/** @hidden */\nexport class Constants {\n    public static readonly DefaultLocalHost: string = \"localhost:7071\";\n    publ..."
  },
  {
    "path": "src/ManagedIdentityTokenSource.ts",
    "chars": 265,
    "preview": "import * as types from \"durable-functions\";\n\nexport class ManagedIdentityTokenSource implements types.ManagedIdentityTok..."
  },
  {
    "path": "src/RetryOptions.ts",
    "chars": 806,
    "preview": "import { Utils } from \"./util/Utils\";\nimport * as types from \"durable-functions\";\n\nexport class RetryOptions implements..."
  },
  {
    "path": "src/actions/ActionType.ts",
    "chars": 878,
    "preview": "/**\n * @hidden\n *\n * The type of asynchronous behavior the Durable Functions extension should\n * perform on behalf of th..."
  },
  {
    "path": "src/actions/CallActivityAction.ts",
    "chars": 482,
    "preview": "import { Utils } from \"../util/Utils\";\nimport { ActionType } from \"./ActionType\";\nimport { IAction } from \"./IAction\";..."
  },
  {
    "path": "src/actions/CallActivityWithRetryAction.ts",
    "chars": 801,
    "preview": "import { Utils } from \"../util/Utils\";\nimport { RetryOptions } from \"../RetryOptions\";\nimport { ActionType } from \"./Act..."
  },
  {
    "path": "src/actions/CallEntityAction.ts",
    "chars": 752,
    "preview": "import { EntityId } from \"../entities/EntityId\";\nimport { Utils } from \"../util/Utils\";\nimport { ActionType } from \"./Ac..."
  },
  {
    "path": "src/actions/CallHttpAction.ts",
    "chars": 347,
    "preview": "import { DurableHttpRequest } from \"../http/DurableHttpRequest\";\nimport { ActionType } from \"./ActionType\";\nimport { IAc..."
  },
  {
    "path": "src/actions/CallSubOrchestratorAction.ts",
    "chars": 680,
    "preview": "import { Utils } from \"../util/Utils\";\nimport { ActionType } from \"./ActionType\";\nimport { IAction } from \"./IAction\";..."
  },
  {
    "path": "src/actions/CallSubOrchestratorWithRetryAction.ts",
    "chars": 977,
    "preview": "import { RetryOptions } from \"../RetryOptions\";\nimport { Utils } from \"../util/Utils\";\nimport { ActionType } from \"./Act..."
  },
  {
    "path": "src/actions/ContinueAsNewAction.ts",
    "chars": 387,
    "preview": "import { Utils } from \"../util/Utils\";\nimport { ActionType } from \"./ActionType\";\nimport { IAction } from \"./IAction\";..."
  },
  {
    "path": "src/actions/CreateTimerAction.ts",
    "chars": 476,
    "preview": "import { types } from \"util\";\nimport { ActionType } from \"./ActionType\";\nimport { IAction } from \"./IAction\";\n\n/** @hidd..."
  },
  {
    "path": "src/actions/ExternalEventType.ts",
    "chars": 297,
    "preview": "/**\n * @hidden\n * Represents the options that can be provided for the \"reason\" field of events in\n * Durable Functions 2..."
  },
  {
    "path": "src/actions/IAction.ts",
    "chars": 116,
    "preview": "import { ActionType } from \"./ActionType\";\n\n/** @hidden */\nexport interface IAction {\n    actionType: ActionType;\n}\n"
  },
  {
    "path": "src/actions/SignalEntityAction.ts",
    "chars": 758,
    "preview": "import { EntityId } from \"../entities/EntityId\";\nimport { Utils } from \"../util/Utils\";\nimport { ActionType } from \"./Ac..."
  },
  {
    "path": "src/actions/WaitForExternalEventAction.ts",
    "chars": 549,
    "preview": "import { Utils } from \"../util/Utils\";\nimport { ActionType } from \"./ActionType\";\nimport { ExternalEventType } from \"./E..."
  },
  {
    "path": "src/actions/WhenAllAction.ts",
    "chars": 397,
    "preview": "import { DFTask } from \"../task\";\nimport { ActionType } from \"./ActionType\";\nimport { IAction } from \"./IAction\";\n\n/** @..."
  },
  {
    "path": "src/actions/WhenAnyAction.ts",
    "chars": 397,
    "preview": "import { DFTask } from \"../task\";\nimport { ActionType } from \"./ActionType\";\nimport { IAction } from \"./IAction\";\n\n/** @..."
  },
  {
    "path": "src/app.ts",
    "chars": 2078,
    "preview": "import {\n    ActivityOptions,\n    EntityHandler,\n    EntityOptions,\n    OrchestrationHandler,\n    OrchestrationOptions,..."
  },
  {
    "path": "src/client.ts",
    "chars": 3849,
    "preview": "import * as input from \"./input\";\nimport {\n    CosmosDBDurableClientOptions,\n    DurableClientHandler,\n    DurableClient..."
  },
  {
    "path": "src/durableClient/DurableClient.ts",
    "chars": 34676,
    "preview": "// tslint:disable:member-access\n\nimport { HttpRequest, HttpResponse } from \"@azure/functions\";\nimport OpenTelemetryApi =..."
  },
  {
    "path": "src/durableClient/OrchestrationClientInputData.ts",
    "chars": 1055,
    "preview": "import { HttpCreationPayload } from \"../http/HttpCreationPayload\";\r\nimport { HttpManagementPayload } from \"../http/HttpM..."
  },
  {
    "path": "src/durableClient/PurgeHistoryResult.ts",
    "chars": 178,
    "preview": "import * as types from \"durable-functions\";\n\nexport class PurgeHistoryResult implements types.PurgeHistoryResult {\n    c..."
  },
  {
    "path": "src/durableClient/getClient.ts",
    "chars": 2999,
    "preview": "import { FunctionInput, InvocationContext } from \"@azure/functions\";\nimport { DurableClientInput } from \"durable-functio..."
  },
  {
    "path": "src/entities/DurableEntityBindingInfo.ts",
    "chars": 659,
    "preview": "import { EntityId } from \"./EntityId\";\nimport { RequestMessage } from \"./RequestMessage\";\n\n/** @hidden */\nexport class D..."
  },
  {
    "path": "src/entities/DurableLock.ts",
    "chars": 105,
    "preview": "/**\n * @hidden\n * For use with locking operations.\n * TODO: improve this\n */\nexport class DurableLock {}\n"
  },
  {
    "path": "src/entities/Entity.ts",
    "chars": 5712,
    "preview": "import * as debug from \"debug\";\nimport {\n    DurableEntityBindingInfoReqFields,\n    DurableEntityBindingInfo,\n} from \"./..."
  },
  {
    "path": "src/entities/EntityId.ts",
    "chars": 1038,
    "preview": "// tslint:disable:member-access\n\nimport { Utils } from \"../util/Utils\";\nimport * as types from \"durable-functions\";\n\nexp..."
  },
  {
    "path": "src/entities/EntityState.ts",
    "chars": 434,
    "preview": "import { OperationResult } from \"./OperationResult\";\nimport { Signal } from \"./Signal\";\n\n/** @hidden */\nexport class Ent..."
  },
  {
    "path": "src/entities/EntityStateResponse.ts",
    "chars": 198,
    "preview": "import * as types from \"durable-functions\";\n\nexport class EntityStateResponse<T> implements types.EntityStateResponse<T>..."
  },
  {
    "path": "src/entities/LockState.ts",
    "chars": 407,
    "preview": "import { EntityId } from \"./EntityId\";\n\n/**\n * @hidden\n * Returned by [DurableOrchestrationContext].[isLocked] and\n * [D..."
  },
  {
    "path": "src/entities/OperationResult.ts",
    "chars": 213,
    "preview": "/** @hidden */\nexport class OperationResult {\n    constructor(\n        readonly isError: boolean,\n        readonly durat..."
  },
  {
    "path": "src/entities/RequestMessage.ts",
    "chars": 1022,
    "preview": "import { EntityId } from \"./EntityId\";\n\n/** @hidden */\nexport class RequestMessage {\n    /** A unique identifier for thi..."
  },
  {
    "path": "src/entities/ResponseMessage.ts",
    "chars": 830,
    "preview": "import { Utils } from \"../util/Utils\";\n\n/** @hidden */\nexport class ResponseMessage {\n    public result?: string; // Res..."
  },
  {
    "path": "src/entities/Signal.ts",
    "chars": 311,
    "preview": "import { EntityId } from \"./EntityId\";\n\n/** @hidden */\nexport class Signal {\n    constructor(\n        public readonly ta..."
  },
  {
    "path": "src/error/AggregatedError.ts",
    "chars": 627,
    "preview": "import * as types from \"durable-functions\";\n\n/** @hidden */\nconst separator = \"-----------------------------------\";\n\nex..."
  },
  {
    "path": "src/error/DurableError.ts",
    "chars": 196,
    "preview": "import * as types from \"durable-functions\";\n\nexport class DurableError extends Error implements types.DurableError {..."
  },
  {
    "path": "src/error/OrchestrationFailureError.ts",
    "chars": 1219,
    "preview": "import { OrchestratorState } from \"../orchestrations/OrchestratorState\";\n\n/** @hidden */\nconst outOfProcDataLabel = \"\\n\\..."
  },
  {
    "path": "src/history/EventRaisedEvent.ts",
    "chars": 668,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/EventSentEvent.ts",
    "chars": 855,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/ExecutionStartedEvent.ts",
    "chars": 821,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/HistoryEvent.ts",
    "chars": 322,
    "preview": "import { HistoryEventType } from \"./HistoryEventType\";\n\n/** @hidden */\nexport abstract class HistoryEvent {\n    construc..."
  },
  {
    "path": "src/history/HistoryEventOptions.ts",
    "chars": 445,
    "preview": "/** @hidden */\nexport class HistoryEventOptions {\n    public details?: string;\n    public fireAt?: Date;\n    public inpu..."
  },
  {
    "path": "src/history/HistoryEventType.ts",
    "chars": 741,
    "preview": "/**\n * @hidden\n * Corresponds to subclasses of HistoryEvent type in [Durable Task framework.](https://github.com/Azure/d..."
  },
  {
    "path": "src/history/OrchestratorCompletedEvent.ts",
    "chars": 465,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/OrchestratorStartedEvent.ts",
    "chars": 461,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/SubOrchestrationInstanceCompletedEvent.ts",
    "chars": 1001,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/SubOrchestrationInstanceCreatedEvent.ts",
    "chars": 1001,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/SubOrchestrationInstanceFailedEvent.ts",
    "chars": 932,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/TaskCompletedEvent.ts",
    "chars": 832,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/TaskFailedEvent.ts",
    "chars": 784,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/TaskScheduledEvent.ts",
    "chars": 653,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/TimerCreatedEvent.ts",
    "chars": 589,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/history/TimerFiredEvent.ts",
    "chars": 782,
    "preview": "import { HistoryEvent } from \"./HistoryEvent\";\nimport { HistoryEventOptions } from \"./HistoryEventOptions\";\nimport { His..."
  },
  {
    "path": "src/http/DurableHttpRequest.ts",
    "chars": 1298,
    "preview": "import { TokenSource } from \"durable-functions\";\n\n/**\n * Data structure representing a durable HTTP request.\n */\nexport..."
  },
  {
    "path": "src/http/DurableHttpResponse.ts",
    "chars": 1181,
    "preview": "/**\n * Data structure representing a durable HTTP response.\n */\nexport class DurableHttpResponse {\n    /**\n     * Create..."
  },
  {
    "path": "src/http/HttpCreationPayload.ts",
    "chars": 181,
    "preview": "/** @hidden */\nexport class HttpCreationPayload {\n    [key: string]: string;\n\n    constructor(public createNewInstancePo..."
  },
  {
    "path": "src/http/HttpManagementPayload.ts",
    "chars": 598,
    "preview": "import * as types from \"durable-functions\";\n\nexport class HttpManagementPayload implements types.HttpManagementPayload {..."
  },
  {
    "path": "src/index.ts",
    "chars": 799,
    "preview": "import { DummyEntityContext, DummyOrchestrationContext } from \"./util/testingUtils\";\r\nimport { ManagedIdentityTokenSourc..."
  },
  {
    "path": "src/input.ts",
    "chars": 264,
    "preview": "import { DurableClientInput } from \"durable-functions\";\nimport { input as azFuncInput } from \"@azure/functions\";\n\nexport..."
  },
  {
    "path": "src/orchestrations/DurableOrchestrationBindingInfo.ts",
    "chars": 1397,
    "preview": "import { HistoryEvent } from \"../history/HistoryEvent\";\nimport { ReplaySchema } from \"./ReplaySchema\";\n\n/** @hidden */\ne..."
  },
  {
    "path": "src/orchestrations/DurableOrchestrationContext.ts",
    "chars": 13745,
    "preview": "import { TaskOrchestrationExecutor } from \"./TaskOrchestrationExecutor\";\nimport { WhenAllAction } from \"../actions/WhenA..."
  },
  {
    "path": "src/orchestrations/DurableOrchestrationStatus.ts",
    "chars": 2408,
    "preview": "import * as types from \"durable-functions\";\nimport { OrchestrationRuntimeStatus } from \"./OrchestrationRuntimeStatus\";..."
  },
  {
    "path": "src/orchestrations/IOrchestratorState.ts",
    "chars": 298,
    "preview": "import { IAction } from \"../actions/IAction\";\nimport { ReplaySchema } from \"./ReplaySchema\";\n\n/** @hidden */\nexport inte..."
  },
  {
    "path": "src/orchestrations/OrchestrationRuntimeStatus.ts",
    "chars": 271,
    "preview": "export enum OrchestrationRuntimeStatus {\n    Running = \"Running\",\n    Completed = \"Completed\",\n    ContinuedAsNew = \"Con..."
  },
  {
    "path": "src/orchestrations/Orchestrator.ts",
    "chars": 4992,
    "preview": "import { DurableOrchestrationContext } from \"./DurableOrchestrationContext\";\nimport { TaskOrchestrationExecutor } from \"..."
  },
  {
    "path": "src/orchestrations/OrchestratorState.ts",
    "chars": 4160,
    "preview": "import { IAction } from \"../actions/IAction\";\nimport { WhenAllAction } from \"../actions/WhenAllAction\";\nimport { WhenAny..."
  },
  {
    "path": "src/orchestrations/ReplaySchema.ts",
    "chars": 193,
    "preview": "/**\n * @hidden\n * Supported OOProc DF extension protocols\n */\nexport enum ReplaySchema {\n    V1 = 0,\n    V2 = 1,\n    V3..."
  },
  {
    "path": "src/orchestrations/TaskOrchestrationExecutor.ts",
    "chars": 22687,
    "preview": "import { OrchestrationFailureError } from \"../error/OrchestrationFailureError\";\nimport { OrchestratorState } from \"./Orc..."
  },
  {
    "path": "src/task/AtomicTask.ts",
    "chars": 78,
    "preview": "import { DFTask } from \"./DFTask\";\n\nexport class AtomicTask extends DFTask {}\n"
  },
  {
    "path": "src/task/CallHttpWithPollingTask.ts",
    "chars": 3987,
    "preview": "import { CompoundTask } from \"./CompoundTask\";\nimport { AtomicTask, TaskBase, TaskID, TaskState } from \".\";\nimport { Dur..."
  },
  {
    "path": "src/task/CompoundTask.ts",
    "chars": 2096,
    "preview": "import { TaskOrchestrationExecutor } from \"src/orchestrations/TaskOrchestrationExecutor\";\nimport { IAction } from \"../ac..."
  },
  {
    "path": "src/task/DFTask.ts",
    "chars": 462,
    "preview": "import { Task } from \"durable-functions\";\nimport { TaskBase } from \"./TaskBase\";\nimport { IAction } from \"../actions/IAc..."
  },
  {
    "path": "src/task/DFTimerTask.ts",
    "chars": 1093,
    "preview": "import { TimerTask } from \"durable-functions\";\nimport { AtomicTask } from \"./AtomicTask\";\nimport { TaskID } from \".\";\nim..."
  },
  {
    "path": "src/task/LongTimerTask.ts",
    "chars": 4005,
    "preview": "import { DurableOrchestrationContext, TimerTask } from \"durable-functions\";\nimport { WhenAllTask } from \"./WhenAllTask\";..."
  },
  {
    "path": "src/task/NoOpTask.ts",
    "chars": 440,
    "preview": "import { TaskBase } from \"./TaskBase\";\n\n/**\n * @hidden\n *\n * A task created only to facilitate replay, it should not com..."
  },
  {
    "path": "src/task/RegisteredActivityTask.ts",
    "chars": 1503,
    "preview": "import * as types from \"durable-functions\";\nimport { AtomicTask } from \"./AtomicTask\";\nimport { RetryOptions } from \"../..."
  },
  {
    "path": "src/task/RegisteredOrchestrationTask.ts",
    "chars": 1661,
    "preview": "import * as types from \"durable-functions\";\nimport { CallSubOrchestratorAction } from \"../actions/CallSubOrchestratorAct..."
  },
  {
    "path": "src/task/RetryableTask.ts",
    "chars": 3737,
    "preview": "import { RetryOptions } from \"durable-functions\";\nimport { TaskOrchestrationExecutor } from \"../orchestrations/TaskOrche..."
  },
  {
    "path": "src/task/TaskBase.ts",
    "chars": 2597,
    "preview": "import { TaskOrchestrationExecutor } from \"src/orchestrations/TaskOrchestrationExecutor\";\nimport { BackingAction, TaskID..."
  },
  {
    "path": "src/task/WhenAllTask.ts",
    "chars": 1510,
    "preview": "import { CompoundTask } from \"./CompoundTask\";\nimport { TaskBase } from \"./TaskBase\";\nimport { AtomicTask } from \"./Atom..."
  },
  {
    "path": "src/task/WhenAnyTask.ts",
    "chars": 971,
    "preview": "import { TaskState } from \".\";\nimport { CompoundTask } from \"./CompoundTask\";\nimport { TaskBase } from \"./TaskBase\";\n\n/*..."
  },
  {
    "path": "src/task/index.ts",
    "chars": 859,
    "preview": "import { IAction } from \"../actions/IAction\";\n\n/**\n * @hidden\n * The states a task can be in\n */\nexport enum TaskState {..."
  },
  {
    "path": "src/trigger.ts",
    "chars": 595,
    "preview": "import { ActivityTrigger, EntityTrigger, OrchestrationTrigger } from \"durable-functions\";\nimport { trigger as azFuncTrig..."
  },
  {
    "path": "src/util/GuidManager.ts",
    "chars": 1332,
    "preview": "import * as crypto from \"crypto\";\n/** @hidden */\nimport { v5 as uuidv5 } from \"uuid\";\nimport { Utils } from \"./Utils\";..."
  },
  {
    "path": "src/util/Utils.ts",
    "chars": 4324,
    "preview": "/** @hidden */\nexport class Utils {\n    public static processInput<T>(input: string | T): string | T {\n        // If we..."
  },
  {
    "path": "src/util/WebhookUtils.ts",
    "chars": 1552,
    "preview": "/** @hidden */\nexport class WebhookUtils {\n    public static getReadEntityUrl(\n        baseUrl: string,\n        required..."
  },
  {
    "path": "src/util/testingUtils.ts",
    "chars": 6034,
    "preview": "import {\n    FunctionHandler,\n    InvocationContext,\n    InvocationContextInit,\n    LogHandler,\n} from \"@azure/functions..."
  },
  {
    "path": "test/integration/entity-spec.ts",
    "chars": 3154,
    "preview": "import { expect } from \"chai\";\r\nimport \"mocha\";\r\nimport { DummyEntityContext } from \"../../src/util/testingUtils\";\r\nimpo..."
  },
  {
    "path": "test/integration/orchestrator-spec.ts",
    "chars": 122258,
    "preview": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\r\nimport { expect } from \"chai\";\r\nimport \"mocha\";\r\nimport *..."
  },
  {
    "path": "test/test-app/.funcignore",
    "chars": 120,
    "preview": "*.js.map\n*.ts\n.git*\n.vscode\n__azurite_db*__.json\n__blobstorage__\n__queuestorage__\nlocal.settings.json\ntest\ntsconfig.json"
  },
  {
    "path": "test/test-app/.gitignore",
    "chars": 1445,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs...."
  },
  {
    "path": "test/test-app/.vscode/extensions.json",
    "chars": 72,
    "preview": "{\n  \"recommendations\": [\n    \"ms-azuretools.vscode-azurefunctions\"\n  ]\n}"
  },
  {
    "path": "test/test-app/.vscode/launch.json",
    "chars": 260,
    "preview": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Attach to Node Functions\",..."
  },
  {
    "path": "test/test-app/.vscode/settings.json",
    "chars": 358,
    "preview": "{\n    \"azureFunctions.deploySubpath\": \".\",\n    \"azureFunctions.postDeployTask\": \"npm install (functions)\",\n    \"azureFun..."
  },
  {
    "path": "test/test-app/.vscode/tasks.json",
    "chars": 667,
    "preview": "{\n\t\"version\": \"2.0.0\",\n\t\"tasks\": [\n\t\t{\n\t\t\t\"type\": \"func\",\n\t\t\t\"label\": \"func: host start\",\n\t\t\t\"command\": \"host start\",..."
  },
  {
    "path": "test/test-app/host.json",
    "chars": 494,
    "preview": "{\n    \"version\": \"2.0\",\n    \"logging\": {\n        \"applicationInsights\": {\n            \"samplingSettings\": {..."
  },
  {
    "path": "test/test-app/package.json",
    "chars": 522,
    "preview": "{\n    \"name\": \"test-app\",\n    \"version\": \"1.0.0\",\n    \"description\": \"\",\n    \"scripts\": {\n        \"build\": \"tsc\",..."
  },
  {
    "path": "test/test-app/src/functions/counter1.ts",
    "chars": 1534,
    "preview": "import { app, HttpHandler, HttpRequest, HttpResponse, InvocationContext } from \"@azure/functions\";\nimport * as df from \"..."
  },
  {
    "path": "test/test-app/src/functions/hello.ts",
    "chars": 1468,
    "preview": "import { app, HttpHandler, HttpRequest, HttpResponse, InvocationContext } from \"@azure/functions\";\nimport * as df from \"..."
  },
  {
    "path": "test/test-app/tsconfig.json",
    "chars": 191,
    "preview": "{\n    \"compilerOptions\": {\n        \"module\": \"commonjs\",\n        \"target\": \"es6\",\n        \"outDir\": \"dist\",\n        \"roo..."
  },
  {
    "path": "test/testobjects/TestOrchestrations.ts",
    "chars": 16985,
    "preview": "import * as df from \"../../src\";\r\nimport { OrchestrationContext } from \"durable-functions\";\r\nimport { createOrchestrator..."
  },
  {
    "path": "test/testobjects/testconstants.ts",
    "chars": 4392,
    "preview": "export class TestConstants {\r\n    public static readonly connectionPlaceholder: string = \"CONNECTION\";\r\n    public stati..."
  },
  {
    "path": "test/testobjects/testentities.ts",
    "chars": 2101,
    "preview": "import { createEntityFunction } from \"../../src/util/testingUtils\";\r\n\r\nexport class TestEntities {\r\n    public static St..."
  },
  {
    "path": "test/testobjects/testentitybatches.ts",
    "chars": 9565,
    "preview": "import { DurableEntityBindingInfo } from \"../../src/entities/DurableEntityBindingInfo\";\r\nimport { EntityState } from \"....."
  },
  {
    "path": "test/testobjects/testentityoperations.ts",
    "chars": 698,
    "preview": "import { DurableEntityBindingInfo } from \"../../src/entities/DurableEntityBindingInfo\";\r\nimport { EntityState } from \"....."
  },
  {
    "path": "test/testobjects/testhistories.ts",
    "chars": 92221,
    "preview": "import * as moment from \"moment\";\r\nimport { EventRaisedEvent } from \"../../src/history/EventRaisedEvent\";\r\nimport { Even..."
  },
  {
    "path": "test/testobjects/testutils.ts",
    "chars": 5295,
    "preview": "import { HttpCreationPayload } from \"../../src/http/HttpCreationPayload\";\r\nimport { IOrchestratorState } from \"../../src..."
  },
  {
    "path": "test/unit/createtimeraction-spec.ts",
    "chars": 1214,
    "preview": "import { expect } from \"chai\";\nimport \"mocha\";\nimport { ActionType } from \"../../src/actions/ActionType\";\nimport { Creat..."
  },
  {
    "path": "test/unit/durableclient-spec.ts",
    "chars": 27902,
    "preview": "import { HttpRequest } from \"@azure/functions\";\r\nimport chai = require(\"chai\");\r\nimport chaiString = require(\"chai-strin..."
  },
  {
    "path": "test/unit/entityid-spec.ts",
    "chars": 1378,
    "preview": "import { expect } from \"chai\";\r\nimport \"mocha\";\r\nimport { EntityId } from \"../../src/entities/EntityId\";\r\n\r\ndescribe(\"En..."
  },
  {
    "path": "test/unit/getclient-spec.ts",
    "chars": 5728,
    "preview": "import { InvocationContext } from \"@azure/functions\";\r\nimport { expect } from \"chai\";\r\nimport chai = require(\"chai\");\r\ni..."
  },
  {
    "path": "test/unit/guidmanager-spec.ts",
    "chars": 1874,
    "preview": "import { expect } from \"chai\";\r\nimport \"mocha\";\r\nimport moment = require(\"moment\");\r\nimport { GuidManager } from \"../../..."
  },
  {
    "path": "test/unit/orchestrationclient-spec.ts",
    "chars": 80682,
    "preview": "// tslint:disable:member-access\r\n\r\nimport { HttpRequest } from \"@azure/functions\";\r\nimport chai = require(\"chai\");\r\nimpo..."
  },
  {
    "path": "test/unit/retryoptions-spec.ts",
    "chars": 399,
    "preview": "import { expect } from \"chai\";\r\nimport \"mocha\";\r\nimport { RetryOptions } from \"../../src/RetryOptions\";\r\n\r\ndescribe(\"Ret..."
  },
  {
    "path": "test/unit/shim-spec.ts",
    "chars": 4871,
    "preview": "import { app as AzFuncApp, FunctionInput } from \"@azure/functions\";\nimport { expect } from \"chai\";\nimport sinon = requir..."
  },
  {
    "path": "test/unit/timertask-spec.ts",
    "chars": 1279,
    "preview": "import { expect } from \"chai\";\r\nimport \"mocha\";\r\nimport { DFTimerTask } from \"../../src/task\";\r\nimport { CreateTimerActi..."
  },
  {
    "path": "test/unit/utils-spec.ts",
    "chars": 6218,
    "preview": "import { expect } from \"chai\";\r\nimport \"mocha\";\r\nimport { Utils } from \"../../src/util/Utils\";\r\n\r\ndescribe(\"Utils\", () =..."
  },
  {
    "path": "tsconfig.json",
    "chars": 683,
    "preview": "{\r\n    \"compilerOptions\": {\r\n        \"strictNullChecks\": true,\r\n        \"declaration\": false,\r\n        \"module\": \"common..."
  },
  {
    "path": "tsconfig.nocomments",
    "chars": 115,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"declaration\": false,\n    \"removeComments\": true\n  }\n}"
  },
  {
    "path": "types/activity.d.ts",
    "chars": 696,
    "preview": "import {\n    FunctionHandler,\n    FunctionInput,\n    FunctionOptions,\n    FunctionOutput,\n    FunctionTrigger,\n} from \"@..."
  },
  {
    "path": "types/app.client.d.ts",
    "chars": 5996,
    "preview": "import {\n    CosmosDBDurableClientOptions,\n    DurableClientOptions,\n    EventGridDurableClientOptions,\n    EventHubDura..."
  },
  {
    "path": "types/app.d.ts",
    "chars": 1983,
    "preview": "import { ActivityOptions, RegisteredActivity } from \"./activity\";\nimport { EntityHandler, EntityOptions } from \"./entity..."
  },
  {
    "path": "types/durableClient.d.ts",
    "chars": 16697,
    "preview": "import {\n    CosmosDBv3FunctionOptions,\n    CosmosDBv4FunctionOptions,\n    EventGridEvent,\n    EventGridFunctionOptions,..."
  },
  {
    "path": "types/entity.d.ts",
    "chars": 5135,
    "preview": "import { FunctionOptions, FunctionTrigger, InvocationContext, LogHandler } from \"@azure/functions\";\n\nexport type EntityH..."
  },
  {
    "path": "types/index.d.ts",
    "chars": 3213,
    "preview": "import { InvocationContext } from \"@azure/functions\";\nimport { DurableClient } from \"./durableClient\";\n\nexport * from \"...."
  },
  {
    "path": "types/input.d.ts",
    "chars": 172,
    "preview": "import { DurableClientInput } from \"./durableClient\";\n\n/**\n * @returns a durable client input configuration object\n */\ne..."
  },
  {
    "path": "types/orchestration.d.ts",
    "chars": 14467,
    "preview": "import { FunctionOptions, FunctionTrigger, InvocationContext, LogHandler } from \"@azure/functions\";\nimport { RetryOption..."
  },
  {
    "path": "types/task.d.ts",
    "chars": 2957,
    "preview": "/**\n * A Durable Functions Task.\n */\nexport interface Task {\n    /**\n     * Whether the task has completed. Note that co..."
  },
  {
    "path": "types/trigger.d.ts",
    "chars": 432,
    "preview": "import { ActivityTrigger } from \"./activity\";\nimport { EntityTrigger } from \"./entity\";\nimport { OrchestrationTrigger }..."
  }
]

About this extraction

This page contains the full source code of the Azure/azure-functions-durable-js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 194 files (710.1 KB), approximately 148.1k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!