@luckystack/devkit 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/AGENTS.md +9 -0
  2. package/CHANGELOG.md +9 -0
  3. package/README.md +2 -37
  4. package/dist/cli/validateDeploy.d.ts +2 -0
  5. package/dist/functionRegistry.d.ts +72 -0
  6. package/dist/hotReload.d.ts +1 -0
  7. package/dist/importDependencyGraph.d.ts +2 -0
  8. package/dist/index.d.ts +15 -280
  9. package/dist/index.js +551 -424
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal/mapUtils.d.ts +2 -0
  12. package/dist/loader.d.ts +11 -0
  13. package/dist/prismaClientCheck.d.ts +19 -0
  14. package/dist/routeConventions.d.ts +20 -0
  15. package/dist/routeNamingValidation.d.ts +46 -0
  16. package/dist/routingRules.d.ts +62 -0
  17. package/dist/runtimeTypeResolver.d.ts +15 -0
  18. package/dist/supervisor.d.ts +25 -0
  19. package/dist/templateInjector.d.ts +60 -0
  20. package/dist/templateRegistry.d.ts +78 -0
  21. package/dist/typeMap/apiMeta.d.ts +42 -0
  22. package/dist/typeMap/discovery.d.ts +3 -0
  23. package/dist/typeMap/emitterArtifacts.d.ts +94 -0
  24. package/dist/typeMap/extractionDiagnostics.d.ts +16 -0
  25. package/dist/typeMap/extractors.d.ts +18 -0
  26. package/dist/typeMap/functionsMeta.d.ts +5 -0
  27. package/dist/typeMap/routeMeta.d.ts +6 -0
  28. package/dist/typeMap/tsApi.d.ts +12 -0
  29. package/dist/typeMap/tsProgram.d.ts +41 -0
  30. package/dist/typeMap/typeContext.d.ts +21 -0
  31. package/dist/typeMap/zodEmitter.d.ts +8 -0
  32. package/dist/typeMapGenerator.d.ts +5 -0
  33. package/dist/validateDeploy.d.ts +25 -0
  34. package/docs/cli.md +3 -243
  35. package/docs/hot-reload.md +4 -362
  36. package/docs/loader-pipeline.md +3 -322
  37. package/docs/runtime-type-resolver.md +3 -256
  38. package/docs/supervisor.md +3 -290
  39. package/docs/template-customization.md +2 -133
  40. package/docs/ts-program-cache.md +4 -197
  41. package/docs/type-map-generation.md +5 -418
  42. package/package.json +5 -5
  43. package/CLAUDE.md +0 -135
@@ -0,0 +1,2 @@
1
+ export declare const getOrInit: <K, V>(map: Map<K, V>, key: K, factory: () => V) => V;
2
+ export declare const mustGet: <K, V>(map: Map<K, V>, key: K, label: string) => V;
@@ -0,0 +1,11 @@
1
+ export declare const devApis: Record<string, unknown>;
2
+ export declare const devSyncs: Record<string, unknown>;
3
+ export declare const devFunctions: Record<string, unknown>;
4
+ export declare const initializeAll: () => Promise<void>;
5
+ export declare const initializeApis: () => Promise<void>;
6
+ export declare const upsertApiFromFile: (filePath: string) => Promise<void>;
7
+ export declare const removeApiFromFile: (filePath: string) => void;
8
+ export declare const initializeSyncs: () => Promise<void>;
9
+ export declare const upsertSyncFromFile: (filePath: string) => Promise<void>;
10
+ export declare const removeSyncFromFile: (filePath: string) => void;
11
+ export declare const initializeFunctions: () => Promise<void>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * True when a Prisma schema exists in the consumer project but the generated
3
+ * client output is absent — i.e. the consumer has not run `prisma generate`
4
+ * yet. This is the only condition under which we auto-generate (or surface the
5
+ * "run prisma:generate" hint), so an unrelated type-map failure never triggers
6
+ * the Prisma-specific path.
7
+ */
8
+ export declare const isPrismaClientMissing: () => boolean;
9
+ /**
10
+ * Runs `prisma generate` once. `prisma generate` only reads the schema —
11
+ * it needs NO database credentials — so this is safe to run on dev boot without
12
+ * any `.env` loading. Resolves to the child's exit code (0 on success). Spawn
13
+ * failures (ENOENT/EACCES) surface through the `tryCatch` tuple, not a throw.
14
+ *
15
+ * Uses the local `node_modules/.bin/prisma` binary directly (shell: false) to
16
+ * avoid shell invocation on Windows. Falls back to `npx prisma` with
17
+ * shell: false when the local binary is absent (e.g. prisma not yet installed).
18
+ */
19
+ export declare const runPrismaGenerate: () => Promise<[Error | null, number | null]>;
@@ -0,0 +1,20 @@
1
+ export declare const API_VERSION_TOKEN_REGEX: RegExp;
2
+ export declare const SYNC_VERSION_TOKEN_REGEX: RegExp;
3
+ export declare const API_VERSIONED_FILE_REGEX: RegExp;
4
+ export declare const SYNC_SERVER_VERSIONED_FILE_REGEX: RegExp;
5
+ export declare const SYNC_CLIENT_VERSIONED_FILE_REGEX: RegExp;
6
+ export declare const SYNC_VERSIONED_FILE_REGEX: RegExp;
7
+ export declare const ROUTE_NAMING_RULES: {
8
+ readonly api: '<name>_v<number>.ts';
9
+ readonly syncServer: '<name>_server_v<number>.ts';
10
+ readonly syncClient: '<name>_client_v<number>.ts';
11
+ };
12
+ export declare const ROUTE_NAMING_EXAMPLES: {
13
+ readonly api: 'updateUser_v1.ts';
14
+ readonly syncServer: 'updateCounter_server_v1.ts';
15
+ readonly syncClient: 'updateCounter_client_v1.ts';
16
+ };
17
+ export declare const isVersionedApiFileName: (fileName: string) => boolean;
18
+ export declare const isVersionedSyncFileName: (fileName: string) => boolean;
19
+ export declare const isVersionedSyncServerFileName: (fileName: string) => boolean;
20
+ export declare const isVersionedSyncClientFileName: (fileName: string) => boolean;
@@ -0,0 +1,46 @@
1
+ export interface RouteNamingIssue {
2
+ kind: 'api' | 'sync';
3
+ filePath: string;
4
+ reason: string;
5
+ expected: string;
6
+ }
7
+ export interface DuplicateRouteKeyIssue {
8
+ kind: 'api' | 'sync';
9
+ routeKey: string;
10
+ filePaths: string[];
11
+ }
12
+ export declare const isInsidePrivateRouteSubfolder: (fullPath: string) => boolean;
13
+ export declare const isRouteSurfaceFile: (fullPath: string) => boolean;
14
+ export declare const collectInvalidRouteNamingIssues: (srcDir: string) => RouteNamingIssue[];
15
+ export declare const collectDuplicateNormalizedRouteKeyIssues: (srcDir: string) => DuplicateRouteKeyIssue[];
16
+ export declare const formatRouteNamingIssues: ({ issues, context, }: {
17
+ issues: RouteNamingIssue[];
18
+ context: string;
19
+ }) => string;
20
+ export declare const formatDuplicateRouteKeyIssues: ({ issues, context, }: {
21
+ issues: DuplicateRouteKeyIssue[];
22
+ context: string;
23
+ }) => string;
24
+ export declare const assertValidRouteNaming: ({ srcDir, context, }: {
25
+ srcDir: string;
26
+ context: string;
27
+ }) => void;
28
+ export declare const assertNoDuplicateNormalizedRouteKeys: ({ srcDir, context, }: {
29
+ srcDir: string;
30
+ context: string;
31
+ }) => void;
32
+ export interface DuplicatePageRouteIssue {
33
+ /** Computed route after invisible-parent stripping (e.g. `/admin`). */
34
+ route: string;
35
+ /** All page.tsx files that resolve to this same route. */
36
+ filePaths: string[];
37
+ }
38
+ export declare const collectDuplicatePageRoutes: (srcDir: string) => DuplicatePageRouteIssue[];
39
+ export declare const formatDuplicatePageRouteIssues: ({ issues, context, }: {
40
+ issues: DuplicatePageRouteIssue[];
41
+ context: string;
42
+ }) => string;
43
+ export declare const assertNoDuplicatePageRoutes: ({ srcDir, context, }: {
44
+ srcDir: string;
45
+ context: string;
46
+ }) => void;
@@ -0,0 +1,62 @@
1
+ export interface RoutingRules {
2
+ /** Folder name that marks an API directory. Default: `_api`. */
3
+ apiMarker: string;
4
+ /** Folder name that marks a sync directory. Default: `_sync`. */
5
+ syncMarker: string;
6
+ /** Suffix matcher for API files: must end with `_v<number>.ts`. */
7
+ apiVersionRegex: RegExp;
8
+ /** Suffix matcher for sync server files: must end with `_server_v<number>.ts`. */
9
+ syncServerVersionRegex: RegExp;
10
+ /** Suffix matcher for sync client files: must end with `_client_v<number>.ts`. */
11
+ syncClientVersionRegex: RegExp;
12
+ /** Combined sync regex (server or client). */
13
+ syncVersionRegex: RegExp;
14
+ /**
15
+ * Predicate called for each candidate file/folder during discovery.
16
+ * Return `true` to skip. Path is provided as a forward-slash relative
17
+ * string from the workspace root (e.g. `src/dashboard/__tests__/foo_v1.ts`).
18
+ */
19
+ ignore: (relativePath: string) => boolean;
20
+ /**
21
+ * Single-character prefix that marks a folder as **invisible-parent** for
22
+ * page routing: `src/_housing/renting/page.tsx` resolves to `/renting`
23
+ * (the `_housing` segment is stripped from the URL). A `page.tsx` placed
24
+ * directly inside an `_<name>` folder is invalid (no URL segment left).
25
+ *
26
+ * Default: `'_'`. Override only if you need a different prefix scheme.
27
+ */
28
+ privateFolderPrefix: string;
29
+ /**
30
+ * Folder names that are reserved for framework-internal use and may NEVER
31
+ * host a `page.tsx`. Scaffold + page-discovery emit a hard error when a
32
+ * page is placed inside one. Extend (do not replace) the defaults if you
33
+ * add your own internal folder convention.
34
+ *
35
+ * Defaults: `_api`, `_sync`, `_function(s)`, `_component(s)`, `_provider(s)`,
36
+ * `_locale(s)`, `_socket(s)`, `_shared`, `_server`. The semantic markers
37
+ * (`_api`, `_sync`) are also reserved by the API/sync routers.
38
+ */
39
+ scaffoldIgnoredFolders: string[];
40
+ /**
41
+ * Optional predicate. Return `true` for a given absolute file path to
42
+ * disable template injection entirely for that file. Useful when a
43
+ * consumer wants to opt some part of the tree out of the scaffold
44
+ * (e.g. `/src/migrations/**` lives by hand). The argument is the
45
+ * absolute path the chokidar watcher provides; the predicate is
46
+ * called BEFORE the `isInApiFolder` / `isPageFile` checks fire.
47
+ */
48
+ disableTemplateInjection?: (filePath: string) => boolean;
49
+ }
50
+ export declare const registerRoutingRules: (overrides: Partial<RoutingRules>) => RoutingRules;
51
+ export declare const getRoutingRules: () => RoutingRules;
52
+ export declare const apiMarkerSegment: () => string;
53
+ export declare const syncMarkerSegment: () => string;
54
+ export declare const isApiFileName: (fileName: string) => boolean;
55
+ export declare const isSyncServerFileName: (fileName: string) => boolean;
56
+ export declare const isSyncClientFileName: (fileName: string) => boolean;
57
+ export declare const isSyncFileName: (fileName: string) => boolean;
58
+ export declare const isRouteTestFile: (fileNameOrPath: string) => boolean;
59
+ export declare const isNonRouteDirectory: (directoryName: string) => boolean;
60
+ import { type PagePathValidationResult as CoreResult } from '@luckystack/core';
61
+ export type PagePathValidationResult = CoreResult;
62
+ export declare const validatePagePath: (srcRelativePath: string) => PagePathValidationResult;
@@ -0,0 +1,15 @@
1
+ type ResolveResult = {
2
+ status: 'success';
3
+ typeText: string;
4
+ } | {
5
+ status: 'error';
6
+ message: string;
7
+ };
8
+ export declare const isUnresolvedTypeMarker: (value: string) => boolean;
9
+ export declare const getUnresolvedTypeMessage: (value: string) => string;
10
+ export declare const clearRuntimeTypeResolverCache: () => void;
11
+ export declare const resolveRuntimeTypeText: ({ typeText, filePath, }: {
12
+ typeText: string;
13
+ filePath?: string;
14
+ }) => ResolveResult;
15
+ export {};
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ export type SupervisorRuntime = 'node' | 'bun';
3
+ export interface ChildSpawnSpec {
4
+ command: string;
5
+ args: string[];
6
+ runtime: SupervisorRuntime;
7
+ }
8
+ export interface ResolveChildSpawnInput {
9
+ isBun: boolean;
10
+ execPath: string;
11
+ npmUserAgent: string | undefined;
12
+ npmExecPath: string | undefined;
13
+ tsxCliPath: string;
14
+ tsconfigServerArgs: string[];
15
+ entry: string;
16
+ fileExists: (candidate: string) => boolean;
17
+ }
18
+ export type ResolveChildSpawnResult = {
19
+ ok: true;
20
+ spec: ChildSpawnSpec;
21
+ } | {
22
+ ok: false;
23
+ message: string;
24
+ };
25
+ export declare const resolveChildSpawn: ({ isBun, execPath, npmUserAgent, npmExecPath, tsxCliPath: tsxCli, tsconfigServerArgs: tsconfigArgs, entry, fileExists, }: ResolveChildSpawnInput) => ResolveChildSpawnResult;
@@ -0,0 +1,60 @@
1
+ export declare const isEmptyFile: (filePath: string) => boolean;
2
+ export declare const isInApiFolder: (filePath: string) => boolean;
3
+ export declare const isInSyncFolder: (filePath: string) => boolean;
4
+ export declare const isPageFile: (filePath: string) => boolean;
5
+ export declare const isSyncServerFile: (filePath: string) => boolean;
6
+ export declare const isSyncClientFile: (filePath: string) => boolean;
7
+ export declare const getRouteFilenameValidationMessage: (filePath: string) => string | null;
8
+ /**
9
+ * Get the paired sync file path (server -> client or client -> server)
10
+ */
11
+ export declare const getPairedSyncFile: (filePath: string) => string | null;
12
+ /**
13
+ * Check if a paired sync file exists
14
+ */
15
+ export declare const hasPairedFile: (filePath: string) => boolean;
16
+ /**
17
+ * Extract page path from a sync file path (e.g., "examples" from "src/examples/_sync/test_server_v1.ts")
18
+ */
19
+ export declare const extractSyncPagePath: (filePath: string) => string;
20
+ /**
21
+ * Extract sync name from a sync file path (e.g., "test" from "src/examples/_sync/test_server_v1.ts")
22
+ */
23
+ export declare const extractSyncName: (filePath: string) => string;
24
+ /**
25
+ * Extract clientInput type body from a sync file's SyncParams interface
26
+ * Returns the content between the braces of clientInput: { ... }
27
+ */
28
+ export declare const extractClientInputFromFile: (filePath: string) => string | null;
29
+ /**
30
+ * Extract clientInput type from the generated apiTypes.generated.ts file
31
+ * Used when the server file is already deleted but we need to migrate types to client
32
+ */
33
+ export declare const extractClientInputFromGeneratedTypes: (pagePath: string, syncName: string) => string | null;
34
+ /**
35
+ * Calculate the relative path prefix (e.g., '../../../') to reach project root from a file
36
+ * @param filePath - Absolute or relative path to the file
37
+ * @returns The relative path prefix to reach project root
38
+ */
39
+ export declare const calculateRelativePath: (filePath: string) => string;
40
+ export declare const injectTemplate: (filePath: string) => Promise<boolean>;
41
+ export declare const shouldInjectTemplate: (filePath: string, options?: {
42
+ isNewFile?: boolean;
43
+ }) => boolean;
44
+ /**
45
+ * Update a client file to use the paired template (imports types from generated file)
46
+ * Called when a _server.ts is created and _client.ts already exists
47
+ * PRESERVES user's main function code!
48
+ */
49
+ export declare const updateClientFileForPairedServer: (clientFilePath: string) => Promise<boolean>;
50
+ /**
51
+ * Update a client file when the paired server file is deleted
52
+ * Preserves user's main function code while:
53
+ * - Inlining clientInput types
54
+ * - Removing serverOutput from SyncParams and main function params
55
+ */
56
+ export declare const updateClientFileForDeletedServer: (clientFilePath: string, clientInputTypes: string) => Promise<boolean>;
57
+ /**
58
+ * Inject server template with pre-filled clientInput types (from existing client file)
59
+ */
60
+ export declare const injectServerTemplateWithClientInput: (serverFilePath: string, clientInputTypes: string) => Promise<boolean>;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The six template kinds the framework ships out of the box. Consumers may
3
+ * register additional kinds (e.g. `page_marketing`) via `registerTemplateKind`.
4
+ */
5
+ export type BuiltInTemplateKind = 'api' | 'sync_server' | 'sync_client_paired' | 'sync_client_standalone' | 'page_plain' | 'page_dashboard';
6
+ export type TemplateKind = BuiltInTemplateKind | (string & {});
7
+ export declare const BUILT_IN_TEMPLATE_KINDS: readonly BuiltInTemplateKind[];
8
+ export declare const BUILT_IN_TEMPLATE_FILENAMES: Record<BuiltInTemplateKind, string>;
9
+ /**
10
+ * Structural classification of the file an injection is being computed for.
11
+ * `templateInjector.ts` derives this from the folder + filename conventions
12
+ * (controlled separately via `registerRoutingRules`). Selection rules match
13
+ * against it to choose a template kind.
14
+ */
15
+ export interface TemplateMatchContext {
16
+ /** Absolute path of the file being created. */
17
+ filePath: string;
18
+ /** Structural kind derived from the route conventions. */
19
+ fileKind: 'api' | 'sync_server' | 'sync_client' | 'page';
20
+ /** For `sync_client`: whether a paired `_server_v<N>.ts` exists on disk. */
21
+ hasPairedServer: boolean;
22
+ /** Path relative to `src/` (forward slashes), or `null` if outside src. */
23
+ srcRelativePath: string | null;
24
+ }
25
+ /** A single template-selection rule. First matching rule (by priority) wins. */
26
+ export interface TemplateRule {
27
+ kind: TemplateKind;
28
+ match: (ctx: TemplateMatchContext) => boolean;
29
+ /** Higher runs first. Built-in defaults use 10 (specific) / 0 (catch-all). */
30
+ priority: number;
31
+ }
32
+ export interface RegisterTemplateKindOptions {
33
+ /** Predicate deciding when this kind is chosen. */
34
+ match: (ctx: TemplateMatchContext) => boolean;
35
+ /** Optional inline template body (same as calling `registerTemplate`). */
36
+ content?: string;
37
+ /** Higher runs first. Defaults to 100 so consumer kinds beat the built-ins. */
38
+ priority?: number;
39
+ }
40
+ export declare const DEFAULT_DASHBOARD_PATH_PATTERN: RegExp;
41
+ /**
42
+ * Override the template body for a given kind. Subsequent injections emit the
43
+ * supplied content with the standard `{{REL_PATH}}` / `{{PAGE_PATH}}` /
44
+ * `{{SYNC_NAME}}` placeholder substitution. Resolution order in the injector
45
+ * is: consumer file (`.luckystack/templates/<kind>.template.*`) → this
46
+ * override → bundled disk template.
47
+ */
48
+ export declare const registerTemplate: (kind: TemplateKind, content: string) => void;
49
+ /** Read the registered content override for a kind, or `null` when none. */
50
+ export declare const getRegisteredTemplate: (kind: TemplateKind) => string | null;
51
+ /** Drop every content override. Test-only. */
52
+ export declare const clearTemplateOverrides: () => void;
53
+ /** Diagnostic: kinds that currently have a content override. */
54
+ export declare const listRegisteredTemplateKinds: () => readonly TemplateKind[];
55
+ /**
56
+ * Register a selection rule. Rules are evaluated by descending `priority`,
57
+ * ties broken by descending registration order (so a later registration —
58
+ * e.g. a consumer overlay — beats an earlier same-priority default).
59
+ */
60
+ export declare const registerTemplateRule: (rule: TemplateRule) => void;
61
+ /**
62
+ * Register a brand-new template kind: its selection predicate plus (optionally)
63
+ * its inline content. Equivalent to `registerTemplateRule` + `registerTemplate`
64
+ * in one call. Default priority 100 so custom kinds win over the built-ins.
65
+ */
66
+ export declare const registerTemplateKind: (kind: TemplateKind, options: RegisterTemplateKindOptions) => void;
67
+ /** Drop every selection rule (including the built-in defaults). */
68
+ export declare const clearTemplateRules: () => void;
69
+ /** Read the active rules in evaluation order (priority desc, then newest first). */
70
+ export declare const getTemplateRules: () => readonly TemplateRule[];
71
+ /** Evaluate the active rules against a context; returns the first matching kind. */
72
+ export declare const resolveTemplateKind: (ctx: TemplateMatchContext) => TemplateKind | null;
73
+ export declare const registerDefaultTemplateRules: () => void;
74
+ /**
75
+ * Test-only: clear rules + content overrides AND re-arm the defaults guard so
76
+ * `registerDefaultTemplateRules()` can repopulate a clean baseline.
77
+ */
78
+ export declare const resetTemplateRegistryForTests: () => void;
@@ -0,0 +1,42 @@
1
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
2
+ export declare const extractHttpMethod: (filePath: string, apiName: string) => HttpMethod;
3
+ export declare const extractRateLimit: (filePath: string) => number | false | undefined;
4
+ /**
5
+ * Reads the `export const validation` declaration from an API/sync source
6
+ * file. Supports `'strict'`, `'relaxed'`, and `{ input: 'skip' | 'strict' }`.
7
+ * Returns undefined when the export is absent (consumer hasn't opted out).
8
+ */
9
+ export type ApiValidationMode = 'strict' | 'relaxed' | {
10
+ input: 'skip' | 'strict';
11
+ };
12
+ export declare const extractValidation: (filePath: string) => ApiValidationMode | undefined;
13
+ /**
14
+ * AST-extracted JSDoc `@docs` metadata for a route file. Parsed from JSDoc
15
+ * blocks attached to top-level statements (typically the `main` export).
16
+ *
17
+ * Convention (matches docs-ui renderer in `packages/docs-ui/src/docsHtml.ts`):
18
+ *
19
+ * /\*\*
20
+ * * Description sentence.
21
+ * * @docs owner @mathijs
22
+ * * @docs tags admin, internal, deprecated-soon
23
+ * * @docs deprecated use api/billing/getInvoice/v2 instead
24
+ * *\/
25
+ * export const main = async (...) => {...};
26
+ *
27
+ * `@docs deprecated` without a reason -> `true` (renders as red "deprecated"
28
+ * badge without explanation). With a reason -> `string` (renders the
29
+ * explanation). `@docs tags` is comma-split + trimmed. Unknown sub-keys are
30
+ * silently ignored so future tags don't break the parser.
31
+ */
32
+ export interface DocsMeta {
33
+ owner?: string;
34
+ tags?: string[];
35
+ deprecated?: string | true;
36
+ }
37
+ export declare const extractDocsMeta: (filePath: string) => DocsMeta | undefined;
38
+ export declare const extractAuth: (filePath: string) => {
39
+ login: boolean;
40
+ additional?: Record<string, unknown>[];
41
+ hasAdditional: boolean;
42
+ };
@@ -0,0 +1,3 @@
1
+ export declare const findAllApiFiles: (srcDir: string) => string[];
2
+ export declare const findAllSyncServerFiles: (srcDir: string) => string[];
3
+ export declare const findAllSyncClientFiles: (srcDir: string) => string[];
@@ -0,0 +1,94 @@
1
+ export interface DocsMetaSnapshot {
2
+ owner?: string;
3
+ tags?: string[];
4
+ deprecated?: string | true;
5
+ }
6
+ export interface ApiTypeEntry {
7
+ input: string;
8
+ output: string;
9
+ stream: string;
10
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
11
+ rateLimit: number | false | undefined;
12
+ auth: unknown;
13
+ version: string;
14
+ meta?: DocsMetaSnapshot;
15
+ }
16
+ interface ApiDocsEntry {
17
+ page: string;
18
+ name: string;
19
+ version: string;
20
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
21
+ input: string;
22
+ output: string;
23
+ stream: string;
24
+ rateLimit: number | false | undefined;
25
+ auth: unknown;
26
+ path: string;
27
+ meta?: DocsMetaSnapshot;
28
+ }
29
+ interface SyncDocsEntry {
30
+ page: string;
31
+ name: string;
32
+ version: string;
33
+ clientInput: string;
34
+ serverOutput: string;
35
+ clientOutput: string;
36
+ serverStream: string;
37
+ clientStream: string;
38
+ path: string;
39
+ meta?: DocsMetaSnapshot;
40
+ }
41
+ export interface GeneratedDocsData {
42
+ apis: Record<string, ApiDocsEntry[]>;
43
+ syncs: Record<string, SyncDocsEntry[]>;
44
+ }
45
+ export interface SyncTypeEntry {
46
+ clientInput: string;
47
+ serverOutput: string;
48
+ clientOutput: string;
49
+ serverStream: string;
50
+ clientStream: string;
51
+ version: string;
52
+ hasServer: boolean;
53
+ hasClient: boolean;
54
+ meta?: DocsMetaSnapshot;
55
+ serverMeta?: SyncServerMeta;
56
+ }
57
+ export interface SyncServerMeta {
58
+ auth: unknown;
59
+ rateLimit: number | false | undefined;
60
+ }
61
+ export declare const stripSymbolKeyedMembers: (text: string) => string;
62
+ export interface DiagnosticsEntry {
63
+ route: string;
64
+ kind: 'api' | 'sync';
65
+ field: string;
66
+ fallback: string;
67
+ reason: string;
68
+ detail?: string;
69
+ }
70
+ export interface GeneratedDiagnosticsData {
71
+ generatedAt: string;
72
+ totalRoutes: number;
73
+ fallbackCount: number;
74
+ fallbacks: DiagnosticsEntry[];
75
+ }
76
+ export declare const buildTypeMapArtifacts: ({ typesByPage, syncTypesByPage, namedImports, defaultImports, functionsInterface, }: {
77
+ typesByPage: Map<string, Map<string, ApiTypeEntry>>;
78
+ syncTypesByPage: Map<string, Map<string, SyncTypeEntry>>;
79
+ namedImports: Map<string, Set<string>>;
80
+ defaultImports: Map<string, string>;
81
+ functionsInterface: string;
82
+ }) => {
83
+ content: string;
84
+ docsData: GeneratedDocsData;
85
+ schemasContent: string;
86
+ diagnosticsData: GeneratedDiagnosticsData;
87
+ };
88
+ export declare const writeTypeMapArtifacts: ({ content, docsData, schemasContent, diagnosticsData, }: {
89
+ content: string;
90
+ docsData: GeneratedDocsData;
91
+ schemasContent?: string;
92
+ diagnosticsData?: GeneratedDiagnosticsData;
93
+ }) => void;
94
+ export {};
@@ -0,0 +1,16 @@
1
+ export type ExtractionKind = 'api' | 'sync';
2
+ export interface ExtractionFailure {
3
+ filePath: string;
4
+ kind: ExtractionKind;
5
+ field: string;
6
+ message: string;
7
+ }
8
+ export declare const recordExtractionOutcome: ({ filePath, kind, field, error, }: {
9
+ filePath: string;
10
+ kind: ExtractionKind;
11
+ field: string;
12
+ error: unknown;
13
+ }) => void;
14
+ export declare const findExtractionFailure: (route: string, kind: ExtractionKind, field: string) => string | undefined;
15
+ export declare const clearExtractionFailures: () => void;
16
+ export declare const getExtractionFailures: () => ExtractionFailure[];
@@ -0,0 +1,18 @@
1
+ import { ExpandedTypeResult } from './tsProgram.js';
2
+ export type TypeExtractionResult = ExpandedTypeResult;
3
+ export declare const getInputTypeFromFile: (filePath: string) => string;
4
+ export declare const getInputTypeDetailsFromFile: (filePath: string) => TypeExtractionResult;
5
+ export declare const getOutputTypeFromFile: (filePath: string) => string;
6
+ export declare const getApiStreamPayloadTypeFromFile: (filePath: string) => string;
7
+ export declare const getApiStreamPayloadTypeDetailsFromFile: (filePath: string) => TypeExtractionResult;
8
+ export declare const getOutputTypeDetailsFromFile: (filePath: string) => TypeExtractionResult;
9
+ export declare const getSyncClientDataType: (filePath: string) => string;
10
+ export declare const getSyncClientDataTypeDetailsFromFile: (filePath: string) => TypeExtractionResult;
11
+ export declare const getSyncServerOutputType: (filePath: string) => string;
12
+ export declare const getSyncServerStreamPayloadTypeFromFile: (filePath: string) => string;
13
+ export declare const getSyncServerStreamPayloadTypeDetailsFromFile: (filePath: string) => TypeExtractionResult;
14
+ export declare const getSyncServerOutputTypeDetailsFromFile: (filePath: string) => TypeExtractionResult;
15
+ export declare const getSyncClientOutputType: (filePath: string) => string;
16
+ export declare const getSyncClientStreamPayloadTypeFromFile: (filePath: string) => string;
17
+ export declare const getSyncClientStreamPayloadTypeDetailsFromFile: (filePath: string) => TypeExtractionResult;
18
+ export declare const getSyncClientOutputTypeDetailsFromFile: (filePath: string) => TypeExtractionResult;
@@ -0,0 +1,5 @@
1
+ import { ImportCollectors } from './typeContext.js';
2
+ export declare const stripLineComments: (value: string) => string;
3
+ export declare const normalizeInlineType: (value: string) => string;
4
+ export declare const portableInferredValueType: (inferred: string, sourceFilePath: string, exportName: string) => string | null;
5
+ export declare const generateServerFunctions: (collectors: ImportCollectors) => string;
@@ -0,0 +1,6 @@
1
+ export declare const extractPagePath: (filePath: string) => string;
2
+ export declare const extractApiName: (filePath: string) => string;
3
+ export declare const extractApiVersion: (filePath: string) => string;
4
+ export declare const extractSyncPagePath: (filePath: string) => string;
5
+ export declare const extractSyncName: (filePath: string) => string;
6
+ export declare const extractSyncVersion: (filePath: string) => string;
@@ -0,0 +1,12 @@
1
+ import { type Project, type Snapshot, type TranspileOutput } from 'typescript-7-api/sync';
2
+ import type { ScriptKind, SourceFile } from 'typescript-7-api/ast';
3
+ export interface TsconfigProject {
4
+ project: Project;
5
+ snapshot: Snapshot;
6
+ }
7
+ export declare const openTsconfigProject: (tsconfigPath: string) => TsconfigProject;
8
+ export declare const getServerProgram: () => Project;
9
+ export declare const invalidateProgramCache: () => void;
10
+ export declare const disposeTsApi: () => void;
11
+ export declare const parseSourceText: (fileName: string, text: string, scriptKind?: ScriptKind) => SourceFile;
12
+ export declare const transpileSourceText: (fileName: string, text: string) => TranspileOutput;
@@ -0,0 +1,41 @@
1
+ import { type Checker, type Symbol as TsSymbol, type Type } from 'typescript-7-api/sync';
2
+ export interface UnresolvedTypeSymbol {
3
+ name: string;
4
+ sourceFile?: string;
5
+ importPath?: string;
6
+ }
7
+ export interface ExpandedTypeResult {
8
+ text: string;
9
+ unresolvedSymbols: UnresolvedTypeSymbol[];
10
+ }
11
+ export declare class UnsupportedWireTypeError extends Error {
12
+ constructor(typeName: string);
13
+ }
14
+ export declare const getDeclarationFileName: (symbol: TsSymbol) => string | undefined;
15
+ interface ExpandState {
16
+ stackTypeIds: Set<number>;
17
+ /**
18
+ * Model what the CLIENT actually receives, not what the handler returns.
19
+ *
20
+ * Everything on an OUTPUT path crosses the wire as JSON — socket.io's default
21
+ * parser is `JSON.stringify`, and the HTTP route does the same. JSON has no
22
+ * `Date`: `Date.prototype.toJSON()` turns it into an ISO string. So emitting
23
+ * `createdAt: Date` was a lie that TypeScript happily endorsed —
24
+ * `user.createdAt.getTime()` compiled and then threw at runtime.
25
+ *
26
+ * OUTPUTS ONLY. Wire-safe inputs stay unprojected because their text feeds
27
+ * `validateInputByType`, which is fail-closed. `extractors.ts` separately
28
+ * rejects Date input annotations: JSON cannot deliver the promised instance.
29
+ */
30
+ wireProjection: boolean;
31
+ }
32
+ export interface ExpandOptions {
33
+ /**
34
+ * Emit what the client RECEIVES rather than what the handler returns.
35
+ * Pass `true` for every OUTPUT type; never for an input (see `ExpandState`).
36
+ */
37
+ wireProjection?: boolean;
38
+ }
39
+ export declare const expandTypeDetailed: (type: Type, checker: Checker, depth?: number, state?: ExpandState, options?: ExpandOptions) => ExpandedTypeResult;
40
+ export declare const expandType: (type: Type, checker: Checker, depth?: number) => string;
41
+ export {};
@@ -0,0 +1,21 @@
1
+ export interface FileImport {
2
+ source: string;
3
+ isDefault: boolean;
4
+ originalName?: string;
5
+ }
6
+ export interface ImportCollectors {
7
+ namedImports: Map<string, Set<string>>;
8
+ defaultImports: Map<string, string>;
9
+ }
10
+ export declare const parseFileTypeContext: (content: string) => {
11
+ availableExports: Set<string>;
12
+ fileImports: Map<string, FileImport>;
13
+ };
14
+ export declare const sanitizeTypeAndCollectImports: ({ type, filePath, availableExports, fileImports, collectors, knownGenerics, }: {
15
+ type: string;
16
+ filePath: string;
17
+ availableExports: Set<string>;
18
+ fileImports: Map<string, FileImport>;
19
+ collectors: ImportCollectors;
20
+ knownGenerics?: Set<string>;
21
+ }) => string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Convert a TypeScript type expression string (as emitted into the generated
3
+ * file) into a Zod schema source string.
4
+ *
5
+ * Returns `null` when the input can't be parsed as a type — callers should
6
+ * fall back to `z.any()` in that case.
7
+ */
8
+ export declare const typeTextToZodSource: (typeText: string) => string | null;
@@ -0,0 +1,5 @@
1
+ interface GenerateTypeMapOptions {
2
+ quiet?: boolean;
3
+ }
4
+ export declare const generateTypeMapFile: (options?: GenerateTypeMapOptions) => void;
5
+ export {};