Sync Helper
Sync Helper
The Sync Helper automatically injects TypeScript type definitions into SvelteKit's generated type files, providing type-safe access to validated, json(), and error() helpers in your route handlers.
What is generateAutoOpenApiTypes?
generateAutoOpenApiTypes is a function that runs during SvelteKit's sync command to inject type augmentations into .svelte-kit/types files.
Setup in svelte.config.js:
import { generateAutoOpenApiTypes } from 'sveltekit-auto-openapi/sync-helper';
generateAutoOpenApiTypes(); // Call before export
/** @type {import('@sveltejs/kit').Config} */
const config = {
// ... your config
};
export default config; What it does:
- Detects when
svelte-kit syncruns - Finds all routes with
_configexports - Injects
InjectedHelperstypes into corresponding$types.d.tsfiles - Provides autocomplete for
validated,json(), anderror()
Type Injection Mechanism
How It Works
The sync helper modifies SvelteKit's auto-generated type files:
Before sync:
// .svelte-kit/types/src/routes/api/users/$types.d.ts
import type * as Kit from '@sveltejs/kit';
type RouteParams = { };
type RouteId = '/api/users';
export type RequestEvent = Kit.RequestEvent<RouteParams, RouteId>;
export type RequestHandler = Kit.RequestHandler<RouteParams, RouteId>; After sync:
// .svelte-kit/types/src/routes/api/users/$types.d.ts
import type * as Kit from '@sveltejs/kit';
type RouteParams = { };
type RouteId = '/api/users';
// AUTO-GENERATED by sveltekit-auto-openapi - DO NOT MODIFY
import type { _config } from './+server';
import type { InjectedHelpers } from 'sveltekit-auto-openapi/types';
type AugmentedRequestEvent = Kit.RequestEvent<RouteParams, RouteId> & (
| InjectedHelpers<typeof _config, 'POST'>
| InjectedHelpers<typeof _config, 'GET'>
);
export type RequestEvent = AugmentedRequestEvent;
export type RequestHandler = (event: AugmentedRequestEvent) => Response | Promise<Response>;
// END AUTO-GENERATED What Gets Injected
The injected code adds three typed helpers to your RequestEvent:
1. validated Property
Contains all validated request data:
{
validated: {
body: T; // Validated request body
query: T; // Validated query parameters
pathParams: T; // Validated path parameters
headers: T; // Validated headers
cookies: T; // Validated cookies
}
} Types are extracted from your _config schemas.
2. json() Helper
Type-safe JSON response function:
json(data: SuccessResponseType): Response The data parameter is type-checked against your 2XX response schemas.
3. error() Helper
Type-safe error function:
error(status: number, body: ErrorResponseType): never The body parameter is type-checked against your 4XX/5XX response schemas.
How Sync Works
On Initial Build
When you run bunx svelte-kit sync:
- Discover routes: Finds all
+server.tsfiles with_configexports - Map to types: Locates corresponding
.svelte-kit/types/.../$types.d.tsfiles - Inject types: Modifies each types file to add
InjectedHelpers - Write files: Saves modified types back to disk
On File Changes
When you modify a route file:
- Detect change: Plugin's HMR hook detects file modification
- Check for _config: Determines if route has
_configexport - Update types: Re-runs sync for just that file
- Restore if removed: If
_configis removed, restores original types
Type Safety Flow
Your _config export
↓
RouteConfig type validates structure
↓
Sync helper reads _config
↓
Extracts HTTP methods
↓
Generates InjectedHelpers<typeof _config, Method>
↓
Injects into $types.d.ts
↓
TypeScript provides autocomplete Internal API
_syncAllTypes()
Syncs all routes with _config exports:
export async function _syncAllTypes(): Promise<void> {
// Find all +server.ts files
const serverFiles = await glob('src/routes/**/+server.ts');
for (const file of serverFiles) {
// Check if has _config
const hasConfig = await checkForConfig(file);
if (hasConfig) {
await _syncFileTypes(file);
}
}
} _syncFileTypes(filePath)
Syncs a specific route file:
export async function _syncFileTypes(filePath: string): Promise<void> {
// Extract methods from _config
const methods = await extractMethods(filePath);
// Find corresponding types file
const typesPath = getTypesPath(filePath);
// Modify types file
await modifyTypesFile(typesPath, methods);
} modifyTypesFile(typesPath, methods)
Uses ts-morph to modify the TypeScript file:
async function modifyTypesFile(
typesPath: string,
methods: string[]
): Promise<void> {
const project = new Project();
const sourceFile = project.addSourceFileAtPath(typesPath);
// Remove previous AUTO-GENERATED section
removePreviousInjection(sourceFile);
// Find RouteId type
const routeIdType = sourceFile.getTypeAlias('RouteId');
if (routeIdType) {
// Add imports
sourceFile.addImportDeclaration({
moduleSpecifier: './+server',
namedImports: [{ name: '_config' }],
isTypeOnly: true
});
sourceFile.addImportDeclaration({
moduleSpecifier: 'sveltekit-auto-openapi/types',
namedImports: [{ name: 'InjectedHelpers' }],
isTypeOnly: true
});
// Build union type for all methods
const unionParts = methods.map(
m => `InjectedHelpers<typeof _config, '${m}'>`
);
// Add augmented type
sourceFile.addTypeAlias({
name: 'AugmentedRequestEvent',
type: `Kit.RequestEvent<RouteParams, RouteId> & (${unionParts.join(' | ')})`
});
// Replace exports
replaceRequestEventExport(sourceFile);
}
await sourceFile.save();
} Troubleshooting
Types Not Updating
Problem: Changes to _config don't reflect in types
Solutions:
Run sync manually:
bunx svelte-kit syncbashRestart TypeScript server in your IDE:
- VS Code: Cmd+Shift+P → "TypeScript: Restart TS Server"
Clear and rebuild:
rm -rf .svelte-kit bunx svelte-kit syncbash
Types Not Found
Problem: validated, json(), error() not available
Solutions:
Check
_configis exported:export const _config = { /* ... */ } satisfies RouteConfig;typescriptVerify
generateAutoOpenApiTypes()is insvelte.config.jsCheck types file exists:
ls .svelte-kit/types/src/routes/your-route/\$types.d.tsbash
Type Conflicts
Problem: TypeScript errors about conflicting types
Solutions:
Check for multiple
_configexports in the same fileEnsure
_configusessatisfies RouteConfig:export const _config = { /* ... */ } satisfies RouteConfig;typescriptRemove manual type augmentations that might conflict
Sync Not Running
Problem: Types never get injected
Solutions:
Check
svelte.config.jshas the call:generateAutoOpenApiTypes(); // Before exportjavascriptVerify you're running
svelte-kit sync:bunx svelte-kit syncbashCheck console for errors during sync
Advanced Usage
Custom Type Augmentation
If you need additional type augmentations:
// src/app.d.ts
import type { InjectedHelpers } from 'sveltekit-auto-openapi/types';
declare global {
namespace App {
interface Locals {
user?: User;
}
}
} Conditional Sync
Only sync specific routes:
// Custom sync helper
import { _syncFileTypes } from 'sveltekit-auto-openapi/sync-helper';
const routesToSync = [
'src/routes/api/users/+server.ts',
'src/routes/api/posts/+server.ts'
];
for (const route of routesToSync) {
await _syncFileTypes(route);
} Manual Sync Trigger
Trigger sync programmatically:
import { _syncAllTypes } from 'sveltekit-auto-openapi/sync-helper';
// After modifying routes
await _syncAllTypes();
console.log('Types synced!'); Performance
Build Time Impact
- First sync: 100-500ms depending on route count
- Incremental sync: 10-50ms per file
- No runtime cost: Types are erased at runtime
When Sync Runs
Sync only runs when:
svelte-kit synccommand executes- Route files with
_configchange (HMR) - SvelteKit build process runs
It does NOT run:
- On every file save
- For routes without
_config - At runtime
Best Practices
Always Use satisfies
Ensure type checking with satisfies:
// ✅ Good
export const _config = {
openapiOverride: { /* ... */ }
} satisfies RouteConfig;
// ❌ Bad - no type checking
export const _config = {
openapiOverride: { /* ... */ }
}; Don't Modify Generated Types
Never manually edit .svelte-kit/types files:
// ❌ Don't do this - will be overwritten
// .svelte-kit/types/src/routes/api/users/$types.d.ts
export type RequestEvent = MyCustomType; Keep _config in Same File
Don't import _config from elsewhere:
// ❌ Bad - sync won't detect
import { _config } from './config';
export { _config };
// ✅ Good - define in route file
export const _config = { /* ... */ } satisfies RouteConfig; Related Documentation
- Type System - Type utilities and helpers
- Route Configuration - Defining
_config - Plugin Configuration - Plugin setup