Skip to content

Commit 68aa5d9

Browse files
Update Readme (#226)
* 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
1 parent 13139fd commit 68aa5d9

1 file changed

Lines changed: 146 additions & 2 deletions

File tree

README.md

Lines changed: 146 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ cron.trigger({ schedule: "0 */5 * * * *" });
3737
// Fetch with built-in consensus across nodes
3838
const price = await cre.runInNodeMode(
3939
fetchPriceData,
40-
consensusMedianAggregation()
40+
consensusMedianAggregation(),
4141
)(config);
4242
```
4343

@@ -47,7 +47,7 @@ const price = await cre.runInNodeMode(
4747
// Read/write to any EVM chain
4848
const evmClient = new cre.capabilities.EVMClient(
4949
undefined,
50-
BigInt("5009297550715157269") // Ethereum Sepolia
50+
BigInt("5009297550715157269"), // Ethereum Sepolia
5151
);
5252
```
5353

@@ -83,6 +83,150 @@ const evmClient = new cre.capabilities.EVMClient(
8383
- Cross-chain token transfers
8484
- Unified liquidity management
8585

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)
102+
├─ Step 2: Runtime compatibility validation (always runs)
103+
├─ Step 3: Bundle to JS
104+
└─ Step 4: Compile to WASM
105+
```
106+
107+
### Workflow `tsconfig.json`
108+
109+
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.
133+
134+
**Blocked modules:** `crypto`, `fs`, `fs/promises`, `net`, `http`, `https`, `child_process`, `os`, `stream`, `worker_threads`, `dns`, `zlib`
135+
136+
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:
154+
155+
| Restricted API | CRE Alternative |
156+
| -------------------------------- | -------------------------------------- |
157+
| `fetch()` | `cre.capabilities.HTTPClient` |
158+
| `setTimeout()` | `cre.capabilities.CronCapability` |
159+
| `setInterval()` | `cre.capabilities.CronCapability` |
160+
| `window`, `document` | Not applicable (no DOM) |
161+
| `XMLHttpRequest` | `cre.capabilities.HTTPClient` |
162+
| `localStorage`, `sessionStorage` | Not applicable (no persistent storage) |
163+
164+
```typescript
165+
// ❌ IDE shows strikethrough + deprecation warning:
166+
// "@deprecated fetch is not available in CRE WASM workflows.
167+
// Use cre.capabilities.HTTPClient instead."
168+
const response = await fetch("https://api.example.com");
169+
// ~~~~~ 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 = new HTTPClient();
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:
186+
187+
- **Text encoding:** `TextEncoder`, `TextDecoder`
188+
- **Binary data:** `Buffer` (with `alloc`, `from`, `concat`, etc.)
189+
- **Base64:** `atob()`, `btoa()`
190+
- **URLs:** `URL`, `URLSearchParams`
191+
- **Console:** `console.log()`, `.warn()`, `.error()`, `.info()`, `.debug()`
192+
- **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:
218+
$ cre compile src/bad-workflow.ts --skip-type-checks
219+
220+
# ⚠️ Skipping TypeScript checks (--skip-type-checks)
221+
# ❌ 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.
229+
86230
## Contributing & Development
87231

88232
This monorepo uses:

0 commit comments

Comments
 (0)