From 1d22072fd0d5967a1eda4b4aadd04565aa02811b Mon Sep 17 00:00:00 2001 From: James Grugett Date: Thu, 18 Sep 2025 22:47:43 -0700 Subject: [PATCH] sdk export as both .mjs and commonjs --- bun.lock | 2 +- sdk/build.ts | 42 ++- sdk/package.json | 16 +- sdk/smoke-test-dist.ts | 4 +- sdk/smoke-test.ts | 94 ------ sdk/test/cjs-compatibility/package-lock.json | 313 +++++++++++++++++++ sdk/test/cjs-compatibility/package.json | 21 ++ sdk/test/cjs-compatibility/test-imports.js | 77 +++++ sdk/test/cjs-compatibility/test-types.ts | 43 +++ sdk/test/cjs-compatibility/tsconfig.json | 17 + sdk/test/esm-compatibility/package-lock.json | 287 +++++++++++++++++ sdk/test/esm-compatibility/package.json | 21 ++ sdk/test/esm-compatibility/test-imports.js | 79 +++++ sdk/test/esm-compatibility/test-types.ts | 49 +++ sdk/test/esm-compatibility/tsconfig.json | 17 + sdk/tsconfig.build.json | 8 +- 16 files changed, 973 insertions(+), 117 deletions(-) delete mode 100644 sdk/smoke-test.ts create mode 100644 sdk/test/cjs-compatibility/package-lock.json create mode 100644 sdk/test/cjs-compatibility/package.json create mode 100644 sdk/test/cjs-compatibility/test-imports.js create mode 100644 sdk/test/cjs-compatibility/test-types.ts create mode 100644 sdk/test/cjs-compatibility/tsconfig.json create mode 100644 sdk/test/esm-compatibility/package-lock.json create mode 100644 sdk/test/esm-compatibility/package.json create mode 100644 sdk/test/esm-compatibility/test-imports.js create mode 100644 sdk/test/esm-compatibility/test-types.ts create mode 100644 sdk/test/esm-compatibility/tsconfig.json diff --git a/bun.lock b/bun.lock index 68defc221c..9cd00b1130 100644 --- a/bun.lock +++ b/bun.lock @@ -236,7 +236,7 @@ }, "sdk": { "name": "@codebuff/sdk", - "version": "0.1.33", + "version": "0.2.0", "dependencies": { "@vscode/ripgrep": "1.15.14", "@vscode/tree-sitter-wasm": "0.1.4", diff --git a/sdk/build.ts b/sdk/build.ts index b7745301dc..ac4dd6a9bf 100644 --- a/sdk/build.ts +++ b/sdk/build.ts @@ -1,5 +1,5 @@ -// Build script for @codebuff/sdk using Bun's bundler with splitting -// Creates structured output with separate chunks for better Node.js compatibility +// Build script for @codebuff/sdk using Bun's bundler with dual package support +// Creates ESM + CJS bundles with TypeScript declarations import { execSync } from 'child_process' import { mkdir, cp } from 'fs/promises' @@ -27,6 +27,21 @@ async function build() { 'util', ] + console.log('๐Ÿ“ฆ Building ESM format...') + await Bun.build({ + entrypoints: ['src/index.ts'], + outdir: 'dist', + target: 'node', + format: 'esm', + sourcemap: 'external', + minify: false, + external, + naming: '[dir]/index.mjs', + loader: { + '.scm': 'text', + }, + }) + console.log('๐Ÿ“ฆ Building CJS format...') await Bun.build({ entrypoints: ['src/index.ts'], @@ -36,6 +51,7 @@ async function build() { sourcemap: 'external', minify: false, external, + naming: '[dir]/index.cjs', define: { 'import.meta.url': 'undefined', 'import.meta': 'undefined', @@ -48,6 +64,7 @@ async function build() { console.log('๐Ÿ“ Generating TypeScript declarations...') try { execSync('tsc -p tsconfig.build.json', { stdio: 'inherit' }) + await createSimpleIndexTypes() } catch (error) { console.warn('โš  TypeScript declaration generation failed, continuing...') } @@ -55,20 +72,23 @@ async function build() { console.log('๐Ÿ“‚ Copying WASM files for tree-sitter...') await copyWasmFiles() - console.log('๐Ÿ“ Creating colocated declaration files...') - await createColocatedDeclarations() - console.log('โœ… Build complete!') + console.log(' ๐Ÿ“„ dist/index.mjs (ESM)') + console.log(' ๐Ÿ“„ dist/index.cjs (CJS)') + console.log(' ๐Ÿ“„ dist/index.d.ts (Types)') } /** - * Create colocated declaration files for better TypeScript compatibility + * Create a simple index.d.ts that re-exports from the generated types */ -async function createColocatedDeclarations() { - // Create index.d.ts that exports everything from ./sdk/src/index.d.ts - const indexDeclaration = 'export * from "./sdk/src/index";\n' - await Bun.write('dist/index.d.ts', indexDeclaration) - console.log(' โœ“ Created dist/index.d.ts') +async function createSimpleIndexTypes() { + try { + const indexDeclaration = 'export * from "./sdk/src/index";\n' + await Bun.write('dist/index.d.ts', indexDeclaration) + console.log(' โœ“ Created simple re-export types') + } catch (error) { + console.warn(' โš  Warning: Could not create index types:', error.message) + } } /** diff --git a/sdk/package.json b/sdk/package.json index 2a085dae64..a35b290648 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -5,15 +5,16 @@ "version": "0.2.0", "description": "Official SDK for Codebuff โ€” AI coding agent & framework", "license": "Apache-2.0", - "type": "commonjs", - "main": "./dist/index.js", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", "types": "./dist/index.d.ts", "typings": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", - "require": "./dist/index.js", - "default": "./dist/index.js" + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" }, "./package.json": "./package.json" }, @@ -25,14 +26,17 @@ ], "scripts": { "build": "bun run build.ts", - "build:verify": "bun run build && bun run smoke-test && bun run smoke-test:dist", - "smoke-test": "bun run smoke-test.ts", + "build:types": "tsc -p tsconfig.build.json", + "build:verify": "bun run build && bun run smoke-test:dist && bun run test:cjs && bun run test:esm", "smoke-test:dist": "bun run smoke-test-dist.ts", + "test:cjs": "cd test/cjs-compatibility && npm install --silent && npm run test:all", + "test:esm": "cd test/esm-compatibility && npm install --silent && npm run test:all", "clean": "rm -rf dist", "prepare-dist": "bun run scripts/publish.ts --dry-run", "publish-sdk": "bun run scripts/publish.ts --public", "publish-dry-run": "bun run build:verify && bun run scripts/publish.ts --dry-run", "prepack": "bun run build", + "prepublishOnly": "bun run build", "typecheck": "tsc --noEmit -p .", "test": "bun test" }, diff --git a/sdk/smoke-test-dist.ts b/sdk/smoke-test-dist.ts index 0e084fe7f4..04e71d4072 100644 --- a/sdk/smoke-test-dist.ts +++ b/sdk/smoke-test-dist.ts @@ -114,7 +114,7 @@ async function testCJSDist() { const testCode = ` try { // Require from the built CJS dist files - const pkg = require('../dist/index.js'); + const pkg = require('../dist/index.cjs'); console.log('CJS dist require successful'); // Verify basic structure @@ -166,7 +166,7 @@ async function testCJSTreeSitter() { const runTest = async () => { try { // Require tree-sitter functionality from built CJS dist - const { getFileTokenScores, setWasmDir } = require('../dist/index.js'); + const { getFileTokenScores, setWasmDir } = require('../dist/index.cjs'); console.log('CJS tree-sitter imports successful'); // Set WASM directory to the correct location for dist tests diff --git a/sdk/smoke-test.ts b/sdk/smoke-test.ts deleted file mode 100644 index 65d163b728..0000000000 --- a/sdk/smoke-test.ts +++ /dev/null @@ -1,94 +0,0 @@ -// Smoke test script to verify CJS build works correctly -// This runs after the build to ensure the artifacts are properly functional - -import { execSync } from 'child_process' -import { writeFileSync, mkdirSync, rmSync } from 'fs' -import { join } from 'path' - -const testDir = 'test-smoke' -const testResults: { format: string; success: boolean; error?: string }[] = [] - -async function runSmokeTests() { - console.log('๐Ÿงช Running SDK smoke tests...') - - // Clean up any previous test directory - try { - rmSync(testDir, { recursive: true, force: true }) - } catch {} - - mkdirSync(testDir, { recursive: true }) - - // Test CJS require - await testCJSRequire() - - // Clean up - rmSync(testDir, { recursive: true, force: true }) - - // Report results - console.log('\n๐Ÿ“Š Smoke Test Results:') - testResults.forEach(({ format, success, error }) => { - const status = success ? 'โœ…' : 'โŒ' - console.log(`${status} ${format}: ${success ? 'PASS' : 'FAIL'}`) - if (error) console.log(` Error: ${error}`) - }) - - const allPassed = testResults.every((r) => r.success) - if (allPassed) { - console.log('\n๐ŸŽ‰ All smoke tests passed!') - process.exit(0) - } else { - console.log('\n๐Ÿ’ฅ Some smoke tests failed!') - process.exit(1) - } -} - -async function testCJSRequire() { - console.log(' Testing CJS require...') - - const testFile = join(testDir, 'test-cjs.cjs') - const testCode = ` -try { - // Test basic require structure without invoking complex functionality - const pkg = require('../dist/index.js'); - console.log('CJS require successful'); - - // Check that it's an object with some exports - if (typeof pkg === 'object' && pkg !== null) { - const exportKeys = Object.keys(pkg); - console.log('Package exports found:', exportKeys.length, 'exports'); - - // Basic smoke test - just verify structure exists - if (exportKeys.length > 0) { - console.log('โœ… CJS format has exports'); - process.exit(0); - } else { - console.error('โŒ No exports found'); - process.exit(1); - } - } else { - console.error('โŒ Package is not an object:', typeof pkg); - process.exit(1); - } -} catch (error) { - console.error('โŒ CJS require failed:', error.message); - process.exit(1); -} -` - - writeFileSync(testFile, testCode) - - try { - execSync(`node ${testFile}`, { stdio: 'pipe', cwd: process.cwd() }) - testResults.push({ format: 'CJS', success: true }) - } catch (error: any) { - testResults.push({ - format: 'CJS', - success: false, - error: error.message || 'Unknown error', - }) - } -} - -if (import.meta.main) { - runSmokeTests().catch(console.error) -} diff --git a/sdk/test/cjs-compatibility/package-lock.json b/sdk/test/cjs-compatibility/package-lock.json new file mode 100644 index 0000000000..0805d482a4 --- /dev/null +++ b/sdk/test/cjs-compatibility/package-lock.json @@ -0,0 +1,313 @@ +{ + "name": "cjs-compatibility-test", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cjs-compatibility-test", + "version": "1.0.0", + "dependencies": { + "@codebuff/sdk": "*" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "typescript": "^5.0.0" + } + }, + "../..": { + "name": "@codebuff/sdk", + "version": "0.2.0", + "extraneous": true, + "license": "Apache-2.0", + "dependencies": { + "@vscode/ripgrep": "1.15.14", + "@vscode/tree-sitter-wasm": "0.1.4", + "ai": "^5.0.0", + "diff": "8.0.2", + "web-tree-sitter": "0.25.6", + "zod": "^4.0.0" + }, + "devDependencies": { + "@types/bun": "^1.2.11", + "@types/diff": "8.0.0", + "@types/node": "22", + "rimraf": "^6.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../dist": { + "extraneous": true + }, + "node_modules/@ai-sdk/gateway": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-1.0.24.tgz", + "integrity": "sha512-Mwp0yYXrEnENoDrc7IH9yVRVJ7RrDW0CXWDtyz1BiyqccbtdWhAKu4wtrDMx2FkeK5riiME1kYYdjRnlba3UFw==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.9" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.9.tgz", + "integrity": "sha512-Pm571x5efqaI4hf9yW4KsVlDBDme8++UepZRnq+kqVBWWjgvGhQlzU8glaFq0YJEB9kkxZHbRRyVeHoV2sRYaQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4" + } + }, + "node_modules/@codebuff/sdk": { + "version": "0.1.33", + "resolved": "https://registry.npmjs.org/@codebuff/sdk/-/sdk-0.1.33.tgz", + "integrity": "sha512-k7MG04+vxEELluGK748daUkDQvjX9baX4uwPS1dUi3yjjpNHHxJxpbdTDJ6LsBsJ7eIfT+u/6xbjj7lY3BKsKw==", + "license": "Apache-2.0", + "dependencies": { + "@vscode/ripgrep": "1.15.14", + "@vscode/tree-sitter-wasm": "0.1.4", + "ai": "^5.0.0", + "diff": "8.0.2", + "web-tree-sitter": "0.25.6", + "zod": "^4.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz", + "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@vscode/ripgrep": { + "version": "1.15.14", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.15.14.tgz", + "integrity": "sha512-/G1UJPYlm+trBWQ6cMO3sv6b8D1+G16WaJH1/DSqw32JOVlzgZbLkDxRyzIpTpv30AcYGMkCf5tUqGlW6HbDWw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "https-proxy-agent": "^7.0.2", + "proxy-from-env": "^1.1.0", + "yauzl": "^2.9.2" + } + }, + "node_modules/@vscode/tree-sitter-wasm": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.1.4.tgz", + "integrity": "sha512-kQVVg/CamCYDM+/XYCZuNTQyixjZd8ts/Gf84UzjEY0eRnbg6kiy5I9z2/2i3XdqwhI87iG07rkMR2KwhqcSbA==", + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ai": { + "version": "5.0.47", + "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.47.tgz", + "integrity": "sha512-/DKfU9tTsQVcUYSDCTu1L7jmvEgzUWOr1xf5UHwwDbRf/HED8LDb60QlWYs6f4BkZsVoLvpliCSjliXiRZywFQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/gateway": "1.0.24", + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.9", + "@opentelemetry/api": "1.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-tree-sitter": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.25.6.tgz", + "integrity": "sha512-WG+/YGbxw8r+rLlzzhV+OvgiOJCWdIpOucG3qBf3RCBFMkGDb1CanUi2BxCxjnkpzU3/hLWPT8VO5EKsMk9Fxg==", + "license": "MIT" + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/zod": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.9.tgz", + "integrity": "sha512-HI32jTq0AUAC125z30E8bQNz0RQ+9Uc+4J7V97gLYjZVKRjeydPgGt6dvQzFrav7MYOUGFqqOGiHpA/fdbd0cQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/sdk/test/cjs-compatibility/package.json b/sdk/test/cjs-compatibility/package.json new file mode 100644 index 0000000000..b0a2fb6652 --- /dev/null +++ b/sdk/test/cjs-compatibility/package.json @@ -0,0 +1,21 @@ +{ + "name": "cjs-compatibility-test", + "version": "1.0.0", + "type": "commonjs", + "private": true, + "main": "index.js", + "scripts": { + "setup": "mkdir -p node_modules/@codebuff && cp -r ../../dist node_modules/@codebuff/sdk && cp ../../package.json node_modules/@codebuff/sdk/", + "test": "node test-imports.js", + "test:types": "tsc --noEmit --skipLibCheck test-types.ts", + "test:compile": "tsc test-types.ts --outDir ./dist --skipLibCheck && cd dist && node test-types.js", + "test:all": "npm run setup && npm run test && npm run test:types" + }, + "dependencies": { + "@codebuff/sdk": "*" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "typescript": "^5.0.0" + } +} diff --git a/sdk/test/cjs-compatibility/test-imports.js b/sdk/test/cjs-compatibility/test-imports.js new file mode 100644 index 0000000000..d77bd08c06 --- /dev/null +++ b/sdk/test/cjs-compatibility/test-imports.js @@ -0,0 +1,77 @@ +// Test CommonJS imports in a pure CommonJS environment +console.log('๐Ÿงช Testing CommonJS imports in CommonJS-only project...') + +try { + // Test 1: Named destructuring import + console.log('\n1. Testing named destructuring import...') + const { CodebuffClient } = require('@codebuff/sdk') + console.log('โœ… Named destructuring successful:', typeof CodebuffClient) + + if (typeof CodebuffClient !== 'function') { + throw new Error( + `Expected CodebuffClient to be a function, got ${typeof CodebuffClient}`, + ) + } + + // Test 2: Default require + console.log('\n2. Testing default require...') + const SDK = require('@codebuff/sdk') + console.log('โœ… Default require successful:', typeof SDK) + + if (typeof SDK !== 'object' || SDK === null) { + throw new Error(`Expected SDK to be an object, got ${typeof SDK}`) + } + + // Test 3: Verify exports are available + console.log('\n3. Testing available exports...') + const exports = Object.keys(SDK) + console.log('โœ… Found', exports.length, 'exports') + + const expectedExports = ['CodebuffClient', 'getCustomToolDefinition'] + const foundExports = expectedExports.filter((exp) => exp in SDK) + console.log('โœ… Found expected exports:', foundExports.join(', ')) + + if (foundExports.length < 1) { + throw new Error('Missing expected exports') + } + + // Test 4: Test that both access patterns work identically + console.log('\n4. Testing access pattern consistency...') + const ClientFromDestructure = require('@codebuff/sdk').CodebuffClient + const ClientFromDefault = require('@codebuff/sdk').CodebuffClient + + if (ClientFromDestructure !== ClientFromDefault) { + throw new Error('Inconsistent access patterns') + } + console.log('โœ… Access patterns consistent') + + // Test 5: Verify no ESM module properties leak through + console.log('\n5. Testing for ESM leakage...') + if ('__esModule' in SDK) { + console.log( + 'โ„น๏ธ __esModule marker found (this is expected for transpiled modules)', + ) + } + + // Test no direct import/export statements work (they shouldn't in CJS) + try { + // This should fail in CommonJS environment + eval('import { CodebuffClient } from "@codebuff/sdk"') + throw new Error('ESM imports should not work in CommonJS environment') + } catch (syntaxError) { + if ( + syntaxError.message.includes('Unexpected token') || + syntaxError.message.includes('Cannot use import statement') + ) { + console.log('โœ… ESM imports correctly rejected in CommonJS environment') + } else { + throw syntaxError + } + } + + console.log('\n๐ŸŽ‰ All CommonJS import tests passed!') + process.exit(0) +} catch (error) { + console.error('\nโŒ CommonJS import test failed:', error.message) + process.exit(1) +} diff --git a/sdk/test/cjs-compatibility/test-types.ts b/sdk/test/cjs-compatibility/test-types.ts new file mode 100644 index 0000000000..df1010b537 --- /dev/null +++ b/sdk/test/cjs-compatibility/test-types.ts @@ -0,0 +1,43 @@ +// Test TypeScript type resolution in CommonJS environment +import type { CodebuffClient, CustomToolDefinition, RunState } from '@codebuff/sdk'; +import { CodebuffClient as ClientClass, getCustomToolDefinition } from '@codebuff/sdk'; + +// Test 1: Type imports work correctly +const testClient: CodebuffClient = {} as any; +const testTool: CustomToolDefinition = {} as any; +const testState: RunState = {} as any; + +console.log('โœ… Type imports successful'); + +// Test 2: Value imports work correctly in TypeScript +const clientConstructor = ClientClass; +const toolDefFunction = getCustomToolDefinition; + +console.log('โœ… Value imports successful:', typeof clientConstructor, typeof toolDefFunction); + +// Test 3: Test actual instantiation would work (without requiring API key) +type ClientOptions = ConstructorParameters[0]; + +const mockOptions: ClientOptions = { + apiKey: 'test-key', + onError: (error) => console.error('Test error:', error.message), +}; + +// This should compile without errors +const mockClient = new ClientClass(mockOptions); + +console.log('โœ… Client instantiation types work correctly'); + +// Test 4: Custom tool definition types (compile-time only) +type MockTool = ReturnType>; +const toolTypeTest: MockTool = {} as any; + +console.log('โœ… Custom tool definition types work correctly'); + +// Test 5: CommonJS import syntax also works in TypeScript +const SDKRequire = require('@codebuff/sdk'); +const ClientFromRequire: typeof ClientClass = SDKRequire.CodebuffClient; + +console.log('โœ… CommonJS require syntax works in TypeScript'); + +export {}; // Make this a module diff --git a/sdk/test/cjs-compatibility/tsconfig.json b/sdk/test/cjs-compatibility/tsconfig.json new file mode 100644 index 0000000000..119ac87451 --- /dev/null +++ b/sdk/test/cjs-compatibility/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["ES2020", "DOM"], + "module": "CommonJS", + "moduleResolution": "node", + "strict": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "noEmit": true + }, + "include": ["*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/sdk/test/esm-compatibility/package-lock.json b/sdk/test/esm-compatibility/package-lock.json new file mode 100644 index 0000000000..c810f0b43a --- /dev/null +++ b/sdk/test/esm-compatibility/package-lock.json @@ -0,0 +1,287 @@ +{ + "name": "esm-compatibility-test", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "esm-compatibility-test", + "version": "1.0.0", + "dependencies": { + "@codebuff/sdk": "*" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "typescript": "^5.0.0" + } + }, + "node_modules/@ai-sdk/gateway": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-1.0.24.tgz", + "integrity": "sha512-Mwp0yYXrEnENoDrc7IH9yVRVJ7RrDW0CXWDtyz1BiyqccbtdWhAKu4wtrDMx2FkeK5riiME1kYYdjRnlba3UFw==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.9" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.9.tgz", + "integrity": "sha512-Pm571x5efqaI4hf9yW4KsVlDBDme8++UepZRnq+kqVBWWjgvGhQlzU8glaFq0YJEB9kkxZHbRRyVeHoV2sRYaQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4" + } + }, + "node_modules/@codebuff/sdk": { + "version": "0.1.33", + "resolved": "https://registry.npmjs.org/@codebuff/sdk/-/sdk-0.1.33.tgz", + "integrity": "sha512-k7MG04+vxEELluGK748daUkDQvjX9baX4uwPS1dUi3yjjpNHHxJxpbdTDJ6LsBsJ7eIfT+u/6xbjj7lY3BKsKw==", + "license": "Apache-2.0", + "dependencies": { + "@vscode/ripgrep": "1.15.14", + "@vscode/tree-sitter-wasm": "0.1.4", + "ai": "^5.0.0", + "diff": "8.0.2", + "web-tree-sitter": "0.25.6", + "zod": "^4.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz", + "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@vscode/ripgrep": { + "version": "1.15.14", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.15.14.tgz", + "integrity": "sha512-/G1UJPYlm+trBWQ6cMO3sv6b8D1+G16WaJH1/DSqw32JOVlzgZbLkDxRyzIpTpv30AcYGMkCf5tUqGlW6HbDWw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "https-proxy-agent": "^7.0.2", + "proxy-from-env": "^1.1.0", + "yauzl": "^2.9.2" + } + }, + "node_modules/@vscode/tree-sitter-wasm": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.1.4.tgz", + "integrity": "sha512-kQVVg/CamCYDM+/XYCZuNTQyixjZd8ts/Gf84UzjEY0eRnbg6kiy5I9z2/2i3XdqwhI87iG07rkMR2KwhqcSbA==", + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ai": { + "version": "5.0.47", + "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.47.tgz", + "integrity": "sha512-/DKfU9tTsQVcUYSDCTu1L7jmvEgzUWOr1xf5UHwwDbRf/HED8LDb60QlWYs6f4BkZsVoLvpliCSjliXiRZywFQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/gateway": "1.0.24", + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.9", + "@opentelemetry/api": "1.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-tree-sitter": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.25.6.tgz", + "integrity": "sha512-WG+/YGbxw8r+rLlzzhV+OvgiOJCWdIpOucG3qBf3RCBFMkGDb1CanUi2BxCxjnkpzU3/hLWPT8VO5EKsMk9Fxg==", + "license": "MIT" + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/zod": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.9.tgz", + "integrity": "sha512-HI32jTq0AUAC125z30E8bQNz0RQ+9Uc+4J7V97gLYjZVKRjeydPgGt6dvQzFrav7MYOUGFqqOGiHpA/fdbd0cQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/sdk/test/esm-compatibility/package.json b/sdk/test/esm-compatibility/package.json new file mode 100644 index 0000000000..7cc7fe5a0d --- /dev/null +++ b/sdk/test/esm-compatibility/package.json @@ -0,0 +1,21 @@ +{ + "name": "esm-compatibility-test", + "version": "1.0.0", + "type": "module", + "private": true, + "main": "index.js", + "scripts": { + "setup": "mkdir -p node_modules/@codebuff && cp -r ../../dist node_modules/@codebuff/sdk && cp ../../package.json node_modules/@codebuff/sdk/", + "test": "node test-imports.js", + "test:types": "tsc --noEmit --skipLibCheck test-types.ts", + "test:compile": "tsc test-types.ts --outDir ./dist --skipLibCheck --module ESNext --target ES2022 --moduleResolution bundler && node ./dist/test-types.js", + "test:all": "npm run setup && npm run test && npm run test:types && npm run test:compile" + }, + "dependencies": { + "@codebuff/sdk": "*" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "typescript": "^5.0.0" + } +} diff --git a/sdk/test/esm-compatibility/test-imports.js b/sdk/test/esm-compatibility/test-imports.js new file mode 100644 index 0000000000..804034353b --- /dev/null +++ b/sdk/test/esm-compatibility/test-imports.js @@ -0,0 +1,79 @@ +// Test ESM imports in a pure ESM environment +console.log('๐Ÿงช Testing ESM imports in ESM-only project...'); + +try { + // Test 1: Named ESM import + console.log('\n1. Testing named ESM import...'); + const { CodebuffClient } = await import('@codebuff/sdk'); + console.log('โœ… Named ESM import successful:', typeof CodebuffClient); + + if (typeof CodebuffClient !== 'function') { + throw new Error(`Expected CodebuffClient to be a function, got ${typeof CodebuffClient}`); + } + + // Test 2: Namespace ESM import + console.log('\n2. Testing namespace ESM import...'); + const SDK = await import('@codebuff/sdk'); + console.log('โœ… Namespace ESM import successful:', typeof SDK); + + if (typeof SDK !== 'object' || SDK === null) { + throw new Error(`Expected SDK to be an object, got ${typeof SDK}`); + } + + // Test 3: Verify exports are available + console.log('\n3. Testing available exports...'); + const exports = Object.keys(SDK); + console.log('โœ… Found', exports.length, 'exports'); + + const expectedExports = ['CodebuffClient', 'getCustomToolDefinition']; + const foundExports = expectedExports.filter(exp => exp in SDK); + console.log('โœ… Found expected exports:', foundExports.join(', ')); + + if (foundExports.length < 1) { + throw new Error('Missing expected exports'); + } + + // Test 4: Test that both access patterns work identically + console.log('\n4. Testing access pattern consistency...'); + const ClientFromNamed = (await import('@codebuff/sdk')).CodebuffClient; + const ClientFromNamespace = SDK.CodebuffClient; + + if (ClientFromNamed !== ClientFromNamespace) { + throw new Error('Inconsistent access patterns'); + } + console.log('โœ… Access patterns consistent'); + + // Test 5: Verify no CommonJS leakage + console.log('\n5. Testing for CommonJS leakage...'); + if ('__esModule' in SDK) { + console.log('โ„น๏ธ __esModule marker found (this is acceptable for dual packages)'); + } + + // Test that require() doesn't work in ESM environment + try { + eval('const { CodebuffClient } = require("@codebuff/sdk")'); + throw new Error('CommonJS require should not work in ESM environment'); + } catch (referenceError) { + if (referenceError.message.includes('require is not defined')) { + console.log('โœ… CommonJS require correctly rejected in ESM environment'); + } else { + throw referenceError; + } + } + + // Test 6: Test tree-shaking compatibility (static imports) + console.log('\n6. Testing static import compatibility...'); + // This would be a static import in a real ESM file: + // import { CodebuffClient } from '@codebuff/sdk' + // We can't test static imports in a dynamic test, but we can verify the exports are clean + const hasDefault = 'default' in SDK; + console.log('โœ… Has default export:', hasDefault); + console.log('โœ… Named exports available for tree-shaking'); + + console.log('\n๐ŸŽ‰ All ESM import tests passed!'); + process.exit(0); + +} catch (error) { + console.error('\nโŒ ESM import test failed:', error.message); + process.exit(1); +} diff --git a/sdk/test/esm-compatibility/test-types.ts b/sdk/test/esm-compatibility/test-types.ts new file mode 100644 index 0000000000..150a6d83be --- /dev/null +++ b/sdk/test/esm-compatibility/test-types.ts @@ -0,0 +1,49 @@ +// Test TypeScript type resolution in ESM environment +import type { CodebuffClient, CustomToolDefinition, RunState } from '@codebuff/sdk'; +import { CodebuffClient as ClientClass, getCustomToolDefinition } from '@codebuff/sdk'; +import * as FullSDK from '@codebuff/sdk'; + +(async () => { + // Test 1: Type imports work correctly + const testClient: CodebuffClient = {} as any; + const testTool: CustomToolDefinition = {} as any; + const testState: RunState = {} as any; + + console.log('โœ… Type imports successful'); + + // Test 2: Value imports work correctly in TypeScript + const clientConstructor = ClientClass; + const toolDefFunction = getCustomToolDefinition; + + console.log('โœ… Value imports successful:', typeof clientConstructor, typeof toolDefFunction); + + // Test 3: Test actual instantiation would work (without requiring API key) + type ClientOptions = ConstructorParameters[0]; + + const mockOptions: ClientOptions = { + apiKey: 'test-key', + onError: (error) => console.error('Test error:', error.message), + }; + + // This should compile without errors + const mockClient = new ClientClass(mockOptions); + + console.log('โœ… Client instantiation types work correctly'); + + // Test 4: Custom tool definition types (compile-time only) + type MockTool = ReturnType>; + const toolTypeTest: MockTool = {} as any; + + console.log('โœ… Custom tool definition types work correctly'); + + // Test 5: Dynamic imports also work in TypeScript ESM + const dynamicSDK = await import('@codebuff/sdk'); + const ClientFromDynamic: typeof ClientClass = dynamicSDK.CodebuffClient; + console.log('โœ… Dynamic imports work in TypeScript ESM'); + + // Test 6: Namespace imports work + const ClientFromNamespace: typeof ClientClass = FullSDK.CodebuffClient; + console.log('โœ… Namespace imports work correctly'); +})(); + +export {}; // Make this a module diff --git a/sdk/test/esm-compatibility/tsconfig.json b/sdk/test/esm-compatibility/tsconfig.json new file mode 100644 index 0000000000..d4fc4e7908 --- /dev/null +++ b/sdk/test/esm-compatibility/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2020", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "outDir": "./dist" + }, + "include": ["*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/sdk/tsconfig.build.json b/sdk/tsconfig.build.json index 170c2fd7b5..4df2941f93 100644 --- a/sdk/tsconfig.build.json +++ b/sdk/tsconfig.build.json @@ -2,8 +2,8 @@ "compilerOptions": { "target": "ES2022", "lib": ["ES2022", "DOM"], - "module": "esnext", - "moduleResolution": "Bundler", + "module": "ES2022", + "moduleResolution": "bundler", "allowImportingTsExtensions": false, "outDir": "dist", @@ -15,7 +15,9 @@ "esModuleInterop": true, "isolatedModules": true, "forceConsistentCasingInFileNames": true, - "noImplicitReturns": true + "noImplicitReturns": true, + "exactOptionalPropertyTypes": false, + "stripInternal": true }, "include": ["src/**/*"], "exclude": ["**/*.test.ts", "**/*.spec.ts", "node_modules", "dist"]