@nanokajs/core 0.1.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.
package/dist/cli.js ADDED
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ import { promises } from 'fs';
3
+ import { resolve, dirname } from 'path';
4
+ import { createJiti } from 'jiti';
5
+
6
+ // src/cli/index.ts
7
+
8
+ // src/codegen/render-field.ts
9
+ function renderField(fieldName, field) {
10
+ const lines = [];
11
+ const kind = field.kind;
12
+ let colType;
13
+ if (kind === "string" || kind === "uuid") {
14
+ colType = `text('${fieldName}')`;
15
+ } else if (kind === "number") {
16
+ colType = `real('${fieldName}')`;
17
+ } else if (kind === "integer") {
18
+ colType = `integer('${fieldName}')`;
19
+ } else if (kind === "boolean") {
20
+ colType = `integer('${fieldName}', { mode: 'boolean' })`;
21
+ } else if (kind === "timestamp") {
22
+ colType = `integer('${fieldName}', { mode: 'timestamp_ms' })`;
23
+ } else if (kind === "json") {
24
+ colType = `text('${fieldName}', { mode: 'json' }).$type<unknown>()`;
25
+ } else {
26
+ throw new Error(`Unknown field kind: ${kind}`);
27
+ }
28
+ let column = colType;
29
+ if (field.modifiers.primary) {
30
+ column += ".primaryKey()";
31
+ }
32
+ if (!field.modifiers.optional) {
33
+ column += ".notNull()";
34
+ }
35
+ if (field.modifiers.unique) {
36
+ column += ".unique()";
37
+ }
38
+ if (field.modifiers.hasDefault) {
39
+ const defaultValue = field.modifiers.defaultValue;
40
+ if (typeof defaultValue === "function") {
41
+ console.warn(
42
+ `[nanoka] Warning: field "${fieldName}" has a function default. Default clause will be omitted. Use Drizzle's $defaultFn() or .onUpdateCurrent() in your custom schema if needed.`
43
+ );
44
+ } else {
45
+ const serializedValue = JSON.stringify(defaultValue);
46
+ column += `.default(${serializedValue})`;
47
+ }
48
+ }
49
+ lines.push(` ${fieldName}: ${column},`);
50
+ return lines.join("\n");
51
+ }
52
+
53
+ // src/codegen/generate.ts
54
+ var USED_DRIZZLE_IMPORTS = {
55
+ text: false,
56
+ integer: false,
57
+ real: false,
58
+ sqliteTable: false
59
+ };
60
+ function detectImports(models) {
61
+ const imports = { ...USED_DRIZZLE_IMPORTS };
62
+ for (const model of models) {
63
+ for (const field of Object.values(model.fields)) {
64
+ const kind = field.kind;
65
+ if (kind === "string" || kind === "uuid" || kind === "json") {
66
+ imports.text = true;
67
+ } else if (kind === "number") {
68
+ imports.real = true;
69
+ } else if (kind === "integer" || kind === "boolean" || kind === "timestamp") {
70
+ imports.integer = true;
71
+ }
72
+ }
73
+ if (Object.values(model.fields).length > 0) {
74
+ imports.sqliteTable = true;
75
+ }
76
+ }
77
+ return imports;
78
+ }
79
+ function buildImportStatement(imports) {
80
+ const used = [];
81
+ if (imports.integer) used.push("integer");
82
+ if (imports.real) used.push("real");
83
+ if (imports.sqliteTable) used.push("sqliteTable");
84
+ if (imports.text) used.push("text");
85
+ if (used.length === 0) {
86
+ return "import { sqliteTable } from 'drizzle-orm/sqlite-core'";
87
+ }
88
+ return `import { ${used.join(", ")} } from 'drizzle-orm/sqlite-core'`;
89
+ }
90
+ function generateDrizzleSchema(models) {
91
+ const imports = detectImports(models);
92
+ const importStatement = buildImportStatement(imports);
93
+ const lines = [
94
+ "// AUTO-GENERATED by `nanoka generate`. DO NOT EDIT BY HAND.",
95
+ "// To regenerate: `npx nanoka generate`",
96
+ importStatement,
97
+ ""
98
+ ];
99
+ for (const model of models) {
100
+ const fieldLines = [];
101
+ for (const [fieldName, field] of Object.entries(model.fields)) {
102
+ fieldLines.push(renderField(fieldName, field));
103
+ }
104
+ const fieldsStr = fieldLines.length > 0 ? fieldLines.join("\n") : "";
105
+ const tableContent = fieldsStr ? `{
106
+ ${fieldsStr}
107
+ }` : "{}";
108
+ lines.push(
109
+ `export const ${model.tableName} = sqliteTable('${model.tableName}', ${tableContent})`
110
+ );
111
+ lines.push("");
112
+ }
113
+ while (lines.length > 0 && lines[lines.length - 1] === "") {
114
+ lines.pop();
115
+ }
116
+ return lines.join("\n") + "\n";
117
+ }
118
+ async function loadConfig(configPath) {
119
+ const jiti = createJiti(import.meta.url, { interopDefault: true });
120
+ const mod = await jiti.import(configPath);
121
+ return mod.default;
122
+ }
123
+
124
+ // src/cli/index.ts
125
+ async function main(args) {
126
+ try {
127
+ if (args.length === 0 || args[0] === "help" || args[0] === "--help" || args[0] === "-h") {
128
+ console.log("Usage: nanoka generate [--config <path>] [--out <path>]");
129
+ console.log("");
130
+ console.log("Options:");
131
+ console.log(" --config <path> Path to nanoka.config.ts (default: ./nanoka.config.ts)");
132
+ console.log(" --out <path> Output file path (overrides config.out)");
133
+ return 0;
134
+ }
135
+ if (args[0] !== "generate") {
136
+ console.error(`Error: unknown command '${args[0]}'`);
137
+ console.error("Usage: nanoka generate [--config <path>] [--out <path>]");
138
+ return 1;
139
+ }
140
+ let configPath = "./nanoka.config.ts";
141
+ let outPath;
142
+ let i = 1;
143
+ while (i < args.length) {
144
+ if (args[i] === "--config" && i + 1 < args.length) {
145
+ configPath = args[i + 1];
146
+ i += 2;
147
+ } else if (args[i] === "--out" && i + 1 < args.length) {
148
+ outPath = args[i + 1];
149
+ i += 2;
150
+ } else {
151
+ console.error(`Error: unknown option '${args[i]}'`);
152
+ return 1;
153
+ }
154
+ }
155
+ const absoluteConfigPath = resolve(process.cwd(), configPath);
156
+ const config = await loadConfig(absoluteConfigPath);
157
+ const finalOutPath = outPath ?? config.out ?? "./drizzle/schema.ts";
158
+ const absoluteOutPath = resolve(process.cwd(), finalOutPath);
159
+ const schema = generateDrizzleSchema(config.models);
160
+ await promises.mkdir(dirname(absoluteOutPath), { recursive: true });
161
+ await promises.writeFile(absoluteOutPath, schema, "utf-8");
162
+ console.log(`\u2713 Generated ${absoluteOutPath}`);
163
+ return 0;
164
+ } catch (error) {
165
+ if (error instanceof Error) {
166
+ console.error(`Error: ${error.message}`);
167
+ } else {
168
+ console.error("Unknown error:", error);
169
+ }
170
+ return 1;
171
+ }
172
+ }
173
+ if (import.meta.url === `file://${process.argv[1]}`) {
174
+ main(process.argv.slice(2)).then((code) => {
175
+ process.exit(code);
176
+ });
177
+ }
178
+
179
+ export { main };
180
+ //# sourceMappingURL=cli.js.map
181
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/codegen/render-field.ts","../src/codegen/generate.ts","../src/cli/load-config.ts","../src/cli/index.ts"],"names":["fs"],"mappings":"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","file":"cli.js","sourcesContent":["import type { Field } from '../field'\n\nexport function renderField(fieldName: string, field: Field<any, any, any>): string {\n const lines: string[] = []\n\n const kind = field.kind\n let colType: string\n\n if (kind === 'string' || kind === 'uuid') {\n colType = `text('${fieldName}')`\n } else if (kind === 'number') {\n colType = `real('${fieldName}')`\n } else if (kind === 'integer') {\n colType = `integer('${fieldName}')`\n } else if (kind === 'boolean') {\n colType = `integer('${fieldName}', { mode: 'boolean' })`\n } else if (kind === 'timestamp') {\n colType = `integer('${fieldName}', { mode: 'timestamp_ms' })`\n } else if (kind === 'json') {\n colType = `text('${fieldName}', { mode: 'json' }).$type<unknown>()`\n } else {\n throw new Error(`Unknown field kind: ${kind}`)\n }\n\n let column = colType\n\n if (field.modifiers.primary) {\n column += '.primaryKey()'\n }\n\n if (!field.modifiers.optional) {\n column += '.notNull()'\n }\n\n if (field.modifiers.unique) {\n column += '.unique()'\n }\n\n if (field.modifiers.hasDefault) {\n const defaultValue = field.modifiers.defaultValue\n if (typeof defaultValue === 'function') {\n console.warn(\n `[nanoka] Warning: field \"${fieldName}\" has a function default. Default clause will be omitted. ` +\n `Use Drizzle's $defaultFn() or .onUpdateCurrent() in your custom schema if needed.`,\n )\n } else {\n const serializedValue = JSON.stringify(defaultValue)\n column += `.default(${serializedValue})`\n }\n }\n\n lines.push(` ${fieldName}: ${column},`)\n return lines.join('\\n')\n}\n","import { renderField } from './render-field'\nimport type { ModelDef } from './types'\n\nconst USED_DRIZZLE_IMPORTS = {\n text: false,\n integer: false,\n real: false,\n sqliteTable: false,\n}\n\nfunction detectImports(\n models: readonly ModelDef[],\n): Record<keyof typeof USED_DRIZZLE_IMPORTS, boolean> {\n const imports = { ...USED_DRIZZLE_IMPORTS }\n\n for (const model of models) {\n for (const field of Object.values(model.fields)) {\n const kind = field.kind\n\n if (kind === 'string' || kind === 'uuid' || kind === 'json') {\n imports.text = true\n } else if (kind === 'number') {\n imports.real = true\n } else if (kind === 'integer' || kind === 'boolean' || kind === 'timestamp') {\n imports.integer = true\n }\n }\n\n if (Object.values(model.fields).length > 0) {\n imports.sqliteTable = true\n }\n }\n\n return imports\n}\n\nfunction buildImportStatement(imports: Record<keyof typeof USED_DRIZZLE_IMPORTS, boolean>): string {\n const used: string[] = []\n\n if (imports.integer) used.push('integer')\n if (imports.real) used.push('real')\n if (imports.sqliteTable) used.push('sqliteTable')\n if (imports.text) used.push('text')\n\n if (used.length === 0) {\n return \"import { sqliteTable } from 'drizzle-orm/sqlite-core'\"\n }\n\n return `import { ${used.join(', ')} } from 'drizzle-orm/sqlite-core'`\n}\n\nexport function generateDrizzleSchema(models: readonly ModelDef[]): string {\n const imports = detectImports(models)\n const importStatement = buildImportStatement(imports)\n\n const lines: string[] = [\n '// AUTO-GENERATED by `nanoka generate`. DO NOT EDIT BY HAND.',\n '// To regenerate: `npx nanoka generate`',\n importStatement,\n '',\n ]\n\n for (const model of models) {\n const fieldLines: string[] = []\n\n for (const [fieldName, field] of Object.entries(model.fields)) {\n fieldLines.push(renderField(fieldName, field))\n }\n\n const fieldsStr = fieldLines.length > 0 ? fieldLines.join('\\n') : ''\n const tableContent = fieldsStr ? `{\\n${fieldsStr}\\n}` : '{}'\n\n lines.push(\n `export const ${model.tableName} = sqliteTable('${model.tableName}', ${tableContent})`,\n )\n lines.push('')\n }\n\n // Remove trailing empty line and add single newline at EOF\n while (lines.length > 0 && lines[lines.length - 1] === '') {\n lines.pop()\n }\n\n return lines.join('\\n') + '\\n'\n}\n","import { createJiti } from 'jiti'\nimport type { NanokaConfig } from '../codegen/types'\n\nexport async function loadConfig(configPath: string): Promise<NanokaConfig> {\n const jiti = createJiti(import.meta.url, { interopDefault: true })\n const mod = await jiti.import<{ default: NanokaConfig }>(configPath)\n return mod.default\n}\n","import { promises as fs } from 'fs'\nimport { dirname, resolve } from 'path'\nimport { generateDrizzleSchema } from '../codegen/generate'\nimport { loadConfig } from './load-config'\n\nasync function main(args: string[]): Promise<number> {\n try {\n if (args.length === 0 || args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {\n console.log('Usage: nanoka generate [--config <path>] [--out <path>]')\n console.log('')\n console.log('Options:')\n console.log(' --config <path> Path to nanoka.config.ts (default: ./nanoka.config.ts)')\n console.log(' --out <path> Output file path (overrides config.out)')\n return 0\n }\n\n if (args[0] !== 'generate') {\n console.error(`Error: unknown command '${args[0]}'`)\n console.error('Usage: nanoka generate [--config <path>] [--out <path>]')\n return 1\n }\n\n let configPath: string = './nanoka.config.ts'\n let outPath: string | undefined\n\n let i = 1\n while (i < args.length) {\n if (args[i] === '--config' && i + 1 < args.length) {\n configPath = args[i + 1]!\n i += 2\n } else if (args[i] === '--out' && i + 1 < args.length) {\n outPath = args[i + 1]!\n i += 2\n } else {\n console.error(`Error: unknown option '${args[i]}'`)\n return 1\n }\n }\n\n const absoluteConfigPath = resolve(process.cwd(), configPath)\n const config = await loadConfig(absoluteConfigPath)\n\n const finalOutPath = outPath ?? config.out ?? './drizzle/schema.ts'\n const absoluteOutPath = resolve(process.cwd(), finalOutPath)\n\n const schema = generateDrizzleSchema(config.models)\n\n await fs.mkdir(dirname(absoluteOutPath), { recursive: true })\n await fs.writeFile(absoluteOutPath, schema, 'utf-8')\n\n console.log(`✓ Generated ${absoluteOutPath}`)\n return 0\n } catch (error) {\n if (error instanceof Error) {\n console.error(`Error: ${error.message}`)\n } else {\n console.error('Unknown error:', error)\n }\n return 1\n }\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n main(process.argv.slice(2)).then((code) => {\n process.exit(code)\n })\n}\n\nexport { main }\n"]}
@@ -0,0 +1,17 @@
1
+ import { F as Field } from './factories-CDsk1Hdt.js';
2
+ export { t } from './factories-CDsk1Hdt.js';
3
+ import 'drizzle-orm/sqlite-core';
4
+ import 'zod';
5
+
6
+ interface ModelDef {
7
+ readonly tableName: string;
8
+ readonly fields: Record<string, Field<any, any, any>>;
9
+ }
10
+ interface NanokaConfig {
11
+ readonly out?: string | undefined;
12
+ readonly models: readonly ModelDef[];
13
+ }
14
+
15
+ declare function defineConfig(config: NanokaConfig): NanokaConfig;
16
+
17
+ export { type NanokaConfig, defineConfig };
package/dist/config.js ADDED
@@ -0,0 +1,10 @@
1
+ export { t } from './chunk-F5OBRXXY.js';
2
+
3
+ // src/config.ts
4
+ function defineConfig(config) {
5
+ return config;
6
+ }
7
+
8
+ export { defineConfig };
9
+ //# sourceMappingURL=config.js.map
10
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"names":[],"mappings":";;;AAMO,SAAS,aAAa,MAAA,EAAoC;AAC/D,EAAA,OAAO,MAAA;AACT","file":"config.js","sourcesContent":["export { t } from './field'\n\nimport type { NanokaConfig } from './codegen/types'\n\nexport type { NanokaConfig } from './codegen/types'\n\nexport function defineConfig(config: NanokaConfig): NanokaConfig {\n return config\n}\n"]}
@@ -0,0 +1,402 @@
1
+ import { SQLiteColumnBuilderBase } from 'drizzle-orm/sqlite-core';
2
+ import { z } from 'zod';
3
+
4
+ interface FieldModifiers {
5
+ optional?: boolean;
6
+ primary?: boolean;
7
+ unique?: boolean;
8
+ hasDefault?: boolean;
9
+ defaultValue?: unknown;
10
+ format?: 'email' | 'uuid';
11
+ min?: number;
12
+ max?: number;
13
+ }
14
+ type FieldKind = 'string' | 'uuid' | 'number' | 'integer' | 'boolean' | 'timestamp' | 'json';
15
+ /**
16
+ * Represents a typed database field with Zod validation and Drizzle column mapping.
17
+ *
18
+ * @template TS - The TypeScript runtime type of the field (e.g. `string`, `number`, `Date`)
19
+ * @template Mods - Modifiers applied to the field (optional, primary, unique, etc.)
20
+ * @template ZB - The Zod base schema type for this field
21
+ *
22
+ * The `tsType` property is a phantom type (its runtime value is always `undefined as unknown as TS`)
23
+ * and serves purely for type narrowing. It is not intended for runtime access.
24
+ *
25
+ * @internal `tsType` is an internal phantom property; use type narrowing via `InferFieldType` instead.
26
+ */
27
+ interface Field<TS = unknown, Mods extends FieldModifiers = {}, ZB extends z.ZodTypeAny = z.ZodTypeAny> {
28
+ /**
29
+ * Phantom type representing the TypeScript type of this field.
30
+ *
31
+ * @internal This is a phantom property and should not be accessed at runtime.
32
+ */
33
+ readonly tsType: TS;
34
+ /**
35
+ * The kind of field (string, uuid, number, integer, boolean, timestamp, json).
36
+ * Used for code generation and field discrimination.
37
+ */
38
+ readonly kind: FieldKind;
39
+ /**
40
+ * A Zod schema that validates values matching this field's configuration.
41
+ * Includes all modifiers (format constraints, min/max, optional, default).
42
+ */
43
+ readonly zodBase: ZB;
44
+ /**
45
+ * The modifiers currently applied to this field.
46
+ */
47
+ readonly modifiers: Readonly<Mods>;
48
+ /**
49
+ * Returns a Drizzle SQLite column builder for this field with the given column name.
50
+ * The builder includes all modifier constraints (notNull, primary, unique, default, etc.).
51
+ *
52
+ * @param name - The column name in the database
53
+ */
54
+ drizzleColumn(name: string): SQLiteColumnBuilderBase;
55
+ }
56
+ /**
57
+ * Extracts the TypeScript type from a Field instance.
58
+ *
59
+ * @example
60
+ * type T1 = InferFieldType<typeof t.string()> // string
61
+ * type T2 = InferFieldType<typeof t.string().optional()> // string | undefined
62
+ */
63
+ type InferFieldType<F> = F extends Field<infer T, FieldModifiers, z.ZodTypeAny> ? T : never;
64
+
65
+ /**
66
+ * Abstract base class for field builders.
67
+ * Provides shared implementation for Zod and Drizzle integration.
68
+ *
69
+ * Subclasses must implement:
70
+ * - `zodBase: ZB` getter
71
+ * - `drizzleColumn(name: string): SQLiteColumnBuilderBase` method
72
+ * - Modifier chain methods (optional, primary, unique, default) that return the subclass type
73
+ *
74
+ * @template TS - The TypeScript type of the field
75
+ * @template Mods - The type of modifiers currently applied
76
+ * @template ZB - The Zod base schema type for this field
77
+ */
78
+ declare abstract class BaseFieldBuilder<TS, Mods extends FieldModifiers = {}, ZB extends z.ZodTypeAny = z.ZodTypeAny> implements Field<TS, Mods, ZB> {
79
+ readonly tsType: TS;
80
+ abstract readonly kind: FieldKind;
81
+ readonly modifiers: Readonly<Mods>;
82
+ constructor(modifiers?: Mods);
83
+ abstract get zodBase(): ZB;
84
+ abstract drizzleColumn(name: string): SQLiteColumnBuilderBase;
85
+ /**
86
+ * Creates an immutable copy of this field with updated modifiers.
87
+ * Subclasses must implement this to maintain their concrete type.
88
+ */
89
+ protected abstract cloneWithModifiers(mods: FieldModifiers): any;
90
+ /**
91
+ * Returns the Zod schema with all modifiers applied.
92
+ * Order: base schema → format/min/max constraints → optional → default
93
+ */
94
+ protected applyModifiersToZod(baseSchema: z.ZodTypeAny): z.ZodTypeAny;
95
+ }
96
+
97
+ declare class StringFieldBuilder<TS = string, Mods extends FieldModifiers = {}, ZB extends z.ZodType<TS, z.ZodTypeDef, TS> = z.ZodType<TS, z.ZodTypeDef, TS>> extends BaseFieldBuilder<TS, Mods, ZB> {
98
+ readonly kind: "string";
99
+ get zodBase(): ZB;
100
+ drizzleColumn(name: string): SQLiteColumnBuilderBase;
101
+ protected cloneWithModifiers<NewMods extends FieldModifiers>(mods: NewMods): StringFieldBuilder<TS, NewMods>;
102
+ /**
103
+ * Marks this field as optional (allows undefined / null).
104
+ */
105
+ optional(this: StringFieldBuilder<TS, Mods>): StringFieldBuilder<TS | undefined, Mods & {
106
+ optional: true;
107
+ }>;
108
+ /**
109
+ * Marks this field as the primary key of its table.
110
+ */
111
+ primary(this: StringFieldBuilder<TS, Mods>): StringFieldBuilder<TS, Mods & {
112
+ primary: true;
113
+ }>;
114
+ /**
115
+ * Adds a unique constraint to this field.
116
+ */
117
+ unique(this: StringFieldBuilder<TS, Mods>): StringFieldBuilder<TS, Mods & {
118
+ unique: true;
119
+ }>;
120
+ /**
121
+ * Sets a default value for this field.
122
+ */
123
+ default(this: StringFieldBuilder<TS, Mods>, value: TS | (() => TS)): StringFieldBuilder<TS, Mods & {
124
+ hasDefault: true;
125
+ }>;
126
+ /**
127
+ * Adds email format validation.
128
+ */
129
+ email(this: StringFieldBuilder<TS, Mods>): StringFieldBuilder<TS, Mods & {
130
+ format: 'email';
131
+ }>;
132
+ /**
133
+ * Sets minimum string length.
134
+ */
135
+ min(this: StringFieldBuilder<TS, Mods>, n: number): StringFieldBuilder<TS, Mods & {
136
+ min: number;
137
+ }>;
138
+ /**
139
+ * Sets maximum string length.
140
+ */
141
+ max(this: StringFieldBuilder<TS, Mods>, n: number): StringFieldBuilder<TS, Mods & {
142
+ max: number;
143
+ }>;
144
+ }
145
+ declare class UuidFieldBuilder<TS = string, Mods extends FieldModifiers = {}, ZB extends z.ZodType<TS, z.ZodTypeDef, TS> = z.ZodType<TS, z.ZodTypeDef, TS>> extends BaseFieldBuilder<TS, Mods, ZB> {
146
+ readonly kind: "uuid";
147
+ get zodBase(): ZB;
148
+ drizzleColumn(name: string): SQLiteColumnBuilderBase;
149
+ protected cloneWithModifiers<NewMods extends FieldModifiers>(mods: NewMods): UuidFieldBuilder<TS, NewMods>;
150
+ /**
151
+ * Marks this field as optional (allows undefined / null).
152
+ */
153
+ optional(this: UuidFieldBuilder<TS, Mods>): UuidFieldBuilder<TS | undefined, Mods & {
154
+ optional: true;
155
+ }>;
156
+ /**
157
+ * Marks this field as the primary key of its table.
158
+ */
159
+ primary(this: UuidFieldBuilder<TS, Mods>): UuidFieldBuilder<TS, Mods & {
160
+ primary: true;
161
+ }>;
162
+ /**
163
+ * Adds a unique constraint to this field.
164
+ */
165
+ unique(this: UuidFieldBuilder<TS, Mods>): UuidFieldBuilder<TS, Mods & {
166
+ unique: true;
167
+ }>;
168
+ /**
169
+ * Sets a default value for this field.
170
+ */
171
+ default(this: UuidFieldBuilder<TS, Mods>, value: TS | (() => TS)): UuidFieldBuilder<TS, Mods & {
172
+ hasDefault: true;
173
+ }>;
174
+ /**
175
+ * Sets minimum string length.
176
+ */
177
+ min(this: UuidFieldBuilder<TS, Mods>, n: number): UuidFieldBuilder<TS, Mods & {
178
+ min: number;
179
+ }>;
180
+ /**
181
+ * Sets maximum string length.
182
+ */
183
+ max(this: UuidFieldBuilder<TS, Mods>, n: number): UuidFieldBuilder<TS, Mods & {
184
+ max: number;
185
+ }>;
186
+ }
187
+ declare class NumberFieldBuilder<TS = number, Mods extends FieldModifiers = {}, ZB extends z.ZodType<TS, z.ZodTypeDef, TS> = z.ZodType<TS, z.ZodTypeDef, TS>> extends BaseFieldBuilder<TS, Mods, ZB> {
188
+ readonly kind: "number";
189
+ get zodBase(): ZB;
190
+ drizzleColumn(name: string): SQLiteColumnBuilderBase;
191
+ protected cloneWithModifiers<NewMods extends FieldModifiers>(mods: NewMods): NumberFieldBuilder<TS, NewMods>;
192
+ /**
193
+ * Marks this field as optional (allows undefined / null).
194
+ */
195
+ optional(this: NumberFieldBuilder<TS, Mods>): NumberFieldBuilder<TS | undefined, Mods & {
196
+ optional: true;
197
+ }>;
198
+ /**
199
+ * Marks this field as the primary key of its table.
200
+ */
201
+ primary(this: NumberFieldBuilder<TS, Mods>): NumberFieldBuilder<TS, Mods & {
202
+ primary: true;
203
+ }>;
204
+ /**
205
+ * Adds a unique constraint to this field.
206
+ */
207
+ unique(this: NumberFieldBuilder<TS, Mods>): NumberFieldBuilder<TS, Mods & {
208
+ unique: true;
209
+ }>;
210
+ /**
211
+ * Sets a default value for this field.
212
+ */
213
+ default(this: NumberFieldBuilder<TS, Mods>, value: TS | (() => TS)): NumberFieldBuilder<TS, Mods & {
214
+ hasDefault: true;
215
+ }>;
216
+ /**
217
+ * Sets minimum value.
218
+ */
219
+ min(this: NumberFieldBuilder<TS, Mods>, n: number): NumberFieldBuilder<TS, Mods & {
220
+ min: number;
221
+ }>;
222
+ /**
223
+ * Sets maximum value.
224
+ */
225
+ max(this: NumberFieldBuilder<TS, Mods>, n: number): NumberFieldBuilder<TS, Mods & {
226
+ max: number;
227
+ }>;
228
+ }
229
+ declare class IntegerFieldBuilder<TS = number, Mods extends FieldModifiers = {}, ZB extends z.ZodType<TS, z.ZodTypeDef, TS> = z.ZodType<TS, z.ZodTypeDef, TS>> extends BaseFieldBuilder<TS, Mods, ZB> {
230
+ readonly kind: "integer";
231
+ get zodBase(): ZB;
232
+ drizzleColumn(name: string): SQLiteColumnBuilderBase;
233
+ protected cloneWithModifiers<NewMods extends FieldModifiers>(mods: NewMods): IntegerFieldBuilder<TS, NewMods>;
234
+ /**
235
+ * Marks this field as optional (allows undefined / null).
236
+ */
237
+ optional(this: IntegerFieldBuilder<TS, Mods>): IntegerFieldBuilder<TS | undefined, Mods & {
238
+ optional: true;
239
+ }>;
240
+ /**
241
+ * Marks this field as the primary key of its table.
242
+ */
243
+ primary(this: IntegerFieldBuilder<TS, Mods>): IntegerFieldBuilder<TS, Mods & {
244
+ primary: true;
245
+ }>;
246
+ /**
247
+ * Adds a unique constraint to this field.
248
+ */
249
+ unique(this: IntegerFieldBuilder<TS, Mods>): IntegerFieldBuilder<TS, Mods & {
250
+ unique: true;
251
+ }>;
252
+ /**
253
+ * Sets a default value for this field.
254
+ */
255
+ default(this: IntegerFieldBuilder<TS, Mods>, value: TS | (() => TS)): IntegerFieldBuilder<TS, Mods & {
256
+ hasDefault: true;
257
+ }>;
258
+ /**
259
+ * Sets minimum value.
260
+ */
261
+ min(this: IntegerFieldBuilder<TS, Mods>, n: number): IntegerFieldBuilder<TS, Mods & {
262
+ min: number;
263
+ }>;
264
+ /**
265
+ * Sets maximum value.
266
+ */
267
+ max(this: IntegerFieldBuilder<TS, Mods>, n: number): IntegerFieldBuilder<TS, Mods & {
268
+ max: number;
269
+ }>;
270
+ }
271
+ declare class BooleanFieldBuilder<TS = boolean, Mods extends FieldModifiers = {}, ZB extends z.ZodType<TS, z.ZodTypeDef, TS> = z.ZodType<TS, z.ZodTypeDef, TS>> extends BaseFieldBuilder<TS, Mods, ZB> {
272
+ readonly kind: "boolean";
273
+ get zodBase(): ZB;
274
+ drizzleColumn(name: string): SQLiteColumnBuilderBase;
275
+ protected cloneWithModifiers<NewMods extends FieldModifiers>(mods: NewMods): BooleanFieldBuilder<TS, NewMods>;
276
+ /**
277
+ * Marks this field as optional (allows undefined / null).
278
+ */
279
+ optional(this: BooleanFieldBuilder<TS, Mods>): BooleanFieldBuilder<TS | undefined, Mods & {
280
+ optional: true;
281
+ }>;
282
+ /**
283
+ * Marks this field as the primary key of its table.
284
+ */
285
+ primary(this: BooleanFieldBuilder<TS, Mods>): BooleanFieldBuilder<TS, Mods & {
286
+ primary: true;
287
+ }>;
288
+ /**
289
+ * Adds a unique constraint to this field.
290
+ */
291
+ unique(this: BooleanFieldBuilder<TS, Mods>): BooleanFieldBuilder<TS, Mods & {
292
+ unique: true;
293
+ }>;
294
+ /**
295
+ * Sets a default value for this field.
296
+ */
297
+ default(this: BooleanFieldBuilder<TS, Mods>, value: TS | (() => TS)): BooleanFieldBuilder<TS, Mods & {
298
+ hasDefault: true;
299
+ }>;
300
+ }
301
+ declare class TimestampFieldBuilder<TS = Date, Mods extends FieldModifiers = {}, ZB extends z.ZodType<TS, z.ZodTypeDef, Date | string | number> = z.ZodType<TS, z.ZodTypeDef, Date | string | number>> extends BaseFieldBuilder<TS, Mods, ZB> {
302
+ readonly kind: "timestamp";
303
+ get zodBase(): ZB;
304
+ drizzleColumn(name: string): SQLiteColumnBuilderBase;
305
+ protected cloneWithModifiers<NewMods extends FieldModifiers>(mods: NewMods): TimestampFieldBuilder<TS, NewMods>;
306
+ /**
307
+ * Marks this field as optional (allows undefined / null).
308
+ */
309
+ optional(this: TimestampFieldBuilder<TS, Mods>): TimestampFieldBuilder<TS | undefined, Mods & {
310
+ optional: true;
311
+ }>;
312
+ /**
313
+ * Marks this field as the primary key of its table.
314
+ */
315
+ primary(this: TimestampFieldBuilder<TS, Mods>): TimestampFieldBuilder<TS, Mods & {
316
+ primary: true;
317
+ }>;
318
+ /**
319
+ * Adds a unique constraint to this field.
320
+ */
321
+ unique(this: TimestampFieldBuilder<TS, Mods>): TimestampFieldBuilder<TS, Mods & {
322
+ unique: true;
323
+ }>;
324
+ /**
325
+ * Sets a default value for this field.
326
+ */
327
+ default(this: TimestampFieldBuilder<TS, Mods>, value: TS | (() => TS)): TimestampFieldBuilder<TS, Mods & {
328
+ hasDefault: true;
329
+ }>;
330
+ }
331
+ /**
332
+ * JSON フィールドビルダー。
333
+ *
334
+ * ⚠️ セキュリティ警告: zod ベースは `z.unknown()` のため、API に晒す際は
335
+ * `validator()` で除外するか、別途検証が必須。
336
+ */
337
+ declare class JsonFieldBuilder<T = unknown, TS = T, Mods extends FieldModifiers = {}, ZB extends z.ZodType<TS, z.ZodTypeDef, TS> = z.ZodType<TS, z.ZodTypeDef, TS>> extends BaseFieldBuilder<TS, Mods, ZB> {
338
+ readonly kind: "json";
339
+ get zodBase(): ZB;
340
+ drizzleColumn(name: string): SQLiteColumnBuilderBase;
341
+ protected cloneWithModifiers<NewMods extends FieldModifiers>(mods: NewMods): JsonFieldBuilder<T, TS, NewMods>;
342
+ /**
343
+ * Marks this field as optional (allows undefined / null).
344
+ */
345
+ optional(this: JsonFieldBuilder<T, TS, Mods>): JsonFieldBuilder<T, TS | undefined, Mods & {
346
+ optional: true;
347
+ }>;
348
+ /**
349
+ * Marks this field as the primary key of its table.
350
+ */
351
+ primary(this: JsonFieldBuilder<T, TS, Mods>): JsonFieldBuilder<T, TS, Mods & {
352
+ primary: true;
353
+ }>;
354
+ /**
355
+ * Adds a unique constraint to this field.
356
+ */
357
+ unique(this: JsonFieldBuilder<T, TS, Mods>): JsonFieldBuilder<T, TS, Mods & {
358
+ unique: true;
359
+ }>;
360
+ /**
361
+ * Sets a default value for this field.
362
+ */
363
+ default(this: JsonFieldBuilder<T, TS, Mods>, value: TS | (() => TS)): JsonFieldBuilder<T, TS, Mods & {
364
+ hasDefault: true;
365
+ }>;
366
+ }
367
+ /**
368
+ * Field DSL factory for building type-safe database fields.
369
+ *
370
+ * @example
371
+ * const nameField = t.string().min(1).max(255)
372
+ * const emailField = t.string().email()
373
+ * const idField = t.uuid().primary()
374
+ * const ageField = t.integer().min(0).max(150)
375
+ * const createdAtField = t.timestamp().default(() => new Date())
376
+ * const dataField = t.json<{ foo: string }>()
377
+ */
378
+ declare const t: {
379
+ string(): StringFieldBuilder<string, {}>;
380
+ uuid(): UuidFieldBuilder<string, {}>;
381
+ number(): NumberFieldBuilder<number, {}>;
382
+ integer(): IntegerFieldBuilder<number, {}>;
383
+ boolean(): BooleanFieldBuilder<boolean, {}>;
384
+ timestamp(): TimestampFieldBuilder<Date, {}>;
385
+ /**
386
+ * JSON フィールド。任意の JSON 値を受け入れる(Zod 内部表現は `z.unknown()`)。
387
+ *
388
+ * ⚠️ セキュリティ警告:
389
+ * このフィールドの zod ベースは `z.unknown()` のため、型パラメータ `T` で
390
+ * 指定した制約は **コンパイル時のみ** 適用され、validator() 経由でも
391
+ * runtime バリデーションは行われません。API 入力として晒す場合は:
392
+ * - `model.validator(target, { omit: ['<json field name>'] })` で除外する、または
393
+ * - ハンドラ側で別途 Zod スキーマを使って手動検証する、
394
+ * のいずれかを必ず実施してください。型パラメータが `unknown` 以外の値を
395
+ * runtime で保証することはありません。
396
+ *
397
+ * Phase 2 以降で `t.json(zodSchema)` 形式の引数追加を検討中。
398
+ */
399
+ json<T = unknown>(): JsonFieldBuilder<T, T, {}>;
400
+ };
401
+
402
+ export { type Field as F, type InferFieldType as I, type FieldModifiers as a, t };