MUST use when writing Bun Native scripts.
Place scripts in a folder. After writing, tell the user they can run:
wmill generate-metadata - Generate .script.yaml and .lock fileswmill sync push - Deploy to WindmillDo NOT run these commands yourself. Instead, inform the user that they should run them.
Use wmill resource-type list --schema to discover available resource types.
Native TypeScript execution with fetch only - no external imports allowed.
Export a single async function called main:
export async function main(param1: string, param2: number) {
// Your code here
return { result: param1, count: param2 };
}
Do not call the main function.
On Windmill, credentials and configuration are stored in resources and passed as parameters to main.
Use the RT namespace for resource types:
export async function main(stripe: RT.Stripe) {
// stripe contains API key and config from the resource
}
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
Before using a resource type, check the rt.d.ts file in the project root to see all available resource types and their fields. This file is generated by wmill resource-type generate-namespace.
No imports allowed. Use the globally available fetch function:
export async function main(url: string) {
const response = await fetch(url);
return await response.json();
}
The windmill client is not available in native TypeScript mode. Use fetch to call APIs directly.
For preprocessor scripts, the function should be named preprocessor and receives an event parameter:
type Event = {
kind:
| "webhook"
| "http"
| "websocket"
| "kafka"
| "email"
| "nats"
| "postgres"
| "sqs"
| "mqtt"
| "gcp";
body: any;
headers: Record<string, string>;
query: Record<string, string>;
};
export async function preprocessor(event: Event) {
return {
param1: event.body.field1,
param2: event.query.id,
};
}
Windmill provides built-in support for S3-compatible storage operations.
The S3Object type represents a file in S3 storage:
type S3Object = {
s3: string; // Path within the bucket
};
import * as wmill from "windmill-client";
// Load file content from S3
const content: Uint8Array = await wmill.loadS3File(s3object);
// Load file as stream
const blob: Blob = await wmill.loadS3FileStream(s3object);
// Write file to S3
const result: S3Object = await wmill.writeS3File(
s3object, // Target path (or undefined to auto-generate)
fileContent, // string or Blob
s3ResourcePath // Optional: specific S3 resource to use
);
Import: import * as wmill from 'windmill-client'
workerHasInternalServer(): boolean
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
$res:path/**
/**
/**
/**
getStatePath().
*/
async setState(state: any, path?: string): Promise<void>/**
/**
/**
/**
/**
/**
getStatePath().
*/
async getState(path?: string): Promise<any>/**
/**
/**
async polarsConnectionSettings(s3_resource_path: string | undefined): Promise<any>
async duckdbConnectionSettings(s3_resource_path: string | undefined): Promise<any>
/**
/**
*/ async loadS3File(s3object: S3Object, s3ResourcePath: string | undefined = undefined): Promise<Uint8Array | undefined>
/**
*/ async loadS3FileStream(s3object: S3Object, s3ResourcePath: string | undefined = undefined): Promise<Blob | undefined>
/**
*/ async writeS3File(s3object: S3Object | undefined, fileContent: string | Blob, s3ResourcePath: string | undefined = undefined, contentType: string | undefined = undefined, contentDisposition: string | undefined = undefined): Promise<S3Object>
/**
/**
/**
/**
/**
This allows pre-approvals that can be consumed by any later suspend step in the same flow.
/**
/**
/**
/**
/**
/**
JobService.getSlackApprovalPayload call fails.
/**
JobService.getTeamsApprovalPayload call fails.
/**
setWorkflowCtx(ctx: WorkflowCtx | null): void
async sleep(seconds: number): Promise<void>
async step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
/**
/**
/**
step() to/**
getResumeUrls() (wrapped in step()) to obtain resume/cancel/approvalPage/**
fn(item), which should be a task().concurrency (default: all at once)./**
/**
WHERE name = ${name} AND age = ${age}::int
/**
WHERE name = ${name} AND age = ${age}