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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 0 additions & 33 deletions bun.lock

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

1 change: 1 addition & 0 deletions packages/sideffect/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type {
WorkflowContext,
WorkflowDefinition,
WorkflowEvent,
WorkflowInput,
WorkflowLayer,
WorkflowRun,
} from "./types.ts";
23 changes: 17 additions & 6 deletions packages/sideffect/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,13 @@ export type WorkflowRun<Payload, Result, Env = DefaultCloudflareEnv> = (
) => MaybeEffect<Result>;

/** Sideffect workflow definition created by `Workflow.make(...)`. */
export interface WorkflowDefinition<Payload, Env = DefaultCloudflareEnv> {
export interface WorkflowDefinition<Payload, Env = DefaultCloudflareEnv, Input = Payload> {
/** Runtime tag used by Sideffect to validate workflow definitions. */
readonly _tag: "WorkflowDefinition";
/** Cloudflare Workflow name. */
readonly name: string;
/** Schema used to decode incoming workflow event payloads. */
readonly payloadSchema: Schema.Schema<Payload>;
readonly payloadSchema: Schema.Codec<Payload, Input, never, unknown>;
/**
* Binds a workflow definition to its implementation.
*
Expand All @@ -198,21 +198,32 @@ export interface WorkflowDefinition<Payload, Env = DefaultCloudflareEnv> {
*/
toLayer<NextResult>(
run: WorkflowRun<Payload, NextResult, Env>,
): WorkflowLayer<Payload, NextResult, Env>;
): WorkflowLayer<Payload, NextResult, Env, Input>;
}

/** Runnable Sideffect workflow layer. */
export interface WorkflowLayer<Payload, Result = unknown, Env = DefaultCloudflareEnv> {
export interface WorkflowLayer<
Payload,
Result = unknown,
Env = DefaultCloudflareEnv,
Input = Payload,
> {
/** Runtime tag used by Sideffect to validate workflow layers. */
readonly _tag: "WorkflowLayer";
/** Workflow definition and payload schema. */
readonly workflow: WorkflowDefinition<Payload, Env>;
readonly workflow: WorkflowDefinition<Payload, Env, Input>;
/** Workflow implementation. */
readonly run: WorkflowRun<Payload, Result, Env>;
}

/** Extracts the encoded input accepted by a Sideffect workflow binding. */
export type WorkflowInput<Layer> =
Layer extends WorkflowLayer<infer _Payload, infer _Result, infer _Env, infer Input>
? Input
: never;

/** @internal Any Sideffect workflow layer. */
export type WorkflowLayerAny = WorkflowLayer<any, any, any>;
export type WorkflowLayerAny = WorkflowLayer<any, any, any, any>;

/** @internal Named workflow layers used to generate Cloudflare entrypoints. */
export type WorkflowLayerEntries = Record<string, WorkflowLayerAny>;
Expand Down
7 changes: 3 additions & 4 deletions packages/sideffect/src/vite/generated-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,23 +112,22 @@ function generateWorkflowEnvTypes(
.join("\n");
const envBindings = workflows
.map((workflow, index) => {
const payload = `__SideffectWorkflowPayload<typeof __SideffectWorkflow${index}>`;
const payload = `WorkflowInput<typeof __SideffectWorkflow${index}>`;
return ` ${workflow.config.binding}: __SideffectCloudflareWorkflow<${payload}>;`;
})
.join("\n");
const cloudflareEnvBindings = workflows
.map((workflow, index) => {
const payload = `__SideffectWorkflowPayload<typeof __SideffectWorkflow${index}>`;
const payload = `WorkflowInput<typeof __SideffectWorkflow${index}>`;
return ` ${workflow.config.binding}: __SideffectCloudflareWorkflow<${payload}>;`;
})
.join("\n");

return `// Generated by Sideffect. Do not edit.
import type { WorkflowLayer } from "sideffect";
import type { WorkflowInput } from "sideffect";
${imports}

type __SideffectCloudflareWorkflow<Payload> = Workflow<Payload>;
type __SideffectWorkflowPayload<T> = T extends WorkflowLayer<infer Payload, any> ? Payload : never;

declare global {
interface Env {
Expand Down
16 changes: 9 additions & 7 deletions packages/sideffect/src/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import type {
} from "./types.ts";

/** Options for creating a Sideffect workflow definition. */
export interface WorkflowMakeOptions<Payload> {
export interface WorkflowMakeOptions<Payload, Input = Payload> {
/** Cloudflare Workflow name. */
readonly name: string;
/** Schema used to decode incoming workflow event payloads. */
readonly payload: Schema.Schema<Payload>;
readonly payload: Schema.Codec<Payload, Input, never, unknown>;
}

/** Helpers for defining Sideffect workflows. */
Expand All @@ -35,14 +35,16 @@ export const Workflow = {
* });
* ```
*/
make<Payload, Env = DefaultCloudflareEnv>(
options: WorkflowMakeOptions<Payload>,
): WorkflowDefinition<Payload, Env> {
const definition: WorkflowDefinition<Payload, Env> = {
make<Payload, Env = DefaultCloudflareEnv, Input = Payload>(
options: WorkflowMakeOptions<Payload, Input>,
): WorkflowDefinition<Payload, Env, Input> {
const definition: WorkflowDefinition<Payload, Env, Input> = {
_tag: "WorkflowDefinition",
name: options.name,
payloadSchema: options.payload,
toLayer<Result>(run: WorkflowRun<Payload, Result, Env>): WorkflowLayer<Payload, Result, Env> {
toLayer<Result>(
run: WorkflowRun<Payload, Result, Env>,
): WorkflowLayer<Payload, Result, Env, Input> {
return {
_tag: "WorkflowLayer",
workflow: definition,
Expand Down
9 changes: 9 additions & 0 deletions packages/sideffect/tests/ctx-env.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Rollback, Schema, Step, Workflow } from "../src/index.ts";
import type { WorkflowInput } from "../src/index.ts";

declare global {
namespace Cloudflare {
Expand Down Expand Up @@ -41,4 +42,12 @@ Workflow.make({
return step.do(envBackedStep, workflow.payload);
});

const encodedWorkflow = Workflow.make({
name: "encoded-workflow",
payload: Schema.NumberFromString,
}).toLayer(async ({ payload }) => payload);

const encodedInput: WorkflowInput<typeof encodedWorkflow> = "42";
void encodedInput;

export {};
1 change: 1 addition & 0 deletions packages/sideffect/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ test("Sideffect workflows plugin discovers workflows from Vite root before confi
const envTypes = readFileSync(join(root, "sideffect-env.d.ts"), "utf8");
expect(envTypes).not.toContain("Workflow as CloudflareWorkflow");
expect(envTypes).not.toContain('from "cloudflare:workers"');
expect(envTypes).toContain('import type { WorkflowInput } from "sideffect";');
expect(envTypes).toContain(
"type __SideffectCloudflareWorkflow<Payload> = Workflow<Payload>;",
);
Expand Down
Loading
Loading