UNPKG

auto-builder-sdk

Version:

SDK for building Auto Builder workflow plugins

133 lines (132 loc) 6.18 kB
/** * Resolve the correct `BaseNodeExecutor` implementation at runtime. * * We cannot use a dynamic string in a static `import` statement because that * violates the ECMAScript module spec and breaks the TypeScript → esbuild * transform used by Vitest. Instead we rely on Node's `createRequire` helper * which is available in ESM contexts and gives us a synchronous `require` * function. This keeps the public surface identical while remaining compatible * with both the Vitest environment (which uses source files directly) and the * normal runtime (which consumes the compiled `auto-builder` package). */ import { fileURLToPath, pathToFileURL } from 'node:url'; import path from 'node:path'; import fs from 'node:fs'; // --------------------------------------------------------------------------- // Runtime-side helpers ------------------------------------------------------- // --------------------------------------------------------------------------- /** Resolve a module by progressively trying a list of candidate paths. */ const tryImport = async (candidates) => { let lastErr; for (const loader of candidates) { try { return await loader(); } catch (err) { lastErr = err; } } throw lastErr; }; const resolveServicePath = (startDir, file) => { let dir = startDir; const root = path.resolve('/'); // eslint-disable-next-line no-constant-condition while (true) { const candidate = path.join(dir, `src/services/${file}`); if (fs.existsSync(candidate)) { return candidate; } // also allow compiled dist path const distCandidate = path.join(dir, `dist/services/${file.replace(/\.ts$/, '.js')}`); if (fs.existsSync(distCandidate)) { return distCandidate; } if (dir === root) break; dir = path.dirname(dir); } return undefined; }; /** * --------------------------------------------------------------------------- * Dynamic ESM resolution for services (no more .js shims needed!) * --------------------------------------------------------------------------- */ const BaseNodeExecutor = await tryImport([ // 1. Vitest – return simple stub to avoid heavy imports async () => { if (!process.env.VITEST) throw new Error('skip'); // eslint-disable-next-line @typescript-eslint/no-empty-interface class StubBaseNodeExecutor { } return StubBaseNodeExecutor; }, // 2. Compiled production bundle async () => (await import('auto-builder/dist/services/BaseNodeExecutor.js')).BaseNodeExecutor, // 2b. Direct TS source file path inside sibling auto-builder package (dev watch mode) async () => { const url = new URL('../../auto-builder/src/services/BaseNodeExecutor.ts', import.meta.url); return (await import(url.href)).BaseNodeExecutor; }, // 2c. Compiled dist inside current working directory (application root) async () => { const abs = path.resolve(process.cwd(), 'dist/services/BaseNodeExecutor.js'); return (await import(pathToFileURL(abs).href)).BaseNodeExecutor; }, // 3. Monorepo dev – walk up until we find the TS source file async () => { const src = resolveServicePath(fileURLToPath(import.meta.url), 'BaseNodeExecutor.ts'); if (!src) throw new Error('not-found'); return (await import(pathToFileURL(src).href)).BaseNodeExecutor; }, ]); // Re-export so consumers can `import { BaseNodeExecutor } from "auto-builder-sdk"`. export { BaseNodeExecutor }; import { validatePlugin } from './plugin.js'; export const definePlugin = (meta) => { validatePlugin(meta); return meta; }; export { validatePlugin, PluginSchema } from './plugin.js'; // SDK public surface: re-export BaseNodeExecutor and core Auto-Builder types. export { makeStubContext, makeStubNode } from './testing.js'; export { registerCredential, getCredentialDef, listCredentialDefinitions } from './credentials.js'; // Runtime helpers --------------------------------------------------------- export { log } from './logger.js'; export { NodeOperationError, NodeApiError } from './errors.js'; export { getDb, _injectPrisma as _internalInjectPrismaClient } from './db.js'; export { getDatabaseService, _internalInjectDatabaseService } from './database-service.js'; // --------------------------------------------------------------------------- // Dynamic ESM resolution for services (no more .js shims needed!) // --------------------------------------------------------------------------- const ParameterResolver = await tryImport([ async () => { if (!process.env.VITEST) throw new Error('skip'); return class ParameterResolverStub { }; }, async () => (await import('auto-builder/dist/services/ParameterResolver.js')).ParameterResolver, async () => { const url = new URL('../../auto-builder/src/services/ParameterResolver.ts', import.meta.url); return (await import(url.href)).ParameterResolver; }, async () => { const abs = path.resolve(process.cwd(), 'dist/services/ParameterResolver.js'); return (await import(pathToFileURL(abs).href)).ParameterResolver; }, async () => { const src = resolveServicePath(fileURLToPath(import.meta.url), 'ParameterResolver.ts'); if (!src) throw new Error('not-found'); return (await import(pathToFileURL(src).href)).ParameterResolver; }, ]); export { ParameterResolver }; // Pagination utilities --------------------------------------------------------- export { convertToLimitOffset, calculatePaginationMeta, validatePaginationParams, createPaginationResponse, extractPaginationParams, convertLegacyPagination, buildApiPaginationParams, parseApiPaginationResponse, addStandardPagination, validateNodePagination, PAGINATION_NODE_DEFINITION, PAGINATION_SIZE_NODE_DEFINITION } from './pagination-utils.js'; // Pagination configuration export { PAGINATION_CONFIG, updatePaginationConfig, resetPaginationConfig } from './pagination.config.js';