You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Update readme
* Remove the information about raw plugin exported values - consumers should care only about the ones we explicity export
* Change the focus of --skip-type-checks to be more around the cli usage
@@ -83,6 +83,150 @@ const evmClient = new cre.capabilities.EVMClient(
83
83
- Cross-chain token transfers
84
84
- Unified liquidity management
85
85
86
+
## Workflow Type Safety
87
+
88
+
CRE workflows compile from TypeScript to WebAssembly and run inside a Javy/QuickJS sandbox — not a full Node.js or browser runtime. The SDK ships a multi-layered type safety system that catches incompatible API usage at every stage: in the IDE, during type checking, and at build time.
89
+
90
+
### How It Works
91
+
92
+
The compilation pipeline (`cre-compile`) runs two validation passes before bundling and WASM compilation:
93
+
94
+
1.**TypeScript type checking** — Runs `tsc` against your workflow using the nearest `tsconfig.json`. Catches all standard TypeScript errors plus SDK-provided type restrictions (see below).
95
+
96
+
2.**Runtime compatibility validation** — Performs AST-level static analysis to detect imports of restricted Node.js modules and usage of unavailable global APIs. This catches patterns that type-level checks alone can't cover, such as `require()` calls, dynamic `import()`, and usage inside `.js` files.
97
+
98
+
```
99
+
cre-compile workflow.ts output.wasm
100
+
│
101
+
├─ Step 1: TypeScript type check (uses your tsconfig.json)
Every new workflow project ships with a recommended `tsconfig.json`:
110
+
111
+
```jsonc
112
+
{
113
+
"compilerOptions": {
114
+
"lib": ["ESNext"],
115
+
"target":"ESNext",
116
+
"module":"ESNext",
117
+
"moduleDetection":"force",
118
+
"moduleResolution":"bundler",
119
+
"strict":true,
120
+
"noEmit":true,
121
+
"types": [],
122
+
// ...
123
+
},
124
+
"include": ["src/**/*"],
125
+
}
126
+
```
127
+
128
+
The critical setting is **`"types": []`**. By default TypeScript auto-includes all `@types/*` packages from `node_modules`, which would expose full Node.js and Bun type definitions. Setting `types` to an empty array prevents this, so only types explicitly provided by `@chainlink/cre-sdk` are available. This means you get type errors the moment you try to use APIs that won't exist at runtime.
129
+
130
+
### Restricted Node.js Modules
131
+
132
+
The SDK blocks imports from Node.js built-in modules that cannot run in the WASM sandbox. Both bare specifiers (`crypto`) and `node:`-prefixed forms (`node:crypto`) are covered.
All exports from these modules are typed as `never`, so your IDE shows errors immediately:
137
+
138
+
```typescript
139
+
import { createHash } from"node:crypto";
140
+
// ^^^^^^^^^^ Type 'never' is not assignable to ...
141
+
142
+
// The import itself also triggers a build-time error:
143
+
// ❌ 'node:crypto' is not available in CRE workflow runtime.
144
+
```
145
+
146
+
These restrictions are enforced at **two levels**:
147
+
148
+
-**IDE/type-check time** — `@deprecated` JSDoc annotations produce strikethrough text and warnings. The `never` types cause type errors at every call site.
149
+
-**Build time** — The runtime compatibility validator walks the AST of your workflow and all transitively imported local files, catching every import syntax (`import`, `export ... from`, `require()`, `import()`). This check **always runs** — even with `--skip-type-checks`.
150
+
151
+
### Restricted Global APIs
152
+
153
+
Some global APIs that exist in browsers or Node.js are not available in the QuickJS runtime. The SDK overrides their type definitions with `never` types and `@deprecated` markers that point you to the correct CRE alternative:
// ~~~~~ Error: Argument of type 'string' is not assignable to parameter of type 'never'
170
+
171
+
// ✅ Correct approach — use HTTPClient:
172
+
import { HTTPClient } from"@chainlink/cre-sdk";
173
+
174
+
const client =newHTTPClient();
175
+
const response =client.sendRequest({
176
+
url: "https://api.example.com",
177
+
method: "GET",
178
+
});
179
+
```
180
+
181
+
The build-time validator also catches these via TypeScript's type-checker, including `globalThis.fetch`-style access. If you shadow a restricted name with your own variable (e.g. `const fetch = myCustomFunction`), the validator correctly ignores it.
182
+
183
+
### Available Runtime APIs
184
+
185
+
The SDK provides type definitions for all APIs that **are** available in the QuickJS/WASM runtime:
-**Utilities:**`Math.random()` (overridden with seeded ChaCha8 for determinism)
193
+
194
+
These are declared in `global.d.ts` and automatically available when you import `@chainlink/cre-sdk`.
195
+
196
+
### The `--skip-type-checks` Flag
197
+
198
+
The CRE CLI exposes a `--skip-type-checks` flag on the `compile` command. Use it when you need to compile a workflow that has TypeScript errors you're willing to accept:
199
+
200
+
```bash
201
+
# Normal compilation — type check + runtime validation + build
202
+
cre compile src/workflow.ts
203
+
204
+
# Skip TypeScript type checking only
205
+
cre compile src/workflow.ts --skip-type-checks
206
+
```
207
+
208
+
**What `--skip-type-checks` does:**
209
+
210
+
- Skips the TypeScript type checker (`tsc`) — your tsconfig errors won't block compilation.
211
+
212
+
**What `--skip-type-checks` does NOT do:**
213
+
214
+
- It does **not** skip the runtime compatibility validation. Imports of restricted Node.js modules (`node:crypto`, `node:fs`, etc.) and usage of unavailable globals (`fetch`, `setTimeout`, etc.) will **always** block compilation, because these would cause runtime failures in the WASM sandbox.
215
+
216
+
```bash
217
+
# This workflow imports node:crypto — compilation fails regardless of the flag:
# ❌ Unsupported API usage found in workflow source.
222
+
# CRE workflows run on Javy (QuickJS), not full Node.js.
223
+
# - src/bad-workflow.ts:1:25 'node:crypto' is not available in CRE workflow runtime.
224
+
```
225
+
226
+
#### SDK internals
227
+
228
+
Under the hood, the SDK's `cre-compile` binary (`bin/cre-compile.ts`) parses the flag and passes it through the compilation pipeline. The flag controls whether `assertWorkflowTypecheck()` runs, while `assertWorkflowRuntimeCompatibility()` always executes regardless. The CRE CLI invokes this binary, so the flag semantics are identical whether you run `cre compile --skip-type-checks` or call the SDK's compilation API directly.
0 commit comments