Repository: Azure/azure-functions-durable-js
Pull request #528 (2023-07-25 01:20:52)

Group orchestration files together
No functional changes, just moving code around. This PR moves orchestration-related files to their own `orchestrations` directory, reducing the flatness of `src`. Also renames the files to match the casing of the classes they export. This PR also deletes the `shim` file (it does nothing now. It should have been deleted with #525, but a rebase brought it back and I merged before noticing)


Patch:
diff --git a/src/classes.ts b/src/classes.ts
index eb5efdc..ae2c096 100644
--- a/src/classes.ts
+++ b/src/classes.ts
@@ -2,11 +2,11 @@
 export { Constants } from "./constants";
 export { Utils } from "./util/Utils";
 
-export { Orchestrator } from "./orchestrator";
+export { Orchestrator } from "./orchestrations/Orchestrator";
 export { Entity } from "./entities/Entity";
 
-export { DurableOrchestrationBindingInfo } from "./durableorchestrationbindinginfo";
-export { DurableOrchestrationContext } from "./durableorchestrationcontext";
+export { DurableOrchestrationBindingInfo } from "./orchestrations/DurableOrchestrationBindingInfo";
+export { DurableOrchestrationContext } from "./orchestrations/DurableOrchestrationContext";
 
 export { IAction } from "./actions/iaction";
 export { ActionType } from "./actions/actiontype";
@@ -38,8 +38,8 @@ export { TaskScheduledEvent } from "./history/taskscheduledevent";
 export { TimerCreatedEvent } from "./history/timercreatedevent";
 export { TimerFiredEvent } from "./history/timerfiredevent";
 
-export { OrchestratorState } from "./orchestratorstate";
-export { IOrchestratorState } from "./iorchestratorstate";
+export { OrchestratorState } from "./orchestrations/OrchestratorState";
+export { IOrchestratorState } from "./orchestrations/IOrchestratorState";
 
 export { RetryOptions } from "./retryoptions";
 
@@ -48,8 +48,8 @@ export { OrchestrationClientInputData } from "./orchestrationclientinputdata";
 export { HttpCreationPayload } from "./http/HttpCreationPayload";
 export { HttpManagementPayload } from "./http/HttpManagementPayload";
 
-export { DurableOrchestrationStatus } from "./durableorchestrationstatus";
-export { OrchestrationRuntimeStatus } from "./orchestrationruntimestatus";
+export { DurableOrchestrationStatus } from "./orchestrations/DurableOrchestrationStatus";
+export { OrchestrationRuntimeStatus } from "./orchestrations/OrchestrationRuntimeStatus";
 export { PurgeHistoryResult } from "./purgehistoryresult";
 
 export { GuidManager } from "./guidmanager";
diff --git a/src/durableorchestrationbindinginfo.ts b/src/orchestrations/DurableOrchestrationBindingInfo.ts
similarity index 91%
rename from src/durableorchestrationbindinginfo.ts
rename to src/orchestrations/DurableOrchestrationBindingInfo.ts
index 17db123..cd9859c 100644
--- a/src/durableorchestrationbindinginfo.ts
+++ b/src/orchestrations/DurableOrchestrationBindingInfo.ts
@@ -1,31 +1,31 @@
-import { HistoryEvent } from "./classes";
-import { ReplaySchema } from "./replaySchema";
-
-/** @hidden */
-export class DurableOrchestrationBindingInfoReqFields {
-    constructor(
-        public readonly history: HistoryEvent[] = [],
-        public readonly instanceId: string = "",
-        public readonly isReplaying: boolean = false,
-        public readonly upperSchemaVersion: ReplaySchema = ReplaySchema.V1 // TODO: Implement entity locking // public readonly contextLocks?: EntityId[],
-    ) {}
-}
-
-/** @hidden */
-export class DurableOrchestrationBindingInfo extends DurableOrchestrationBindingInfoReqFields {
-    public readonly upperSchemaVersionNew?: ReplaySchema;
-
-    constructor(
-        public readonly history: HistoryEvent[] = [],
-        public readonly input?: unknown,
-        public readonly instanceId: string = "",
-        public readonly isReplaying: boolean = false,
-        public readonly parentInstanceId?: string,
-        public readonly maximumShortTimerDuration?: string,
-        public readonly longRunningTimerIntervalDuration?: string,
-        public readonly defaultHttpAsyncRequestSleepTimeMillseconds?: number,
-        public readonly upperSchemaVersion: ReplaySchema = ReplaySchema.V1 // TODO: Implement entity locking // public readonly contextLocks?: EntityId[],
-    ) {
-        super(history, instanceId, isReplaying, upperSchemaVersion);
-    }
-}
+import { HistoryEvent } from "../classes";
+import { ReplaySchema } from "./ReplaySchema";
+
+/** @hidden */
+export class DurableOrchestrationBindingInfoReqFields {
+    constructor(
+        public readonly history: HistoryEvent[] = [],
+        public readonly instanceId: string = "",
+        public readonly isReplaying: boolean = false,
+        public readonly upperSchemaVersion: ReplaySchema = ReplaySchema.V1 // TODO: Implement entity locking // public readonly contextLocks?: EntityId[],
+    ) {}
+}
+
+/** @hidden */
+export class DurableOrchestrationBindingInfo extends DurableOrchestrationBindingInfoReqFields {
+    public readonly upperSchemaVersionNew?: ReplaySchema;
+
+    constructor(
+        public readonly history: HistoryEvent[] = [],
+        public readonly input?: unknown,
+        public readonly instanceId: string = "",
+        public readonly isReplaying: boolean = false,
+        public readonly parentInstanceId?: string,
+        public readonly maximumShortTimerDuration?: string,
+        public readonly longRunningTimerIntervalDuration?: string,
+        public readonly defaultHttpAsyncRequestSleepTimeMillseconds?: number,
+        public readonly upperSchemaVersion: ReplaySchema = ReplaySchema.V1 // TODO: Implement entity locking // public readonly contextLocks?: EntityId[],
+    ) {
+        super(history, instanceId, isReplaying, upperSchemaVersion);
+    }
+}
diff --git a/src/durableorchestrationcontext.ts b/src/orchestrations/DurableOrchestrationContext.ts
similarity index 94%
rename from src/durableorchestrationcontext.ts
rename to src/orchestrations/DurableOrchestrationContext.ts
index 8f9c130..0ebc86c 100644
--- a/src/durableorchestrationcontext.ts
+++ b/src/orchestrations/DurableOrchestrationContext.ts
@@ -1,312 +1,312 @@
-import {
-    EntityId,
-    RetryOptions,
-    CallActivityAction,
-    CallActivityWithRetryAction,
-    CallEntityAction,
-    CallHttpAction,
-    CallSubOrchestratorAction,
-    CallSubOrchestratorWithRetryAction,
-    ContinueAsNewAction,
-    CreateTimerAction,
-    DurableHttpRequest,
-    ExternalEventType,
-    GuidManager,
-    HistoryEvent,
-    WaitForExternalEventAction,
-} from "./classes";
-import { TaskOrchestrationExecutor } from "./taskorchestrationexecutor";
-import { WhenAllAction } from "./actions/whenallaction";
-import { WhenAnyAction } from "./actions/whenanyaction";
-import {
-    WhenAllTask,
-    WhenAnyTask,
-    AtomicTask,
-    RetryableTask,
-    DFTimerTask,
-    DFTask,
-    LongTimerTask,
-    CallHttpWithPollingTask,
-} from "./task";
-import moment = require("moment");
-import { ReplaySchema } from "./replaySchema";
-import { CallHttpOptions, Task, TimerTask } from "durable-functions";
-import * as types from "durable-functions";
-import { SignalEntityAction } from "./actions/signalentityaction";
-
-/**
- * Parameter data for orchestration bindings that can be used to schedule
- * function-based activities.
- */
-export class DurableOrchestrationContext implements types.DurableOrchestrationContext {
-    constructor(
-        state: HistoryEvent[],
-        instanceId: string,
-        currentUtcDateTime: Date,
-        isReplaying: boolean,
-        parentInstanceId: string | undefined,
-        longRunningTimerIntervalDuration: string | undefined,
-        maximumShortTimerDuration: string | undefined,
-        defaultHttpAsyncRequestSleepTimeMillseconds: number | undefined,
-        schemaVersion: ReplaySchema,
-        input: unknown,
-        private taskOrchestratorExecutor: TaskOrchestrationExecutor
-    ) {
-        this.state = state;
-        this.instanceId = instanceId;
-        this.isReplaying = isReplaying;
-        this.currentUtcDateTime = currentUtcDateTime;
-        this.parentInstanceId = parentInstanceId;
-        this.longRunningTimerIntervalDuration = longRunningTimerIntervalDuration
-            ? moment.duration(longRunningTimerIntervalDuration)
-            : undefined;
-        this.maximumShortTimerDuration = maximumShortTimerDuration
-            ? moment.duration(maximumShortTimerDuration)
-            : undefined;
-        this.defaultHttpAsyncRequestSleepTimeMillseconds = defaultHttpAsyncRequestSleepTimeMillseconds;
-        this.schemaVersion = schemaVersion;
-        this.input = input;
-        this.newGuidCounter = 0;
-    }
-
-    private input: unknown;
-    private readonly state: HistoryEvent[];
-    private newGuidCounter: number;
-    public customStatus: unknown;
-
-    /**
-     * The default time to wait between attempts when making HTTP polling requests
-     * This duration is used unless a different value (in seconds) is specified in the
-     * 'Retry-After' header of the 202 response.
-     */
-    private readonly defaultHttpAsyncRequestSleepTimeMillseconds?: number;
-
-    public readonly instanceId: string;
-    public readonly parentInstanceId: string | undefined;
-    public isReplaying: boolean;
-    public currentUtcDateTime: Date;
-
-    /**
-     * Gets the maximum duration for timers allowed by the
-     * underlying storage infrastructure
-     *
-     * This duration property is determined by the underlying storage
-     * solution and passed to the SDK from the extension.
-     */
-    private readonly maximumShortTimerDuration: moment.Duration | undefined;
-
-    /**
-     * A duration property which defines the duration of smaller
-     * timers to break long timers into, in case they are longer
-     * than the maximum supported duration
-     *
-     * This duration property is determined by the underlying
-     * storage solution and passed to the SDK from the extension.
-     */
-    private readonly longRunningTimerIntervalDuration: moment.Duration | undefined;
-
-    /**
-     * Gets the current schema version that this execution is
-     * utilizing, based on negotiation with the extension.
-     *
-     * Different schema versions can allow different behavior.
-     * For example, long timers are only supported in schema version >=3
-     */
-    private readonly schemaVersion: ReplaySchema;
-
-    /**
-     * @hidden
-     * This method informs the type-checker that an ITask[] can be treated as DFTask[].
-     * This is required for type-checking in the Task.all and Task.any method bodies while
-     * preventing the DFTask type from being exported to users.
-     * @param tasks
-     */
-    private isDFTaskArray(tasks: Task[]): tasks is DFTask[] {
-        return tasks.every((x) => x instanceof DFTask);
-    }
-
-    public Task = {
-        all: (tasks: Task[]): Task => {
-            if (this.isDFTaskArray(tasks)) {
-                const action = new WhenAllAction(tasks);
-                const task = new WhenAllTask(tasks, action);
-                return task;
-            }
-            throw Error(
-                "Task.all received a non-valid input. " +
-                    "This may occur if it somehow received a non-list input, " +
-                    "or if the input list's Tasks were corrupted. Please review your orchestrator code and/or file an issue."
-            );
-        },
-
-        any: (tasks: Task[]): Task => {
-            if (this.isDFTaskArray(tasks)) {
-                const action = new WhenAnyAction(tasks);
-                const task = new WhenAnyTask(tasks, action);
-                return task;
-            }
-            throw Error(
-                "Task.any received a non-valid input. " +
-                    "This may occur if it somehow received a non-list input, " +
-                    "or if the input list's Tasks were corrupted. Please review your orchestrator code and/or file an issue."
-            );
-        },
-    };
-
-    public callActivity(name: string, input?: unknown): Task {
-        const newAction = new CallActivityAction(name, input);
-        const task = new AtomicTask(false, newAction);
-        return task;
-    }
-
-    public callActivityWithRetry(name: string, retryOptions: RetryOptions, input?: unknown): Task {
-        const newAction = new CallActivityWithRetryAction(name, retryOptions, input);
-        const backingTask = new AtomicTask(false, newAction);
-        const task = new RetryableTask(backingTask, retryOptions, this.taskOrchestratorExecutor);
-        return task;
-    }
-
-    public callEntity(entityId: EntityId, operationName: string, operationInput?: unknown): Task {
-        const newAction = new CallEntityAction(entityId, operationName, operationInput);
-        const task = new AtomicTask(false, newAction);
-        return task;
-    }
-    public signalEntity(entityId: EntityId, operationName: string, operationInput?: unknown): void {
-        const action = new SignalEntityAction(entityId, operationName, operationInput);
-        this.taskOrchestratorExecutor.recordFireAndForgetAction(action);
-    }
-
-    public callSubOrchestrator(name: string, input?: unknown, instanceId?: string): Task {
-        if (!name) {
-            throw new Error(
-                "A sub-orchestration function name must be provided when attempting to create a suborchestration"
-            );
-        }
-
-        const newAction = new CallSubOrchestratorAction(name, instanceId, input);
-        const task = new AtomicTask(false, newAction);
-        return task;
-    }
-
-    public callSubOrchestratorWithRetry(
-        name: string,
-        retryOptions: RetryOptions,
-        input?: unknown,
-        instanceId?: string
-    ): Task {
-        if (!name) {
-            throw new Error(
-                "A sub-orchestration function name must be provided when attempting to create a suborchestration"
-            );
-        }
-
-        const newAction = new CallSubOrchestratorWithRetryAction(
-            name,
-            retryOptions,
-            input,
-            instanceId
-        );
-        const backingTask = new AtomicTask(false, newAction);
-        const task = new RetryableTask(backingTask, retryOptions, this.taskOrchestratorExecutor);
-        return task;
-    }
-
-    public callHttp(options: CallHttpOptions): Task {
-        let content = options.body;
-        if (content && typeof content !== "string") {
-            content = JSON.stringify(content);
-        }
-
-        let enablePolling = true;
-        if (options.enablePolling !== undefined) {
-            enablePolling = options.enablePolling;
-        } else if (options.asynchronousPatternEnabled !== undefined) {
-            enablePolling = options.asynchronousPatternEnabled;
-        }
-        const request = new DurableHttpRequest(
-            options.method,
-            options.url,
-            content as string,
-            options.headers,
-            options.tokenSource,
-            enablePolling
-        );
-        const newAction = new CallHttpAction(request);
-        if (this.schemaVersion >= ReplaySchema.V3 && request.asynchronousPatternEnabled) {
-            if (!this.defaultHttpAsyncRequestSleepTimeMillseconds) {
-                throw Error(
-                    "A framework-internal error was detected: replay schema version >= V3 is being used, " +
-                        "but `defaultHttpAsyncRequestSleepDuration` property is not defined. " +
-                        "This is likely an issue with the Durable Functions Extension. " +
-                        "Please report this bug here: https://github.com/Azure/azure-functions-durable-js/issues"
-                );
-            }
-            return new CallHttpWithPollingTask(
-                false,
-                newAction,
-                this,
-                this.taskOrchestratorExecutor,
-                this.defaultHttpAsyncRequestSleepTimeMillseconds
-            );
-        }
-        return new AtomicTask(false, newAction);
-    }
-
-    public continueAsNew(input: unknown): void {
-        const newAction = new ContinueAsNewAction(input);
-        this.taskOrchestratorExecutor.addToActions(newAction);
-        this.taskOrchestratorExecutor.willContinueAsNew = true;
-    }
-
-    public createTimer(fireAt: Date): TimerTask {
-        const timerAction = new CreateTimerAction(fireAt);
-        const durationUntilFire = moment.duration(moment(fireAt).diff(this.currentUtcDateTime));
-        if (this.schemaVersion >= ReplaySchema.V3) {
-            if (!this.maximumShortTimerDuration || !this.longRunningTimerIntervalDuration) {
-                throw Error(
-                    "A framework-internal error was detected: replay schema version >= V3 is being used, " +
-                        "but one or more of the properties `maximumShortTimerDuration` and `longRunningTimerIntervalDuration` are not defined. " +
-                        "This is likely an issue with the Durable Functions Extension. " +
-                        "Please report this bug here: https://github.com/Azure/azure-functions-durable-js/issues\n" +
-                        `maximumShortTimerDuration: ${this.maximumShortTimerDuration}\n` +
-                        `longRunningTimerIntervalDuration: ${this.longRunningTimerIntervalDuration}`
-                );
-            }
-
-            if (durationUntilFire > this.maximumShortTimerDuration) {
-                return new LongTimerTask(
-                    false,
-                    timerAction,
-                    this,
-                    this.taskOrchestratorExecutor,
-                    this.maximumShortTimerDuration.toISOString(),
-                    this.longRunningTimerIntervalDuration.toISOString()
-                );
-            }
-        }
-
-        return new DFTimerTask(false, timerAction);
-    }
-
-    public getInput<T>(): T {
-        return this.input as T;
-    }
-
-    public newGuid(instanceId: string): string {
-        const guidNameValue = `${instanceId}_${this.currentUtcDateTime.valueOf()}_${
-            this.newGuidCounter
-        }`;
-        this.newGuidCounter++;
-        return GuidManager.createDeterministicGuid(GuidManager.UrlNamespaceValue, guidNameValue);
-    }
-
-    public setCustomStatus(customStatusObject: unknown): void {
-        this.customStatus = customStatusObject;
-    }
-
-    public waitForExternalEvent(name: string): Task {
-        const newAction = new WaitForExternalEventAction(name, ExternalEventType.ExternalEvent);
-        const task = new AtomicTask(name, newAction);
-        return task;
-    }
-}
+import {
+    EntityId,
+    RetryOptions,
+    CallActivityAction,
+    CallActivityWithRetryAction,
+    CallEntityAction,
+    CallHttpAction,
+    CallSubOrchestratorAction,
+    CallSubOrchestratorWithRetryAction,
+    ContinueAsNewAction,
+    CreateTimerAction,
+    DurableHttpRequest,
+    ExternalEventType,
+    GuidManager,
+    HistoryEvent,
+    WaitForExternalEventAction,
+} from "../classes";
+import { TaskOrchestrationExecutor } from "./TaskOrchestrationExecutor";
+import { WhenAllAction } from "../actions/whenallaction";
+import { WhenAnyAction } from "../actions/whenanyaction";
+import {
+    WhenAllTask,
+    WhenAnyTask,
+    AtomicTask,
+    RetryableTask,
+    DFTimerTask,
+    DFTask,
+    LongTimerTask,
+    CallHttpWithPollingTask,
+} from "../task";
+import moment = require("moment");
+import { ReplaySchema } from "./ReplaySchema";
+import { CallHttpOptions, Task, TimerTask } from "durable-functions";
+import * as types from "durable-functions";
+import { SignalEntityAction } from "../actions/signalentityaction";
+
+/**
+ * Parameter data for orchestration bindings that can be used to schedule
+ * function-based activities.
+ */
+export class DurableOrchestrationContext implements types.DurableOrchestrationContext {
+    constructor(
+        state: HistoryEvent[],
+        instanceId: string,
+        currentUtcDateTime: Date,
+        isReplaying: boolean,
+        parentInstanceId: string | undefined,
+        longRunningTimerIntervalDuration: string | undefined,
+        maximumShortTimerDuration: string | undefined,
+        defaultHttpAsyncRequestSleepTimeMillseconds: number | undefined,
+        schemaVersion: ReplaySchema,
+        input: unknown,
+        private taskOrchestratorExecutor: TaskOrchestrationExecutor
+    ) {
+        this.state = state;
+        this.instanceId = instanceId;
+        this.isReplaying = isReplaying;
+        this.currentUtcDateTime = currentUtcDateTime;
+        this.parentInstanceId = parentInstanceId;
+        this.longRunningTimerIntervalDuration = longRunningTimerIntervalDuration
+            ? moment.duration(longRunningTimerIntervalDuration)
+            : undefined;
+        this.maximumShortTimerDuration = maximumShortTimerDuration
+            ? moment.duration(maximumShortTimerDuration)
+            : undefined;
+        this.defaultHttpAsyncRequestSleepTimeMillseconds = defaultHttpAsyncRequestSleepTimeMillseconds;
+        this.schemaVersion = schemaVersion;
+        this.input = input;
+        this.newGuidCounter = 0;
+    }
+
+    private input: unknown;
+    private readonly state: HistoryEvent[];
+    private newGuidCounter: number;
+    public customStatus: unknown;
+
+    /**
+     * The default time to wait between attempts when making HTTP polling requests
+     * This duration is used unless a different value (in seconds) is specified in the
+     * 'Retry-After' header of the 202 response.
+     */
+    private readonly defaultHttpAsyncRequestSleepTimeMillseconds?: number;
+
+    public readonly instanceId: string;
+    public readonly parentInstanceId: string | undefined;
+    public isReplaying: boolean;
+    public currentUtcDateTime: Date;
+
+    /**
+     * Gets the maximum duration for timers allowed by the
+     * underlying storage infrastructure
+     *
+     * This duration property is determined by the underlying storage
+     * solution and passed to the SDK from the extension.
+     */
+    private readonly maximumShortTimerDuration: moment.Duration | undefined;
+
+    /**
+     * A duration property which defines the duration of smaller
+     * timers to break long timers into, in case they are longer
+     * than the maximum supported duration
+     *
+     * This duration property is determined by the underlying
+     * storage solution and passed to the SDK from the extension.
+     */
+    private readonly longRunningTimerIntervalDuration: moment.Duration | undefined;
+
+    /**
+     * Gets the current schema version that this execution is
+     * utilizing, based on negotiation with the extension.
+     *
+     * Different schema versions can allow different behavior.
+     * For example, long timers are only supported in schema version >=3
+     */
+    private readonly schemaVersion: ReplaySchema;
+
+    /**
+     * @hidden
+     * This method informs the type-checker that an ITask[] can be treated as DFTask[].
+     * This is required for type-checking in the Task.all and Task.any method bodies while
+     * preventing the DFTask type from being exported to users.
+     * @param tasks
+     */
+    private isDFTaskArray(tasks: Task[]): tasks is DFTask[] {
+        return tasks.every((x) => x instanceof DFTask);
+    }
+
+    public Task = {
+        all: (tasks: Task[]): Task => {
+            if (this.isDFTaskArray(tasks)) {
+                const action = new WhenAllAction(tasks);
+                const task = new WhenAllTask(tasks, action);
+                return task;
+            }
+            throw Error(
+                "Task.all received a non-valid input. " +
+                    "This may occur if it somehow received a non-list input, " +
+                    "or if the input list's Tasks were corrupted. Please review your orchestrator code and/or file an issue."
+            );
+        },
+
+        any: (tasks: Task[]): Task => {
+            if (this.isDFTaskArray(tasks)) {
+                const action = new WhenAnyAction(tasks);
+                const task = new WhenAnyTask(tasks, action);
+                return task;
+            }
+            throw Error(
+                "Task.any received a non-valid input. " +
+                    "This may occur if it somehow received a non-list input, " +
+                    "or if the input list's Tasks were corrupted. Please review your orchestrator code and/or file an issue."
+            );
+        },
+    };
+
+    public callActivity(name: string, input?: unknown): Task {
+        const newAction = new CallActivityAction(name, input);
+        const task = new AtomicTask(false, newAction);
+        return task;
+    }
+
+    public callActivityWithRetry(name: string, retryOptions: RetryOptions, input?: unknown): Task {
+        const newAction = new CallActivityWithRetryAction(name, retryOptions, input);
+        const backingTask = new AtomicTask(false, newAction);
+        const task = new RetryableTask(backingTask, retryOptions, this.taskOrchestratorExecutor);
+        return task;
+    }
+
+    public callEntity(entityId: EntityId, operationName: string, operationInput?: unknown): Task {
+        const newAction = new CallEntityAction(entityId, operationName, operationInput);
+        const task = new AtomicTask(false, newAction);
+        return task;
+    }
+    public signalEntity(entityId: EntityId, operationName: string, operationInput?: unknown): void {
+        const action = new SignalEntityAction(entityId, operationName, operationInput);
+        this.taskOrchestratorExecutor.recordFireAndForgetAction(action);
+    }
+
+    public callSubOrchestrator(name: string, input?: unknown, instanceId?: string): Task {
+        if (!name) {
+            throw new Error(
+                "A sub-orchestration function name must be provided when attempting to create a suborchestration"
+            );
+        }
+
+        const newAction = new CallSubOrchestratorAction(name, instanceId, input);
+        const task = new AtomicTask(false, newAction);
+        return task;
+    }
+
+    public callSubOrchestratorWithRetry(
+        name: string,
+        retryOptions: RetryOptions,
+        input?: unknown,
+        instanceId?: string
+    ): Task {
+        if (!name) {
+            throw new Error(
+                "A sub-orchestration function name must be provided when attempting to create a suborchestration"
+            );
+        }
+
+        const newAction = new CallSubOrchestratorWithRetryAction(
+            name,
+            retryOptions,
+            input,
+            instanceId
+        );
+        const backingTask = new AtomicTask(false, newAction);
+        const task = new RetryableTask(backingTask, retryOptions, this.taskOrchestratorExecutor);
+        return task;
+    }
+
+    public callHttp(options: CallHttpOptions): Task {
+        let content = options.body;
+        if (content && typeof content !== "string") {
+            content = JSON.stringify(content);
+        }
+
+        let enablePolling = true;
+        if (options.enablePolling !== undefined) {
+            enablePolling = options.enablePolling;
+        } else if (options.asynchronousPatternEnabled !== undefined) {
+            enablePolling = options.asynchronousPatternEnabled;
+        }
+        const request = new DurableHttpRequest(
+            options.method,
+            options.url,
+            content as string,
+            options.headers,
+            options.tokenSource,
+            enablePolling
+        );
+        const newAction = new CallHttpAction(request);
+        if (this.schemaVersion >= ReplaySchema.V3 && request.asynchronousPatternEnabled) {
+            if (!this.defaultHttpAsyncRequestSleepTimeMillseconds) {
+                throw Error(
+                    "A framework-internal error was detected: replay schema version >= V3 is being used, " +
+                        "but `defaultHttpAsyncRequestSleepDuration` property is not defined. " +
+                        "This is likely an issue with the Durable Functions Extension. " +
+                        "Please report this bug here: https://github.com/Azure/azure-functions-durable-js/issues"
+                );
+            }
+            return new CallHttpWithPollingTask(
+                false,
+                newAction,
+                this,
+                this.taskOrchestratorExecutor,
+                this.defaultHttpAsyncRequestSleepTimeMillseconds
+            );
+        }
+        return new AtomicTask(false, newAction);
+    }
+
+    public continueAsNew(input: unknown): void {
+        const newAction = new ContinueAsNewAction(input);
+        this.taskOrchestratorExecutor.addToActions(newAction);
+        this.taskOrchestratorExecutor.willContinueAsNew = true;
+    }
+
+    public createTimer(fireAt: Date): TimerTask {
+        const timerAction = new CreateTimerAction(fireAt);
+        const durationUntilFire = moment.duration(moment(fireAt).diff(this.currentUtcDateTime));
+        if (this.schemaVersion >= ReplaySchema.V3) {
+            if (!this.maximumShortTimerDuration || !this.longRunningTimerIntervalDuration) {
+                throw Error(
+                    "A framework-internal error was detected: replay schema version >= V3 is being used, " +
+                        "but one or more of the properties `maximumShortTimerDuration` and `longRunningTimerIntervalDuration` are not defined. " +
+                        "This is likely an issue with the Durable Functions Extension. " +
+                        "Please report this bug here: https://github.com/Azure/azure-functions-durable-js/issues\n" +
+                        `maximumShortTimerDuration: ${this.maximumShortTimerDuration}\n` +
+                        `longRunningTimerIntervalDuration: ${this.longRunningTimerIntervalDuration}`
+                );
+            }
+
+            if (durationUntilFire > this.maximumShortTimerDuration) {
+                return new LongTimerTask(
+                    false,
+                    timerAction,
+                    this,
+                    this.taskOrchestratorExecutor,
+                    this.maximumShortTimerDuration.toISOString(),
+                    this.longRunningTimerIntervalDuration.toISOString()
+                );
+            }
+        }
+
+        return new DFTimerTask(false, timerAction);
+    }
+
+    public getInput<T>(): T {
+        return this.input as T;
+    }
+
+    public newGuid(instanceId: string): string {
+        const guidNameValue = `${instanceId}_${this.currentUtcDateTime.valueOf()}_${
+            this.newGuidCounter
+        }`;
+        this.newGuidCounter++;
+        return GuidManager.createDeterministicGuid(GuidManager.UrlNamespaceValue, guidNameValue);
+    }
+
+    public setCustomStatus(customStatusObject: unknown): void {
+        this.customStatus = customStatusObject;
+    }
+
+    public waitForExternalEvent(name: string): Task {
+        const newAction = new WaitForExternalEventAction(name, ExternalEventType.ExternalEvent);
+        const task = new AtomicTask(name, newAction);
+        return task;
+    }
+}
diff --git a/src/durableorchestrationstatus.ts b/src/orchestrations/DurableOrchestrationStatus.ts
similarity index 95%
rename from src/durableorchestrationstatus.ts
rename to src/orchestrations/DurableOrchestrationStatus.ts
index 1bf2b3b..1d07b40 100644
--- a/src/durableorchestrationstatus.ts
+++ b/src/orchestrations/DurableOrchestrationStatus.ts
@@ -1,62 +1,62 @@
-import { OrchestrationRuntimeStatus } from "./classes";
-import * as types from "durable-functions";
-
-export class DurableOrchestrationStatus implements types.DurableOrchestrationStatus {
-    public readonly name: string;
-    public readonly instanceId: string;
-    public readonly createdTime: Date;
-    public readonly lastUpdatedTime: Date;
-    public readonly input: unknown;
-    public readonly output: unknown;
-    public readonly runtimeStatus: OrchestrationRuntimeStatus;
-    public readonly customStatus?: unknown;
-    public readonly history?: Array<unknown>;
-
-    /** @hidden */
-    constructor(init: unknown) {
-        if (!this.isDurableOrchestrationStatusInit(init)) {
-            throw new TypeError(
-                `Failed to construct a DurableOrchestrationStatus object because the initializer had invalid types or missing fields. Initializer received: ${JSON.stringify(
-                    init
-                )}`
-            );
-        }
-
-        this.name = init.name;
-        this.instanceId = init.instanceId;
-        this.createdTime = new Date(init.createdTime);
-        this.lastUpdatedTime = new Date(init.lastUpdatedTime);
-        this.input = init.input;
-        this.output = init.output;
-        this.runtimeStatus = init.runtimeStatus as OrchestrationRuntimeStatus;
-        this.customStatus = init.customStatus;
-        this.history = init.history;
-    }
-
-    private isDurableOrchestrationStatusInit(obj: unknown): obj is DurableOrchestrationStatusInit {
-        const objAsInit = obj as DurableOrchestrationStatusInit;
-        return (
-            objAsInit !== undefined &&
-            typeof objAsInit.name === "string" &&
-            typeof objAsInit.instanceId === "string" &&
-            (typeof objAsInit.createdTime === "string" || objAsInit.createdTime instanceof Date) &&
-            (typeof objAsInit.lastUpdatedTime === "string" ||
-                objAsInit.lastUpdatedTime instanceof Date) &&
-            objAsInit.input !== undefined &&
-            objAsInit.output !== undefined &&
-            typeof objAsInit.runtimeStatus === "string"
-        );
-    }
-}
-
-interface DurableOrchestrationStatusInit {
-    name: string;
-    instanceId: string;
-    createdTime: string | Date;
-    lastUpdatedTime: string | Date;
-    input: unknown;
-    output: unknown;
-    runtimeStatus: string;
-    customStatus?: unknown;
-    history?: Array<unknown>;
-}
+import { OrchestrationRuntimeStatus } from "../classes";
+import * as types from "durable-functions";
+
+export class DurableOrchestrationStatus implements types.DurableOrchestrationStatus {
+    public readonly name: string;
+    public readonly instanceId: string;
+    public readonly createdTime: Date;
+    public readonly lastUpdatedTime: Date;
+    public readonly input: unknown;
+    public readonly output: unknown;
+    public readonly runtimeStatus: OrchestrationRuntimeStatus;
+    public readonly customStatus?: unknown;
+    public readonly history?: Array<unknown>;
+
+    /** @hidden */
+    constructor(init: unknown) {
+        if (!this.isDurableOrchestrationStatusInit(init)) {
+            throw new TypeError(
+                `Failed to construct a DurableOrchestrationStatus object because the initializer had invalid types or missing fields. Initializer received: ${JSON.stringify(
+                    init
+                )}`
+            );
+        }
+
+        this.name = init.name;
+        this.instanceId = init.instanceId;
+        this.createdTime = new Date(init.createdTime);
+        this.lastUpdatedTime = new Date(init.lastUpdatedTime);
+        this.input = init.input;
+        this.output = init.output;
+        this.runtimeStatus = init.runtimeStatus as OrchestrationRuntimeStatus;
+        this.customStatus = init.customStatus;
+        this.history = init.history;
+    }
+
+    private isDurableOrchestrationStatusInit(obj: unknown): obj is DurableOrchestrationStatusInit {
+        const objAsInit = obj as DurableOrchestrationStatusInit;
+        return (
+            objAsInit !== undefined &&
+            typeof objAsInit.name === "string" &&
+            typeof objAsInit.instanceId === "string" &&
+            (typeof objAsInit.createdTime === "string" || objAsInit.createdTime instanceof Date) &&
+            (typeof objAsInit.lastUpdatedTime === "string" ||
+                objAsInit.lastUpdatedTime instanceof Date) &&
+            objAsInit.input !== undefined &&
+            objAsInit.output !== undefined &&
+            typeof objAsInit.runtimeStatus === "string"
+        );
+    }
+}
+
+interface DurableOrchestrationStatusInit {
+    name: string;
+    instanceId: string;
+    createdTime: string | Date;
+    lastUpdatedTime: string | Date;
+    input: unknown;
+    output: unknown;
+    runtimeStatus: string;
+    customStatus?: unknown;
+    history?: Array<unknown>;
+}
diff --git a/src/iorchestratorstate.ts b/src/orchestrations/IOrchestratorState.ts
similarity index 68%
rename from src/iorchestratorstate.ts
rename to src/orchestrations/IOrchestratorState.ts
index ff78bb6..e82c597 100644
--- a/src/iorchestratorstate.ts
+++ b/src/orchestrations/IOrchestratorState.ts
@@ -1,12 +1,12 @@
-import { IAction } from "./classes";
-import { ReplaySchema } from "./replaySchema";
-
-/** @hidden */
-export interface IOrchestratorState {
-    isDone: boolean;
-    actions: IAction[][];
-    output: unknown;
-    error?: string;
-    customStatus?: unknown;
-    schemaVersion: ReplaySchema;
-}
+import { IAction } from "../classes";
+import { ReplaySchema } from "./ReplaySchema";
+
+/** @hidden */
+export interface IOrchestratorState {
+    isDone: boolean;
+    actions: IAction[][];
+    output: unknown;
+    error?: string;
+    customStatus?: unknown;
+    schemaVersion: ReplaySchema;
+}
diff --git a/src/orchestrationruntimestatus.ts b/src/orchestrations/OrchestrationRuntimeStatus.ts
similarity index 100%
rename from src/orchestrationruntimestatus.ts
rename to src/orchestrations/OrchestrationRuntimeStatus.ts
diff --git a/src/orchestrator.ts b/src/orchestrations/Orchestrator.ts
similarity index 91%
rename from src/orchestrator.ts
rename to src/orchestrations/Orchestrator.ts
index 3ff4172..0f29bb1 100644
--- a/src/orchestrator.ts
+++ b/src/orchestrations/Orchestrator.ts
@@ -1,104 +1,104 @@
-import {
-    DurableOrchestrationBindingInfo,
-    HistoryEvent,
-    HistoryEventType,
-    OrchestratorState,
-    Utils,
-} from "./classes";
-import { DurableOrchestrationContext } from "./durableorchestrationcontext";
-import { TaskOrchestrationExecutor } from "./taskorchestrationexecutor";
-import { LatestReplaySchema, ReplaySchema } from "./replaySchema";
-import { DurableOrchestrationBindingInfoReqFields } from "./durableorchestrationbindinginfo";
-import { OrchestrationContext } from "durable-functions";
-
-/** @hidden */
-export class Orchestrator {
-    private currentUtcDateTime: Date;
-    private taskOrchestrationExecutor: TaskOrchestrationExecutor;
-
-    // Our current testing infrastructure depends on static unit testing helpers that don't play
-    // nicely with Orchestrator data being initialized in the constructor: state may preserved
-    // across unit test runs.
-    // As a result, we are currently constrained to initialize all of our data in the `handle` method.
-    constructor(public fn: (context: OrchestrationContext) => IterableIterator<unknown>) {}
-
-    public listen(): (
-        orchestrationTrigger: DurableOrchestrationBindingInfo,
-        context: OrchestrationContext
-    ) => Promise<OrchestratorState> {
-        return this.handle.bind(this);
-    }
-
-    private async handle(
-        orchestrationTrigger: DurableOrchestrationBindingInfo,
-        context: OrchestrationContext
-    ): Promise<OrchestratorState> {
-        this.taskOrchestrationExecutor = new TaskOrchestrationExecutor();
-        const orchestrationBinding = Utils.getInstancesOf<DurableOrchestrationBindingInfo>(
-            { trigger: orchestrationTrigger },
-            new DurableOrchestrationBindingInfoReqFields() as DurableOrchestrationBindingInfo
-        )[0];
-
-        if (!orchestrationBinding) {
-            throw new Error("Could not find an orchestrationClient binding on context.");
-        }
-
-        const state: HistoryEvent[] = orchestrationBinding.history;
-        const input = orchestrationBinding.input;
-        const instanceId: string = orchestrationBinding.instanceId;
-        // const contextLocks: EntityId[] = orchestrationBinding.contextLocks;
-
-        // The upper schema version corresponds to the maximum OOProc protocol version supported by the extension,
-        // we use it to determine the format of the SDK's output
-        let upperSchemaVersion: ReplaySchema;
-
-        // represents the upper schema version suported by the extension
-        const extensionUpperSchemaVersion: ReplaySchema = orchestrationBinding.upperSchemaVersionNew
-            ? orchestrationBinding.upperSchemaVersionNew
-            : orchestrationBinding.upperSchemaVersion;
-
-        // It is assumed that the extension supports all schemas in range [0, upperSchemaVersion].
-        // Similarly, it is assumed that this SDK supports all schemas in range [0, LatestReplaySchema].
-        // Therefore, if the extension supplies a upperSchemaVersion included in our ReplaySchema enum, we use it.
-        // But if the extension supplies an upperSchemaVersion not included in our ReplaySchema enum, then we
-        // assume that upperSchemaVersion is larger than LatestReplaySchema and therefore use LatestReplaySchema instead.
-        if (Object.values(ReplaySchema).includes(extensionUpperSchemaVersion)) {
-            upperSchemaVersion = extensionUpperSchemaVersion;
-        } else {
-            upperSchemaVersion = LatestReplaySchema;
-        }
-
-        // Initialize currentUtcDateTime
-        const decisionStartedEvent: HistoryEvent = Utils.ensureNonNull(
-            state.find((e) => e.EventType === HistoryEventType.OrchestratorStarted),
-            "The orchestrator can not execute without an OrchestratorStarted event."
-        );
-        this.currentUtcDateTime = new Date(decisionStartedEvent.Timestamp);
-
-        // Only create durable orchestration context when `context.df` has not been defined
-        // if it has been defined, then we must be in some unit-testing scenario
-        if (context.df === undefined) {
-            // Create durable orchestration context
-            context.df = new DurableOrchestrationContext(
-                state,
-                instanceId,
-                this.currentUtcDateTime,
-                orchestrationBinding.isReplaying,
-                orchestrationBinding.parentInstanceId,
-                orchestrationBinding.longRunningTimerIntervalDuration,
-                orchestrationBinding.maximumShortTimerDuration,
-                orchestrationBinding.defaultHttpAsyncRequestSleepTimeMillseconds,
-                upperSchemaVersion,
-                input,
-                this.taskOrchestrationExecutor
-            );
-        }
-
-        return await this.taskOrchestrationExecutor.execute(
-            context,
-            state,
-            upperSchemaVersion,
-            this.fn
-        );
-    }
-}
+import {
+    DurableOrchestrationBindingInfo,
+    HistoryEvent,
+    HistoryEventType,
+    OrchestratorState,
+    Utils,
+} from "../classes";
+import { DurableOrchestrationContext } from "./DurableOrchestrationContext";
+import { TaskOrchestrationExecutor } from "./TaskOrchestrationExecutor";
+import { LatestReplaySchema, ReplaySchema } from "./ReplaySchema";
+import { DurableOrchestrationBindingInfoReqFields } from "./DurableOrchestrationBindingInfo";
+import { OrchestrationContext } from "durable-functions";
+
+/** @hidden */
+export class Orchestrator {
+    private currentUtcDateTime: Date;
+    private taskOrchestrationExecutor: TaskOrchestrationExecutor;
+
+    // Our current testing infrastructure depends on static unit testing helpers that don't play
+    // nicely with Orchestrator data being initialized in the constructor: state may preserved
+    // across unit test runs.
+    // As a result, we are currently constrained to initialize all of our data in the `handle` method.
+    constructor(public fn: (context: OrchestrationContext) => IterableIterator<unknown>) {}
+
+    public listen(): (
+        orchestrationTrigger: DurableOrchestrationBindingInfo,
+        context: OrchestrationContext
+    ) => Promise<OrchestratorState> {
+        return this.handle.bind(this);
+    }
+
+    private async handle(
+        orchestrationTrigger: DurableOrchestrationBindingInfo,
+        context: OrchestrationContext
+    ): Promise<OrchestratorState> {
+        this.taskOrchestrationExecutor = new TaskOrchestrationExecutor();
+        const orchestrationBinding = Utils.getInstancesOf<DurableOrchestrationBindingInfo>(
+            { trigger: orchestrationTrigger },
+            new DurableOrchestrationBindingInfoReqFields() as DurableOrchestrationBindingInfo
+        )[0];
+
+        if (!orchestrationBinding) {
+            throw new Error("Could not find an orchestrationClient binding on context.");
+        }
+
+        const state: HistoryEvent[] = orchestrationBinding.history;
+        const input = orchestrationBinding.input;
+        const instanceId: string = orchestrationBinding.instanceId;
+        // const contextLocks: EntityId[] = orchestrationBinding.contextLocks;
+
+        // The upper schema version corresponds to the maximum OOProc protocol version supported by the extension,
+        // we use it to determine the format of the SDK's output
+        let upperSchemaVersion: ReplaySchema;
+
+        // represents the upper schema version suported by the extension
+        const extensionUpperSchemaVersion: ReplaySchema = orchestrationBinding.upperSchemaVersionNew
+            ? orchestrationBinding.upperSchemaVersionNew
+            : orchestrationBinding.upperSchemaVersion;
+
+        // It is assumed that the extension supports all schemas in range [0, upperSchemaVersion].
+        // Similarly, it is assumed that this SDK supports all schemas in range [0, LatestReplaySchema].
+        // Therefore, if the extension supplies a upperSchemaVersion included in our ReplaySchema enum, we use it.
+        // But if the extension supplies an upperSchemaVersion not included in our ReplaySchema enum, then we
+        // assume that upperSchemaVersion is larger than LatestReplaySchema and therefore use LatestReplaySchema instead.
+        if (Object.values(ReplaySchema).includes(extensionUpperSchemaVersion)) {
+            upperSchemaVersion = extensionUpperSchemaVersion;
+        } else {
+            upperSchemaVersion = LatestReplaySchema;
+        }
+
+        // Initialize currentUtcDateTime
+        const decisionStartedEvent: HistoryEvent = Utils.ensureNonNull(
+            state.find((e) => e.EventType === HistoryEventType.OrchestratorStarted),
+            "The orchestrator can not execute without an OrchestratorStarted event."
+        );
+        this.currentUtcDateTime = new Date(decisionStartedEvent.Timestamp);
+
+        // Only create durable orchestration context when `context.df` has not been defined
+        // if it has been defined, then we must be in some unit-testing scenario
+        if (context.df === undefined) {
+            // Create durable orchestration context
+            context.df = new DurableOrchestrationContext(
+                state,
+                instanceId,
+                this.currentUtcDateTime,
+                orchestrationBinding.isReplaying,
+                orchestrationBinding.parentInstanceId,
+                orchestrationBinding.longRunningTimerIntervalDuration,
+                orchestrationBinding.maximumShortTimerDuration,
+                orchestrationBinding.defaultHttpAsyncRequestSleepTimeMillseconds,
+                upperSchemaVersion,
+                input,
+                this.taskOrchestrationExecutor
+            );
+        }
+
+        return await this.taskOrchestrationExecutor.execute(
+            context,
+            state,
+            upperSchemaVersion,
+            this.fn
+        );
+    }
+}
diff --git a/src/orchestratorstate.ts b/src/orchestrations/OrchestratorState.ts
similarity index 92%
rename from src/orchestratorstate.ts
rename to src/orchestrations/OrchestratorState.ts
index 24b6516..e1e89ca 100644
--- a/src/orchestratorstate.ts
+++ b/src/orchestrations/OrchestratorState.ts
@@ -1,93 +1,93 @@
-import { WhenAllAction } from "./actions/whenallaction";
-import { WhenAnyAction } from "./actions/whenanyaction";
-import { IAction, IOrchestratorState } from "./classes";
-import { ReplaySchema } from "./replaySchema";
-
-/** @hidden */
-export class OrchestratorState implements IOrchestratorState {
-    public readonly isDone: boolean;
-    public readonly actions: IAction[][];
-    public readonly output: unknown;
-    public readonly error?: string;
-    public readonly customStatus?: unknown;
-    public readonly schemaVersion: ReplaySchema;
-
-    /**
-     * @hidden
-     *
-     * It flattens an array of actions.
-     * By flatten, we mean that, in the presence of a compound action (WhenAll/WhenAny),
-     * we recursively extract all of its sub-actions into a flat sequence which is then
-     * put in-place of the original compound action.
-     *
-     * For example, given the array:
-     *  [Activity, Activity, WhenAll(Activity, WhenAny(ExternalEvent, Activity))]
-     * We obtain:
-     *  [Activity, Activity, Activity, ExternalEvent, Activity]
-     *
-     * This is helpful in translating the representation of user actions in
-     * the DF extension replay protocol V2 to V1.
-     *
-     * @param actions
-     *  The array of actions to flatten
-     * @returns
-     *  The flattened array of actions.
-     */
-    private flattenCompoundActions(actions: IAction[]): IAction[] {
-        const flatActions: IAction[] = [];
-        for (const action of actions) {
-            // Given any compound action
-            if (action instanceof WhenAllAction || action instanceof WhenAnyAction) {
-                // We obtain its inner actions as a flat array
-                const innerActionArr = this.flattenCompoundActions(action.compoundActions);
-                // we concatenate the inner actions to the flat array we're building
-                flatActions.push(...innerActionArr);
-            } else {
-                // The action wasn't compound, so it's left intact
-                flatActions.push(action);
-            }
-        }
-        return flatActions;
-    }
-
-    // literal actions is used exclusively to facilitate testing. If true, the action representation is to be left intact
-    constructor(options: IOrchestratorState, _literalActions = false) {
-        this.isDone = options.isDone;
-        this.actions = options.actions;
-        this.output = options.output;
-        this.schemaVersion = options.schemaVersion;
-
-        if (options.error) {
-            this.error = options.error;
-        }
-
-        if (options.customStatus) {
-            this.customStatus = options.customStatus;
-        }
-        // Under replay protocol V1, compound actions are treated as lists of actions and
-        // atomic actions are represented as a 1-element lists.
-        // For example, given actions list: [Activity, WhenAny(ExternalEvent, WhenAll(Timer, Activity))]
-        // The V1 protocol expects: [[Activity], [ExternalEvent, Timer, Activity]]
-        if (options.schemaVersion === ReplaySchema.V1 && !_literalActions) {
-            // We need to transform our V2 action representation to V1.
-            // In V2, actions are represented as 2D arrays (for legacy reasons) with a singular element: an array of actions.
-            const actions = this.actions[0];
-            const newActions: IAction[][] = [];
-            // guard against empty array, meaning no user actions were scheduled
-            if (actions !== undefined) {
-                for (const action of actions) {
-                    // Each action is represented as an array in V1
-                    const newEntry: IAction[] = [];
-                    if (action instanceof WhenAllAction || action instanceof WhenAnyAction) {
-                        const innerActionArr = this.flattenCompoundActions(action.compoundActions);
-                        newEntry.push(...innerActionArr);
-                    } else {
-                        newEntry.push(action);
-                    }
-                    newActions.push(newEntry);
-                }
-                this.actions = newActions;
-            }
-        }
-    }
-}
+import { WhenAllAction } from "../actions/whenallaction";
+import { WhenAnyAction } from "../actions/whenanyaction";
+import { IAction, IOrchestratorState } from "../classes";
+import { ReplaySchema } from "./ReplaySchema";
+
+/** @hidden */
+export class OrchestratorState implements IOrchestratorState {
+    public readonly isDone: boolean;
+    public readonly actions: IAction[][];
+    public readonly output: unknown;
+    public readonly error?: string;
+    public readonly customStatus?: unknown;
+    public readonly schemaVersion: ReplaySchema;
+
+    /**
+     * @hidden
+     *
+     * It flattens an array of actions.
+     * By flatten, we mean that, in the presence of a compound action (WhenAll/WhenAny),
+     * we recursively extract all of its sub-actions into a flat sequence which is then
+     * put in-place of the original compound action.
+     *
+     * For example, given the array:
+     *  [Activity, Activity, WhenAll(Activity, WhenAny(ExternalEvent, Activity))]
+     * We obtain:
+     *  [Activity, Activity, Activity, ExternalEvent, Activity]
+     *
+     * This is helpful in translating the representation of user actions in
+     * the DF extension replay protocol V2 to V1.
+     *
+     * @param actions
+     *  The array of actions to flatten
+     * @returns
+     *  The flattened array of actions.
+     */
+    private flattenCompoundActions(actions: IAction[]): IAction[] {
+        const flatActions: IAction[] = [];
+        for (const action of actions) {
+            // Given any compound action
+            if (action instanceof WhenAllAction || action instanceof WhenAnyAction) {
+                // We obtain its inner actions as a flat array
+                const innerActionArr = this.flattenCompoundActions(action.compoundActions);
+                // we concatenate the inner actions to the flat array we're building
+                flatActions.push(...innerActionArr);
+            } else {
+                // The action wasn't compound, so it's left intact
+                flatActions.push(action);
+            }
+        }
+        return flatActions;
+    }
+
+    // literal actions is used exclusively to facilitate testing. If true, the action representation is to be left intact
+    constructor(options: IOrchestratorState, _literalActions = false) {
+        this.isDone = options.isDone;
+        this.actions = options.actions;
+        this.output = options.output;
+        this.schemaVersion = options.schemaVersion;
+
+        if (options.error) {
+            this.error = options.error;
+        }
+
+        if (options.customStatus) {
+            this.customStatus = options.customStatus;
+        }
+        // Under replay protocol V1, compound actions are treated as lists of actions and
+        // atomic actions are represented as a 1-element lists.
+        // For example, given actions list: [Activity, WhenAny(ExternalEvent, WhenAll(Timer, Activity))]
+        // The V1 protocol expects: [[Activity], [ExternalEvent, Timer, Activity]]
+        if (options.schemaVersion === ReplaySchema.V1 && !_literalActions) {
+            // We need to transform our V2 action representation to V1.
+            // In V2, actions are represented as 2D arrays (for legacy reasons) with a singular element: an array of actions.
+            const actions = this.actions[0];
+            const newActions: IAction[][] = [];
+            // guard against empty array, meaning no user actions were scheduled
+            if (actions !== undefined) {
+                for (const action of actions) {
+                    // Each action is represented as an array in V1
+                    const newEntry: IAction[] = [];
+                    if (action instanceof WhenAllAction || action instanceof WhenAnyAction) {
+                        const innerActionArr = this.flattenCompoundActions(action.compoundActions);
+                        newEntry.push(...innerActionArr);
+                    } else {
+                        newEntry.push(action);
+                    }
+                    newActions.push(newEntry);
+                }
+                this.actions = newActions;
+            }
+        }
+    }
+}
diff --git a/src/replaySchema.ts b/src/orchestrations/ReplaySchema.ts
similarity index 100%
rename from src/replaySchema.ts
rename to src/orchestrations/ReplaySchema.ts
diff --git a/src/taskorchestrationexecutor.ts b/src/orchestrations/TaskOrchestrationExecutor.ts
similarity index 98%
rename from src/taskorchestrationexecutor.ts
rename to src/orchestrations/TaskOrchestrationExecutor.ts
index 37da832..63c25ca 100644
--- a/src/taskorchestrationexecutor.ts
+++ b/src/orchestrations/TaskOrchestrationExecutor.ts
@@ -10,12 +10,12 @@ import {
     SubOrchestrationInstanceCompletedEvent,
     TaskCompletedEvent,
     WaitForExternalEventAction,
-} from "./classes";
-import { OrchestrationFailureError } from "./error/OrchestrationFailureError";
-import { OrchestratorState } from "./orchestratorstate";
-import { TaskBase, NoOpTask, DFTask, CompoundTask, TaskState } from "./task";
-import { ReplaySchema } from "./replaySchema";
-import { Utils } from "./util/Utils";
+} from "../classes";
+import { OrchestrationFailureError } from "../error/OrchestrationFailureError";
+import { OrchestratorState } from "./OrchestratorState";
+import { TaskBase, NoOpTask, DFTask, CompoundTask, TaskState } from "../task";
+import { ReplaySchema } from "./ReplaySchema";
+import { Utils } from "../util/Utils";
 import { DurableOrchestrationContext, OrchestrationContext } from "durable-functions";
 
 /**
diff --git a/src/shim.ts b/src/shim.ts
deleted file mode 100644
index 70ff5d3..0000000
--- a/src/shim.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import {
-    app as azFuncApp,
-    FunctionHandler,
-    input as azFuncInput,
-    trigger as azFuncTrigger,
-} from "@azure/functions";
-import {
-    ActivityOptions,
-    EntityHandler,
-    DurableClientInput,
-    OrchestrationHandler,
-    ActivityTrigger,
-    OrchestrationTrigger,
-    EntityTrigger,
-    OrchestrationOptions,
-    EntityOptions,
-    OrchestrationContext,
-    EntityContext,
-} from "durable-functions";
-import { Entity, EntityState, Orchestrator } from "./classes";
-import { DurableEntityBindingInfo } from "./entities/DurableEntityBindingInfo";
-import { OrchestratorState } from "./orchestratorstate";
-import { DurableOrchestrationInput } from "./util/testingUtils";
-
-type EntityFunction<T> = FunctionHandler &
-    ((entityTrigger: DurableEntityBindingInfo, context: EntityContext<T>) => Promise<EntityState>);
-
-type OrchestrationFunction = FunctionHandler &
-    ((
-        orchestrationTrigger: DurableOrchestrationInput,
-        context: OrchestrationContext
-    ) => Promise<OrchestratorState>);
-
-/**
- * Enables a generator function to act as an orchestrator function.
- *
- * @param fn the generator function that should act as an orchestrator
- */
-export function createOrchestrator(fn: OrchestrationHandler): OrchestrationFunction {
-    const listener = new Orchestrator(fn).listen();
-
-    return async (
-        orchestrationTrigger: DurableOrchestrationInput,
-        context: OrchestrationContext
-    ): Promise<OrchestratorState> => {
-        return await listener(orchestrationTrigger, context);
-    };
-}
-
-/**
- * Enables an entity handler function to act as a Durable Entity Azure Function.
- *
- * @param fn the handler function that should act as a durable entity
- */
-export function createEntityFunction<T = unknown>(fn: EntityHandler<T>): EntityFunction<T> {
-    const listener = new Entity<T>(fn).listen();
-
-    return async (
-        entityTrigger: DurableEntityBindingInfo,
-        context: EntityContext<T>
-    ): Promise<EntityState> => {
-        return await listener(entityTrigger, context);
-    };
-}
-
-export namespace app {
-    export function orchestration(
-        functionName: string,
-        handlerOrOptions: OrchestrationHandler | OrchestrationOptions
-    ): void {
-        const options: OrchestrationOptions =
-            typeof handlerOrOptions === "function"
-                ? { handler: handlerOrOptions }
-                : handlerOrOptions;
-
-        azFuncApp.generic(functionName, {
-            trigger: trigger.orchestration(),
-            ...options,
-            handler: createOrchestrator(options.handler),
-        });
-    }
-
-    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): void {
-        azFuncApp.generic(functionName, {
-            trigger: trigger.activity(),
-            ...options,
-        });
-    }
-}
-
-export namespace trigger {
-    export function activity(): ActivityTrigger {
-        return azFuncTrigger.generic({
-            type: "activityTrigger",
-        }) as ActivityTrigger;
-    }
-
-    export function orchestration(): OrchestrationTrigger {
-        return azFuncTrigger.generic({
-            type: "orchestrationTrigger",
-        }) as OrchestrationTrigger;
-    }
-
-    export function entity(): EntityTrigger {
-        return azFuncTrigger.generic({
-            type: "entityTrigger",
-        }) as EntityTrigger;
-    }
-}
-
-export namespace input {
-    export function durableClient(): DurableClientInput {
-        return azFuncInput.generic({
-            type: "durableClient",
-        }) as DurableClientInput;
-    }
-}
diff --git a/src/task/CallHttpWithPollingTask.ts b/src/task/CallHttpWithPollingTask.ts
index be53d90..b91e1fb 100644
--- a/src/task/CallHttpWithPollingTask.ts
+++ b/src/task/CallHttpWithPollingTask.ts
@@ -1,8 +1,8 @@
 import { CallHttpAction, DurableHttpResponse } from "../classes";
 import { CompoundTask } from "./CompoundTask";
 import { AtomicTask, TaskBase, TaskID, TaskState } from ".";
-import { DurableOrchestrationContext } from "../durableorchestrationcontext";
-import { TaskOrchestrationExecutor } from "src/taskorchestrationexecutor";
+import { DurableOrchestrationContext } from "../orchestrations/DurableOrchestrationContext";
+import { TaskOrchestrationExecutor } from "src/orchestrations/TaskOrchestrationExecutor";
 import moment = require("moment");
 
 /**
diff --git a/src/task/LongTimerTask.ts b/src/task/LongTimerTask.ts
index 2f9780c..d32249f 100644
--- a/src/task/LongTimerTask.ts
+++ b/src/task/LongTimerTask.ts
@@ -2,7 +2,7 @@ import { DurableOrchestrationContext, TimerTask } from "durable-functions";
 import { WhenAllTask } from "./WhenAllTask";
 import moment = require("moment");
 import { CreateTimerAction } from "../classes";
-import { TaskOrchestrationExecutor } from "../taskorchestrationexecutor";
+import { TaskOrchestrationExecutor } from "../orchestrations/TaskOrchestrationExecutor";
 import { TaskID } from ".";
 import { DFTimerTask } from "./DFTimerTask";
 
diff --git a/src/task/RetryableTask.ts b/src/task/RetryableTask.ts
index ce04912..ab3b89a 100644
--- a/src/task/RetryableTask.ts
+++ b/src/task/RetryableTask.ts
@@ -1,5 +1,5 @@
 import { RetryOptions } from "durable-functions";
-import { TaskOrchestrationExecutor } from "../taskorchestrationexecutor";
+import { TaskOrchestrationExecutor } from "../orchestrations/TaskOrchestrationExecutor";
 import { TaskState } from ".";
 import { DFTask } from "./DFTask";
 import { NoOpTask } from "./NoOpTask";


Test patch:
diff --git a/src/util/testingUtils.ts b/src/util/testingUtils.ts
index e2f920f..9d00790 100644
--- a/src/util/testingUtils.ts
+++ b/src/util/testingUtils.ts
@@ -16,7 +16,7 @@ import {
     OrchestratorStartedEvent,
     OrchestratorState,
 } from "../classes";
-import { ReplaySchema } from "../replaySchema";
+import { ReplaySchema } from "../orchestrations/ReplaySchema";
 import * as uuidv1 from "uuid/v1";
 import {
     DurableEntityContext,
diff --git a/test/integration/orchestrator-spec.ts b/test/integration/orchestrator-spec.ts
index 7e421c7..112c201 100644
--- a/test/integration/orchestrator-spec.ts
+++ b/test/integration/orchestrator-spec.ts
@@ -26,7 +26,7 @@ import {
     WaitForExternalEventAction,
 } from "../../src/classes";
 import { OrchestrationFailureError } from "../../src/error/OrchestrationFailureError";
-import { ReplaySchema } from "../../src/replaySchema";
+import { ReplaySchema } from "../../src/orchestrations/ReplaySchema";
 import { DurableOrchestrationInput } from "../../src/util/testingUtils";
 import { TestHistories } from "../testobjects/testhistories";
 import { TestOrchestrations } from "../testobjects/TestOrchestrations";