diff --git a/docs/content/docs/ai/defining-tools.mdx b/docs/content/docs/ai/defining-tools.mdx index cc5780eaaf..aef99741c9 100644 --- a/docs/content/docs/ai/defining-tools.mdx +++ b/docs/content/docs/ai/defining-tools.mdx @@ -23,6 +23,9 @@ Just like in regular AI SDK tool definitions, tool in DurableAgent are called wi When you tool needs access to the full message history, you can access it via the `messages` property of the tool call context: ```typescript title="tools.ts" lineNumbers +import { Experimental_Agent as Agent } from "ai"; +import type { ModelMessage } from "ai"; + async function getWeather( { city }: { city: string }, { messages, toolCallId }: { messages: ModelMessage[], toolCallId: string }) { // [!code highlight] @@ -65,6 +68,9 @@ Tools can be implemented either at the step level or the workflow level, with di Tools can also combine both by starting out on the workflow level, and calling into steps for I/O operations, like so: ```typescript title="tools.ts" lineNumbers +import { sleep } from "workflow"; +import type { LanguageModel, ModelMessage } from "ai"; + // Step: handles I/O with retries async function performFetch(url: string) { "use step"; diff --git a/docs/content/docs/ai/index.mdx b/docs/content/docs/ai/index.mdx index 176db0e700..66de5531bb 100644 --- a/docs/content/docs/ai/index.mdx +++ b/docs/content/docs/ai/index.mdx @@ -123,6 +123,9 @@ The core code that makes all of this happen is quite simple. Here's a breakdown Our API route makes a simple call to [AI SDK's `Agent` class](https://ai-sdk.dev/docs/agents/overview), which is a simple wrapper around [AI SDK's `streamText` function](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text#streamtext). This is also where we pass tools to the agent. ```typescript title="app/api/chat/route.ts" lineNumbers +import { Experimental_Agent as Agent } from "ai"; +import type { LanguageModel } from "ai"; + export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json(); const agent = new Agent({ // [!code highlight] diff --git a/docs/content/docs/ai/message-queueing.mdx b/docs/content/docs/ai/message-queueing.mdx index 4cdaad58b2..ca02665fcc 100644 --- a/docs/content/docs/ai/message-queueing.mdx +++ b/docs/content/docs/ai/message-queueing.mdx @@ -32,6 +32,8 @@ If you just need basic multi-turn conversations where messages arrive between tu The `prepareStep` callback runs before each step in the agent loop. It receives the current state and can modify the messages sent to the model: ```typescript lineNumbers +import type { ModelMessage, LanguageModel } from "ai"; + interface PrepareStepInfo { model: string | (() => Promise); // Current model stepNumber: number; // 0-indexed step count diff --git a/docs/content/docs/ai/sleep-and-delays.mdx b/docs/content/docs/ai/sleep-and-delays.mdx index f3eb33415d..69abc1b912 100644 --- a/docs/content/docs/ai/sleep-and-delays.mdx +++ b/docs/content/docs/ai/sleep-and-delays.mdx @@ -162,6 +162,8 @@ Aside from providing `sleep()` as a tool, there are other use cases for Agents t When hitting API rate limits, use `RetryableError` with a delay: ```typescript lineNumbers +import { RetryableError } from "workflow"; + async function callRateLimitedAPI(endpoint: string) { "use step"; diff --git a/docs/content/docs/api-reference/workflow-ai/durable-agent.mdx b/docs/content/docs/api-reference/workflow-ai/durable-agent.mdx index 19e8ffde90..580b4b38a1 100644 --- a/docs/content/docs/api-reference/workflow-ai/durable-agent.mdx +++ b/docs/content/docs/api-reference/workflow-ai/durable-agent.mdx @@ -317,6 +317,8 @@ async function multiToolAgentWorkflow(userQuery: string) { ```typescript import { DurableAgent } from "@workflow/ai/agent"; +import { getWritable } from "workflow"; +import type { UIMessageChunk } from "ai"; import { z } from "zod"; async function searchProducts({ query }: { query: string }) { diff --git a/docs/content/docs/api-reference/workflow-api/get-run.mdx b/docs/content/docs/api-reference/workflow-api/get-run.mdx index ecf48c3dd6..a2ff7ff080 100644 --- a/docs/content/docs/api-reference/workflow-api/get-run.mdx +++ b/docs/content/docs/api-reference/workflow-api/get-run.mdx @@ -144,6 +144,8 @@ export async function POST(req: Request) { You can also target specific sleep calls by correlation ID: ```typescript lineNumbers +import { getRun } from "workflow/api"; + const run = getRun("my-run-id"); // @setup const { stoppedCount } = await run.wakeUp({ correlationIds: ["wait_abc123"], diff --git a/docs/content/docs/api-reference/workflow/define-hook.mdx b/docs/content/docs/api-reference/workflow/define-hook.mdx index 2d64078a93..ad0d697f30 100644 --- a/docs/content/docs/api-reference/workflow/define-hook.mdx +++ b/docs/content/docs/api-reference/workflow/define-hook.mdx @@ -193,6 +193,8 @@ export const approvalHook = defineHook({ Tokens are used to identify a specific hook and for resuming a hook. You can customize the token to be more specific to a use case. ```typescript lineNumbers +import { defineHook } from "workflow"; + const slackHook = defineHook<{ text: string; userId: string }>(); export async function slackBotWorkflow(channelId: string) { diff --git a/docs/content/docs/api-reference/workflow/get-writable.mdx b/docs/content/docs/api-reference/workflow/get-writable.mdx index 19680fc249..a82257bcd4 100644 --- a/docs/content/docs/api-reference/workflow/get-writable.mdx +++ b/docs/content/docs/api-reference/workflow/get-writable.mdx @@ -208,6 +208,7 @@ Here's a more complex example showing how you might stream AI chat responses: ```typescript lineNumbers import { getWritable } from "workflow"; import { generateId, streamText, type UIMessageChunk } from "ai"; +import type { ModelMessage } from "ai"; export async function chat(messages: ModelMessage[]) { "use workflow"; diff --git a/docs/content/docs/errors/hook-conflict.mdx b/docs/content/docs/errors/hook-conflict.mdx index e18091db9e..89bd1ab3e7 100644 --- a/docs/content/docs/errors/hook-conflict.mdx +++ b/docs/content/docs/errors/hook-conflict.mdx @@ -46,6 +46,8 @@ export async function processPayment() { **Solution:** Use unique tokens that include the run ID or other unique identifiers. ```typescript lineNumbers +import { createHook } from "workflow"; + export async function processPayment(orderId: string) { "use workflow"; @@ -60,6 +62,8 @@ export async function processPayment(orderId: string) { The safest approach is to let the Workflow runtime generate a unique token automatically: ```typescript lineNumbers +import { createHook } from "workflow"; + export async function processPayment() { "use workflow"; @@ -74,6 +78,7 @@ export async function processPayment() { When a hook conflict occurs, awaiting the hook will throw a `HookConflictError`. You can catch this error to handle the conflict gracefully: ```typescript lineNumbers +import { createHook } from "workflow"; import { HookConflictError } from "@workflow/errors"; export async function processPayment(orderId: string) { diff --git a/docs/content/docs/errors/webhook-invalid-respond-with-value.mdx b/docs/content/docs/errors/webhook-invalid-respond-with-value.mdx index 4eb470463a..dc341d324d 100644 --- a/docs/content/docs/errors/webhook-invalid-respond-with-value.mdx +++ b/docs/content/docs/errors/webhook-invalid-respond-with-value.mdx @@ -43,6 +43,8 @@ export async function webhookWorkflow() { **Solution:** Use `"manual"` or provide a `Response` object. ```typescript lineNumbers +import { createWebhook } from "workflow"; + // Fixed - use "manual" export async function webhookWorkflow() { "use workflow"; @@ -74,6 +76,8 @@ export async function webhookWorkflow() { **Solution:** Create a proper `Response` object. ```typescript lineNumbers +import { createWebhook } from "workflow"; + // Fixed - use Response constructor export async function webhookWorkflow() { "use workflow"; @@ -89,6 +93,8 @@ export async function webhookWorkflow() { ### Default Behavior (202 Response) ```typescript lineNumbers +import { createWebhook } from "workflow"; + // Returns 202 Accepted automatically const webhook = await createWebhook(); const request = await webhook; @@ -98,6 +104,8 @@ const request = await webhook; ### Manual Response ```typescript lineNumbers +import { createWebhook } from "workflow"; + // Manual response control const webhook = await createWebhook({ respondWith: "manual", @@ -120,6 +128,8 @@ await request.respondWith( ### Pre-defined Response ```typescript lineNumbers +import { createWebhook } from "workflow"; + // Immediate response const webhook = await createWebhook({ respondWith: new Response("Request received", { status: 200 }), diff --git a/docs/content/docs/errors/webhook-response-not-sent.mdx b/docs/content/docs/errors/webhook-response-not-sent.mdx index ae9011d0bd..15a95124a5 100644 --- a/docs/content/docs/errors/webhook-response-not-sent.mdx +++ b/docs/content/docs/errors/webhook-response-not-sent.mdx @@ -49,6 +49,8 @@ export async function webhookWorkflow() { **Solution:** Always call `request.respondWith()` when using manual response mode. ```typescript lineNumbers +import { createWebhook } from "workflow"; + // Fixed - response sent export async function webhookWorkflow() { "use workflow"; @@ -92,6 +94,8 @@ export async function webhookWorkflow() { **Solution:** Ensure all code paths send a response. ```typescript lineNumbers +import { createWebhook } from "workflow"; + // Fixed - response sent in all branches export async function webhookWorkflow() { "use workflow"; @@ -135,6 +139,8 @@ export async function webhookWorkflow() { **Solution:** Use try-catch to handle errors and send appropriate responses. ```typescript lineNumbers +import { createWebhook } from "workflow"; + // Fixed - error handling with response export async function webhookWorkflow() { "use workflow"; @@ -163,6 +169,8 @@ export async function webhookWorkflow() { If you don't need custom response control, consider using the default response mode which automatically returns a `202 Accepted` response: ```typescript lineNumbers +import { createWebhook } from "workflow"; + // Automatic 202 response - no manual response needed export async function webhookWorkflow() { "use workflow"; diff --git a/docs/content/docs/foundations/errors-and-retries.mdx b/docs/content/docs/foundations/errors-and-retries.mdx index 061425c139..2727b4a989 100644 --- a/docs/content/docs/foundations/errors-and-retries.mdx +++ b/docs/content/docs/foundations/errors-and-retries.mdx @@ -139,6 +139,35 @@ callApi.maxRetries = 5; // Retry up to 5 times on failure (6 total attempts) step can run up to 4 times total (1 initial attempt + 3 retries). +## Error Codes + +When a workflow run fails, the error may include a `code` that classifies the failure. You can access it programmatically via the `Run` class: + +```typescript lineNumbers +import { WorkflowRunFailedError } from "@workflow/errors"; +import { start } from "workflow/api"; + +const run = await start(myWorkflow, [input]); + +try { + const result = await run.returnValue; +} catch (err) { + if (WorkflowRunFailedError.is(err)) { + console.log(err.cause.code); // "USER_ERROR", "RUNTIME_ERROR", or undefined + console.log(err.cause.message); // The error message + } +} +``` + +| Code | Meaning | +| --- | --- | +| `USER_ERROR` | An error thrown in your workflow or step code (including propagated step failures like `FatalError`) | +| `RUNTIME_ERROR` | An internal runtime error such as a corrupted event log or missing data. If you see this, please [file an issue](https://github.com/vercel/workflow/issues) | + + + The error code is also available on the run entity via the CLI (`npx workflow inspect runs `) in the `error.code` field, and as an OTEL span attribute (`workflow.error.code`) for observability. + + ## Rolling Back Failed Steps When a workflow fails partway through, it can leave the system in an inconsistent state. diff --git a/docs/content/docs/foundations/streaming.mdx b/docs/content/docs/foundations/streaming.mdx index f1ae0b383d..9015d65fbb 100644 --- a/docs/content/docs/foundations/streaming.mdx +++ b/docs/content/docs/foundations/streaming.mdx @@ -164,6 +164,8 @@ Workflow functions must be deterministic to support replay. Since streams bypass For more on determinism and replay, see [Workflows and Steps](/docs/foundations/workflows-and-steps). ```typescript title="workflows/bad-example.ts" lineNumbers +import { getWritable } from "workflow"; + export async function badWorkflow() { "use workflow"; @@ -176,6 +178,8 @@ export async function badWorkflow() { ``` ```typescript title="workflows/good-example.ts" lineNumbers +import { getWritable } from "workflow"; + export async function goodWorkflow() { "use workflow"; @@ -501,6 +505,8 @@ If a lock is not released, the step function's HTTP request cannot terminate. Ev **Close streams when done:** ```typescript lineNumbers +import { getWritable } from "workflow"; + async function finalizeStream() { "use step"; diff --git a/packages/docs-typecheck/src/__tests__/docs.test.ts b/packages/docs-typecheck/src/__tests__/docs.test.ts index a1b586c79d..cb5ad9135d 100644 --- a/packages/docs-typecheck/src/__tests__/docs.test.ts +++ b/packages/docs-typecheck/src/__tests__/docs.test.ts @@ -4,7 +4,6 @@ import { fileURLToPath } from 'node:url'; import { globSync } from 'glob'; import { describe, expect, it } from 'vitest'; import { extractCodeSamples } from '../extractor.js'; -import { addInferredImports } from '../import-inference.js'; import { formatResult, typeCheckBatch } from '../type-checker.js'; import type { CodeSample, @@ -79,7 +78,11 @@ for (const relativeFile of allDocFiles) { if (sample.skipTypeCheck) { skippedSamples.push({ relativeFile, sample }); } else { - const processed = addInferredImports(sample); + const processed: ProcessedCodeSample = { + ...sample, + processedSource: sample.source, + addedImports: [], + }; allSamples.push({ relativeFile, sample, processed }); } } diff --git a/packages/docs-typecheck/src/docs-globals.d.ts b/packages/docs-typecheck/src/docs-globals.d.ts index 8bfa8e09af..4f7f01133c 100644 --- a/packages/docs-typecheck/src/docs-globals.d.ts +++ b/packages/docs-typecheck/src/docs-globals.d.ts @@ -172,4 +172,7 @@ declare global { const MAX_STEPS: number; const reportId: string; const userId: string; + + // Workflow placeholders used in examples + const myWorkflow: (...args: any[]) => Promise; } diff --git a/packages/docs-typecheck/src/import-inference.ts b/packages/docs-typecheck/src/import-inference.ts deleted file mode 100644 index bdcf062c31..0000000000 --- a/packages/docs-typecheck/src/import-inference.ts +++ /dev/null @@ -1,540 +0,0 @@ -import ts from 'typescript'; -import type { CodeSample, ProcessedCodeSample } from './types.js'; - -interface ImportMapping { - module: string; - isType?: boolean; - /** If set, import this name and alias it to the symbol name */ - importAs?: string; -} - -/** - * Mapping of known symbols to their source modules - */ -const SYMBOL_IMPORTS: Record = { - // From 'workflow' (re-exports from @workflow/core) - FatalError: { module: 'workflow' }, - RetryableError: { module: 'workflow' }, - createHook: { module: 'workflow' }, - createWebhook: { module: 'workflow' }, - defineHook: { module: 'workflow' }, - sleep: { module: 'workflow' }, - getStepMetadata: { module: 'workflow' }, - getWorkflowMetadata: { module: 'workflow' }, - getWritable: { module: 'workflow' }, - fetch: { module: 'workflow' }, - - // Types from 'workflow' - Hook: { module: 'workflow', isType: true }, - HookOptions: { module: 'workflow', isType: true }, - RequestWithResponse: { module: 'workflow', isType: true }, - Webhook: { module: 'workflow', isType: true }, - WebhookOptions: { module: 'workflow', isType: true }, - StepMetadata: { module: 'workflow', isType: true }, - WorkflowMetadata: { module: 'workflow', isType: true }, - TypedHook: { module: 'workflow', isType: true }, - WorkflowWritableStreamOptions: { module: 'workflow', isType: true }, - RetryableErrorOptions: { module: 'workflow', isType: true }, - - // From 'workflow/api' - start: { module: 'workflow/api' }, - getRun: { module: 'workflow/api' }, - runStep: { module: 'workflow/api' }, - resumeHook: { module: 'workflow/api' }, - resumeWebhook: { module: 'workflow/api' }, - getHookByToken: { module: 'workflow/api' }, - Run: { module: 'workflow/api' }, - - // Types from 'workflow/api' - Event: { module: 'workflow/api', isType: true }, - StartOptions: { module: 'workflow/api', isType: true }, - WorkflowRun: { module: 'workflow/api', isType: true }, - WorkflowReadableStreamOptions: { module: 'workflow/api', isType: true }, - - // From '@workflow/next' - withWorkflow: { module: '@workflow/next' }, - - // From '@workflow/ai' - createDurableAgent: { module: '@workflow/ai' }, - DurableAgent: { module: '@workflow/ai' }, // Class (both type and value) - - // Third-party - z: { module: 'zod' }, - - // AI SDK exports - Output: { module: 'ai' }, - Agent: { module: 'ai', importAs: 'Experimental_Agent' }, // AI SDK exports as Experimental_Agent - tool: { module: 'ai' }, - streamText: { module: 'ai' }, - generateText: { module: 'ai' }, - streamObject: { module: 'ai' }, - generateObject: { module: 'ai' }, - generateId: { module: 'ai' }, - convertToModelMessages: { module: 'ai' }, - createUIMessageStreamResponse: { module: 'ai' }, - UIMessage: { module: 'ai', isType: true }, - UIMessageChunk: { module: 'ai', isType: true }, - ModelMessage: { module: 'ai', isType: true }, - LanguageModel: { module: 'ai', isType: true }, -}; - -/** - * Finds all identifiers used in the source code - */ -function findUsedIdentifiers(sourceCode: string): Set { - const identifiers = new Set(); - - try { - const sourceFile = ts.createSourceFile( - 'sample.ts', - sourceCode, - ts.ScriptTarget.Latest, - true, - ts.ScriptKind.TS - ); - - function visit(node: ts.Node) { - if (ts.isIdentifier(node)) { - identifiers.add(node.text); - } - ts.forEachChild(node, visit); - } - - visit(sourceFile); - } catch { - // If parsing fails, fall back to regex-based extraction - const identifierRegex = /\b([A-Za-z_$][A-Za-z0-9_$]*)\b/g; - let match; - while ((match = identifierRegex.exec(sourceCode)) !== null) { - identifiers.add(match[1]); - } - } - - return identifiers; -} - -/** - * Finds identifiers that are declared locally in the source - */ -function findLocalDeclarations(sourceCode: string): Set { - const locals = new Set(); - - try { - const sourceFile = ts.createSourceFile( - 'sample.ts', - sourceCode, - ts.ScriptTarget.Latest, - true, - ts.ScriptKind.TS - ); - - function visit(node: ts.Node) { - // Variable declarations: const x = ..., let y = ... - if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) { - locals.add(node.name.text); - } - - // Function declarations: function foo() {} - if (ts.isFunctionDeclaration(node) && node.name) { - locals.add(node.name.text); - } - - // Class declarations: class Foo {} - if (ts.isClassDeclaration(node) && node.name) { - locals.add(node.name.text); - } - - // Parameters: (x, y) => ... - if (ts.isParameter(node) && ts.isIdentifier(node.name)) { - locals.add(node.name.text); - } - - // Type aliases: type Foo = ... - if (ts.isTypeAliasDeclaration(node)) { - locals.add(node.name.text); - } - - // Interface declarations: interface Foo {} - if (ts.isInterfaceDeclaration(node)) { - locals.add(node.name.text); - } - - // Enum declarations: enum Foo {} - if (ts.isEnumDeclaration(node)) { - locals.add(node.name.text); - } - - ts.forEachChild(node, visit); - } - - visit(sourceFile); - } catch { - // Ignore parse errors for incomplete snippets - } - - return locals; -} - -/** - * Extracts existing imports from the source code - */ -function findExistingImports(sourceCode: string): Set { - const imported = new Set(); - - try { - const sourceFile = ts.createSourceFile( - 'sample.ts', - sourceCode, - ts.ScriptTarget.Latest, - true, - ts.ScriptKind.TS - ); - - for (const statement of sourceFile.statements) { - if (ts.isImportDeclaration(statement)) { - const clause = statement.importClause; - if (clause) { - // Default import - if (clause.name) { - imported.add(clause.name.text); - } - // Named imports - if (clause.namedBindings) { - if (ts.isNamedImports(clause.namedBindings)) { - for (const element of clause.namedBindings.elements) { - imported.add(element.name.text); - } - } else if (ts.isNamespaceImport(clause.namedBindings)) { - imported.add(clause.namedBindings.name.text); - } - } - } - } - } - } catch { - // Ignore parse errors - } - - return imported; -} - -/** - * Generates import statements for missing symbols - */ -function generateImports(missingSymbols: Map): string[] { - // Group by module, tracking aliases separately - const byModule = new Map< - string, - { - values: string[]; - types: string[]; - aliases: Array<{ from: string; to: string }>; - } - >(); - - for (const [symbol, mapping] of missingSymbols) { - const existing = byModule.get(mapping.module) || { - values: [], - types: [], - aliases: [], - }; - - if (mapping.importAs) { - // This symbol needs to be imported with an alias - existing.aliases.push({ from: mapping.importAs, to: symbol }); - } else if (mapping.isType) { - existing.types.push(symbol); - } else { - existing.values.push(symbol); - } - byModule.set(mapping.module, existing); - } - - // Generate import statements - const imports: string[] = []; - - for (const [module, { values, types, aliases }] of byModule) { - const allSymbols: string[] = []; - - // Add value imports - allSymbols.push(...values.sort()); - - // Add aliased imports (e.g., "Experimental_Agent as Agent") - for (const { from, to } of aliases) { - allSymbols.push(`${from} as ${to}`); - } - - // Add type imports with 'type' prefix - for (const t of types.sort()) { - allSymbols.push(`type ${t}`); - } - - if (allSymbols.length > 0) { - imports.push(`import { ${allSymbols.join(', ')} } from '${module}';`); - } - } - - return imports.sort(); -} - -/** - * Processes a code sample to add inferred imports - */ -export function addInferredImports(sample: CodeSample): ProcessedCodeSample { - const { source } = sample; - - // Find all identifiers used - const usedIdentifiers = findUsedIdentifiers(source); - - // Find locally declared identifiers - const localDeclarations = findLocalDeclarations(source); - - // Find existing imports - const existingImports = findExistingImports(source); - - // Determine which symbols need to be imported - const missingSymbols = new Map(); - - for (const identifier of usedIdentifiers) { - // Skip if locally declared - if (localDeclarations.has(identifier)) continue; - - // Skip if already imported - if (existingImports.has(identifier)) continue; - - // Skip common globals/keywords - if (isBuiltinOrKeyword(identifier)) continue; - - // Check if we have a mapping for this symbol - const mapping = SYMBOL_IMPORTS[identifier]; - if (mapping) { - missingSymbols.set(identifier, mapping); - } - } - - // Generate import statements - const addedImports = generateImports(missingSymbols); - - // Prepend imports to source - const processedSource = - addedImports.length > 0 - ? addedImports.join('\n') + '\n\n' + source - : source; - - return { - ...sample, - processedSource, - addedImports, - }; -} - -/** - * Checks if an identifier is a built-in or keyword - */ -function isBuiltinOrKeyword(identifier: string): boolean { - const builtins = new Set([ - // JavaScript keywords - 'abstract', - 'arguments', - 'await', - 'boolean', - 'break', - 'byte', - 'case', - 'catch', - 'char', - 'class', - 'const', - 'continue', - 'debugger', - 'default', - 'delete', - 'do', - 'double', - 'else', - 'enum', - 'eval', - 'export', - 'extends', - 'false', - 'final', - 'finally', - 'float', - 'for', - 'function', - 'goto', - 'if', - 'implements', - 'import', - 'in', - 'instanceof', - 'int', - 'interface', - 'let', - 'long', - 'native', - 'new', - 'null', - 'package', - 'private', - 'protected', - 'public', - 'return', - 'short', - 'static', - 'super', - 'switch', - 'synchronized', - 'this', - 'throw', - 'throws', - 'transient', - 'true', - 'try', - 'typeof', - 'undefined', - 'var', - 'void', - 'volatile', - 'while', - 'with', - 'yield', - - // TypeScript keywords - 'any', - 'as', - 'asserts', - 'async', - 'bigint', - 'declare', - 'from', - 'get', - 'infer', - 'is', - 'keyof', - 'module', - 'namespace', - 'never', - 'of', - 'readonly', - 'require', - 'set', - 'string', - 'number', - 'symbol', - 'type', - 'unique', - 'unknown', - - // Common globals - 'console', - 'process', - 'global', - 'globalThis', - 'window', - 'document', - 'JSON', - 'Math', - 'Date', - 'Array', - 'Object', - 'String', - 'Number', - 'Boolean', - 'Symbol', - 'BigInt', - 'Map', - 'Set', - 'WeakMap', - 'WeakSet', - 'Promise', - 'Proxy', - 'Reflect', - 'Error', - 'TypeError', - 'ReferenceError', - 'SyntaxError', - 'RangeError', - 'URIError', - 'EvalError', - 'RegExp', - 'Function', - 'Uint8Array', - 'Int8Array', - 'Uint16Array', - 'Int16Array', - 'Uint32Array', - 'Int32Array', - 'Float32Array', - 'Float64Array', - 'ArrayBuffer', - 'DataView', - 'Buffer', - 'setTimeout', - 'setInterval', - 'clearTimeout', - 'clearInterval', - 'setImmediate', - 'clearImmediate', - 'queueMicrotask', - - // Web APIs - 'Request', - 'Response', - 'Headers', - 'URL', - 'URLSearchParams', - 'FormData', - 'Blob', - 'File', - 'ReadableStream', - 'WritableStream', - 'TransformStream', - 'TextEncoder', - 'TextDecoder', - 'AbortController', - 'AbortSignal', - 'crypto', - 'performance', - 'navigator', - 'location', - 'history', - 'localStorage', - 'sessionStorage', - 'indexedDB', - 'WebSocket', - 'EventSource', - 'Worker', - 'SharedWorker', - 'ServiceWorker', - 'Notification', - 'Intl', - 'atob', - 'btoa', - - // Common type names that don't need imports - 'Partial', - 'Required', - 'Readonly', - 'Record', - 'Pick', - 'Omit', - 'Exclude', - 'Extract', - 'NonNullable', - 'Parameters', - 'ConstructorParameters', - 'ReturnType', - 'InstanceType', - 'ThisParameterType', - 'OmitThisParameter', - 'ThisType', - 'Awaited', - 'Uppercase', - 'Lowercase', - 'Capitalize', - 'Uncapitalize', - ]); - - return builtins.has(identifier); -} diff --git a/packages/docs-typecheck/src/index.ts b/packages/docs-typecheck/src/index.ts index a93d938092..7f529ba7c6 100644 --- a/packages/docs-typecheck/src/index.ts +++ b/packages/docs-typecheck/src/index.ts @@ -1,5 +1,4 @@ export { extractCodeSamples, extractCodeSamplesFromFile } from './extractor.js'; -export { addInferredImports } from './import-inference.js'; export { formatResult, typeCheck, typeCheckBatch } from './type-checker.js'; export type { CodeSample,