Skip to content
Open
2 changes: 1 addition & 1 deletion packages/cre-sdk-examples/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@chainlink/cre-sdk-examples",
"private": true,
"version": "1.4.0",
"version": "1.6.0",
"type": "module",
"author": "Ernest Nowacki",
"license": "BUSL-1.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/cre-sdk-javy-plugin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@chainlink/cre-sdk-javy-plugin",
"version": "1.2.0",
"version": "1.5.0",
"type": "module",
"bin": {
"cre-setup": "bin/setup.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/cre-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@chainlink/cre-sdk",
"version": "1.4.0",
"version": "1.6.0",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions packages/cre-sdk/scripts/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { WorkflowRuntimeCompatibilityError } from './src/validate-workflow-runti

const availableScripts = [
'build-types',
'check-determinism', // Check for non-deterministic patterns in workflow source
'compile-to-js',
'compile-to-wasm',
'compile-workflow', // TS -> JS -> WASM compilation in single script
Expand Down
64 changes: 64 additions & 0 deletions packages/cre-sdk/scripts/src/check-determinism.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
import { spawnSync } from 'node:child_process'
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'

let tempDir: string

const scriptsDir = path.resolve(import.meta.dir, '..')
const runScript = path.join(scriptsDir, 'run.ts')

beforeEach(() => {
tempDir = mkdtempSync(path.join(tmpdir(), 'cre-check-determinism-test-'))
})

afterEach(() => {
rmSync(tempDir, { recursive: true, force: true })
})

const runCheckDeterminism = (filePath: string) =>
spawnSync(process.execPath, [runScript, 'check-determinism', filePath], {
cwd: scriptsDir,
encoding: 'utf-8',
})

describe('check-determinism CLI', () => {
test('fails when the input file does not exist', () => {
const missingFile = path.join(tempDir, 'does-not-exist.ts')
const result = runCheckDeterminism(missingFile)

expect(result.status).toBe(1)
expect(result.stdout).not.toContain('No non-determinism warnings found.')
expect(result.stderr).toContain(`❌ File not found: ${missingFile}`)
})

test('prints warnings for non-deterministic patterns and exits 0', () => {
const filePath = path.join(tempDir, 'workflow.ts')
writeFileSync(filePath, `const result = await Promise.race([]);\n`, 'utf-8')
const result = runCheckDeterminism(filePath)

expect(result.status).toBe(0)
expect(result.stderr).toContain('Non-determinism warnings')
expect(result.stderr).toContain('Promise.race()')
})

test('prints success message for clean workflow and exits 0', () => {
const filePath = path.join(tempDir, 'workflow.ts')
writeFileSync(filePath, `const x = 1;\n`, 'utf-8')
const result = runCheckDeterminism(filePath)

expect(result.status).toBe(0)
expect(result.stdout).toContain('No non-determinism warnings found.')
})

test('fails when no input file is provided', () => {
const result = spawnSync(process.execPath, [runScript, 'check-determinism'], {
cwd: scriptsDir,
encoding: 'utf-8',
})

expect(result.status).toBe(1)
expect(result.stderr).toContain('Usage:')
})
})
32 changes: 32 additions & 0 deletions packages/cre-sdk/scripts/src/check-determinism.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { existsSync } from 'node:fs'
import path from 'node:path'
import { checkWorkflowDeterminism, printDeterminismWarnings } from './validate-workflow-determinism'

const printUsage = () => {
console.error('Usage: bun scripts/run.ts check-determinism <path/to/workflow.ts>')
console.error('Example:')
console.error(' bun scripts/run.ts check-determinism src/workflows/my-workflow/index.ts')
}

export const main = () => {
const inputPath = process.argv[3]

if (!inputPath) {
printUsage()
process.exit(1)
}

const resolvedInput = path.resolve(inputPath)
if (!existsSync(resolvedInput)) {
console.error(`❌ File not found: ${resolvedInput}`)
process.exit(1)
}

const warnings = checkWorkflowDeterminism(resolvedInput)

if (warnings.length > 0) {
printDeterminismWarnings(warnings)
} else {
console.info('No non-determinism warnings found.')
}
}
7 changes: 7 additions & 0 deletions packages/cre-sdk/scripts/src/compile-to-js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from 'node:path'
import { $ } from 'bun'
import { parseCompileCliArgs, skipTypeChecksFlag } from './compile-cli-args'
import { assertWorkflowTypecheck } from './typecheck-workflow'
import { checkWorkflowDeterminism, printDeterminismWarnings } from './validate-workflow-determinism'
import { assertWorkflowRuntimeCompatibility } from './validate-workflow-runtime-compat'
import { wrapWorkflowCode } from './workflow-wrapper'

Expand Down Expand Up @@ -60,6 +61,12 @@ export const main = async (
assertWorkflowTypecheck(resolvedInput)
}
assertWorkflowRuntimeCompatibility(resolvedInput)
if (!parsedSkipTypeChecks) {
const warnings = checkWorkflowDeterminism(resolvedInput)
if (warnings.length > 0) {
printDeterminismWarnings(warnings)
}
}
console.info(`📁 Using input file: ${resolvedInput}`)

// If no explicit output path → same dir, swap extension to .js
Expand Down
Loading
Loading