JavaScript and TypeScript Modules
Declare project-local code once and call it through services.
Export named functions
export function calculateTax(subtotal) {
return subtotal * 0.2;
}Import the module
<woml>
<imports><module name="pricing" from="./pricing.js" /></imports>
<workflow id="orders" version="1.0.0">
<steps><step id="total"><script>
return { tax: services.pricing.calculateTax(context.payload.subtotal) };
</script></step></steps>
</workflow>
</woml>Use named function exports. Default exports, CommonJS, export lists, package imports, and dynamic imports are not supported in the current module profile. Static relative imports require explicit .js or .ts extensions.
Build a pricing module
Create modules/pricing.ts:
export interface OrderItem {
price: number;
quantity: number;
}
export function calculate(items: OrderItem[], taxRate: number) {
const subtotal = items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
const tax = subtotal * taxRate;
return { subtotal, tax, total: subtotal + tax };
}Import it once near the document root:
<imports>
<module name="pricing" from="./modules/pricing.ts" />
</imports>Call the named export through the injected service alias:
<step id="calculateTotal">
<script>
return services.pricing.calculate(context.payload.items, 0.2);
</script>
</step>The workflow remains responsible for data flow and durable step boundaries. The module remains ordinary reusable code.
Use services inside a module
Local modules receive services and native fetch() automatically, so an API wrapper may call services.http.request() without importing WOML. The generated woml-env.d.ts declaration teaches TypeScript and editors about that injected global.
Modules do not automatically receive context, attempt, or secrets. Pass values explicitly:
return services.crm.loadCustomer(
context.payload.customerId,
secrets.CRM_TOKEN
);This makes data and credential dependencies visible at the workflow call site.
Validate and generate types
woml check and woml run resolve the complete static module graph and refresh the default declarations. Use woml types only for an explicit refresh or custom output path.
Keep module initialization free of external side effects. Export functions that perform work when called rather than opening clients or sending requests during module loading.