Skip to content
Merged
24 changes: 24 additions & 0 deletions .github/workflows/runtime-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Runtime Compatibility Tests

on: [push, pull_request]

jobs:
runtime-compatibility:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
- uses: denoland/setup-deno@v2
with:
deno-version: v1.x
- uses: oven-sh/setup-bun@v2

- name: Install and build
run: |
npm install
npm run build

- name: Runtime compatibility check
run: npm run check:runtimes
52 changes: 36 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
"node": ">=18"
},
"type": "module",
"main": "./lib/index.cjs",
"module": "./lib/index.js",
"types": "./lib/index.d.ts",
"main": "./lib/cjs/index.cjs",
"module": "./lib/esm/index.js",
"types": "./lib/esm/index.d.ts",
"files": [
"lib/",
"package.json"
Expand All @@ -37,7 +37,7 @@
"lint": "eslint",
"test": "jest",
"test:watch": "jest --watch",
"test:worker": "jest src/worker.spec.ts",
"check:runtimes": "tsx scripts/ecosystem-check.ts",
"prettier": "prettier \"src/**/*.{js,ts,tsx}\" --check",
"format": "prettier \"src/**/*.{js,ts,tsx}\" --write",
"prepublishOnly": "npm run build"
Expand All @@ -54,45 +54,65 @@
"@babel/preset-typescript": "^7.27.0",
"@eslint/js": "^9.21.0",
"@types/cookie": "^0.6.0",
"@types/glob": "^8.1.0",
"@types/jest": "^29.5.14",
"@types/node": "~18",
"@types/pluralize": "0.0.33",
"@typescript-eslint/parser": "^8.25.0",
"babel-jest": "^29.7.0",
"esbuild-fix-imports-plugin": "^1.0.21",
"eslint": "^9.21.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-n": "^17.15.1",
"glob": "^11.0.3",
"jest": "29.7.0",
"jest-environment-miniflare": "^2.14.2",
"jest-fetch-mock": "^3.0.3",
"miniflare": "^3.20250408.2",
"nock": "^13.5.5",
"prettier": "^3.5.3",
"supertest": "7.1.0",
"ts-jest": "29.3.1",
"tsup": "^8.5.0",
"tsx": "^4.19.0",
"typescript": "5.8.2",
"typescript-eslint": "^8.25.0"
},
"exports": {
".": {
"types": "./lib/index.d.ts",
"types": {
"require": "./lib/cjs/index.d.cts",
"import": "./lib/esm/index.d.ts"
},
"workerd": {
"import": "./lib/index.worker.js",
"require": "./lib/index.worker.cjs"
"import": "./lib/esm/index.worker.js",
"require": "./lib/cjs/index.worker.cjs"
},
"edge-light": {
"import": "./lib/index.worker.js",
"require": "./lib/index.worker.cjs"
"import": "./lib/esm/index.worker.js",
"require": "./lib/cjs/index.worker.cjs"
},
"deno": "./lib/esm/index.js",
"bun": {
"import": "./lib/esm/index.js",
"require": "./lib/cjs/index.cjs"
},
"import": "./lib/index.js",
"require": "./lib/index.cjs",
"default": "./lib/index.js"
"node": {
"import": "./lib/esm/index.js",
"require": "./lib/cjs/index.cjs"
},
"import": "./lib/esm/index.js",
"require": "./lib/cjs/index.cjs",
"default": "./lib/esm/index.js"
},
"./worker": {
"types": "./lib/index.worker.d.ts",
"import": "./lib/index.worker.js",
"require": "./lib/index.worker.cjs",
"default": "./lib/index.worker.js"
"types": {
"require": "./lib/cjs/index.worker.d.cts",
"import": "./lib/esm/index.worker.d.ts"
},
"import": "./lib/esm/index.worker.js",
"require": "./lib/cjs/index.worker.cjs",
"default": "./lib/esm/index.worker.js"
},
"./package.json": "./package.json"
}
Expand Down
142 changes: 142 additions & 0 deletions scripts/ecosystem-check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// scripts/ecosystem-check.ts
import { spawnSync } from 'node:child_process';
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import os from 'node:os';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const root = join(__dirname, '..');
const libCjs = join(root, 'lib/cjs');
const libEsm = join(root, 'lib/esm');
const tmp = mkdtempSync(join(os.tmpdir(), 'workos-test-'));

// Map of "runtime label" → { cmd, args }
const tests: Record<string, { cmd: string; args: string[] }> = {
'node-cjs': {
cmd: 'node',
args: [
'-e',
`console.log('✅ Node CJS:', require("${libCjs}/index.cjs").WorkOS.name)`,
],
},
'node-esm': {
cmd: 'node',
args: [
'-e',
`import("${libEsm}/index.js").then(m => console.log('✅ Node ESM:', m.WorkOS.name))`,
],
},
deno: {
cmd: 'deno',
args: [
'eval',
`import("${libEsm}/index.js").then(m => console.log('✅ Deno:', m.WorkOS.name))`,
],
},
'bun-cjs': {
cmd: 'bun',
args: [
'-e',
`console.log('✅ Bun CJS:', require("${libCjs}/index.cjs").WorkOS.name)`,
],
},
'bun-esm': {
cmd: 'bun',
args: [
'-e',
`import("${libEsm}/index.js").then(m => console.log('✅ Bun ESM:', m.WorkOS.name))`,
],
},
};

let allOK = true;
let ranTests = 0;

console.log('🚀 Running WorkOS SDK ecosystem compatibility checks...\n');

// Run basic runtime tests
for (const [name, { cmd, args }] of Object.entries(tests)) {
process.stdout.write(`Testing ${name.padEnd(12)}... `);

const { status, stderr } = spawnSync(cmd, args, {
stdio: ['inherit', 'pipe', 'pipe'],
encoding: 'utf8',
});

if (status !== 0) {
allOK = false;
console.error(`❌ Failed`);
if (stderr) {
console.error(` Error: ${stderr.trim()}`);
}
} else {
ranTests++;
console.log(`✅ Passed`);
}
}

// Test Cloudflare Worker environment using miniflare
process.stdout.write(`Testing worker ... `);

// 1. Check if miniflare is available
const miniflareCheck = spawnSync('npx', ['miniflare', '--version'], {
stdio: 'ignore', // We don't need to see the version output
encoding: 'utf8',
});

if (miniflareCheck.status !== 0) {
console.log(`⚠️ Skipped (miniflare not found or failed to execute)`);
} else {
// 2. Create the temporary worker script
const workerScriptPath = join(tmp, 'worker-test.js');
const safeLibEsmPath = libEsm.replace(/\\/g, '\\\\'); // For Windows compatibility
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Windows path handling might still fail if path contains spaces. Use JSON.stringify() for full path escaping


const workerScriptContent = `
import { WorkOS } from '${safeLibEsmPath}/index.js';

if (WorkOS && WorkOS.name === 'WorkOS') {
console.log('✅ Worker (miniflare): SDK imported successfully.');
} else {
console.error('❌ Worker (miniflare): SDK import failed or WorkOS class is incorrect.');
process.exit(1);
}
`;

writeFileSync(workerScriptPath, workerScriptContent);

// 3. Execute the worker script with miniflare
const { status, stderr } = spawnSync(
'npx',
['miniflare', '--modules', workerScriptPath],
{
stdio: ['inherit', 'pipe', 'pipe'],
encoding: 'utf8',
},
);

// 4. Process the result
if (status !== 0) {
allOK = false;
console.error(`❌ Failed`);
if (stderr) {
console.error(` Error: ${stderr.trim()}`);
}
} else {
ranTests++;
console.log(`✅ Passed`);
}
}

// Cleanup
rmSync(tmp, { recursive: true, force: true });

console.log(`\n📊 Results: ${ranTests} runtime tests completed`);

if (allOK) {
console.log('🎉 All core runtime compatibility checks passed!');
} else {
console.log('💥 Some runtime tests failed. Check the output above.');
throw new Error('Ecosystem compatibility checks failed');
}
2 changes: 1 addition & 1 deletion src/sso/interfaces/authorization-url-options.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ export interface SSOAuthorizationURLOptions {
/**
* @deprecated Use SSOAuthorizationURLOptions instead
*/
// tslint:disable-next-line:no-empty-interface
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface AuthorizationURLOptions extends SSOAuthorizationURLOptions {}
9 changes: 0 additions & 9 deletions src/worker.spec.ts

This file was deleted.

5 changes: 4 additions & 1 deletion src/workos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ export class WorkOS {
readonly widgets = new Widgets(this);
readonly vault = new Vault(this);

constructor(readonly key?: string, readonly options: WorkOSOptions = {}) {
constructor(
readonly key?: string,
readonly options: WorkOSOptions = {},
) {
if (!key) {
// process might be undefined in some environments
this.key =
Expand Down
Loading