@nanokajs/core 0.1.4 → 1.0.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/CHANGELOG.md +72 -0
- package/README.md +38 -20
- package/dist/{chunk-F5OBRXXY.js → chunk-UYXRKFAR.js} +108 -18
- package/dist/chunk-UYXRKFAR.js.map +1 -0
- package/dist/cli.js +6 -3
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +1 -1
- package/dist/{factories-CDsk1Hdt.d.ts → factories-Cmvx0495.d.ts} +89 -22
- package/dist/index.d.ts +206 -24
- package/dist/index.js +338 -39
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
- package/dist/chunk-F5OBRXXY.js.map +0 -1
package/dist/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SQLiteColumnBuilderBase } from 'drizzle-orm/sqlite-core';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
|
+
type FieldPolicy = 'serverOnly' | 'writeOnly' | 'readOnly';
|
|
4
5
|
interface FieldModifiers {
|
|
5
6
|
optional?: boolean;
|
|
6
7
|
primary?: boolean;
|
|
@@ -10,6 +11,7 @@ interface FieldModifiers {
|
|
|
10
11
|
format?: 'email' | 'uuid';
|
|
11
12
|
min?: number;
|
|
12
13
|
max?: number;
|
|
14
|
+
policy?: FieldPolicy;
|
|
13
15
|
}
|
|
14
16
|
type FieldKind = 'string' | 'uuid' | 'number' | 'integer' | 'boolean' | 'timestamp' | 'json';
|
|
15
17
|
/**
|
|
@@ -60,7 +62,7 @@ interface Field<TS = unknown, Mods extends FieldModifiers = {}, ZB extends z.Zod
|
|
|
60
62
|
* type T1 = InferFieldType<typeof t.string()> // string
|
|
61
63
|
* type T2 = InferFieldType<typeof t.string().optional()> // string | undefined
|
|
62
64
|
*/
|
|
63
|
-
type InferFieldType<F> = F extends Field<infer T, FieldModifiers, z.ZodTypeAny> ? T : never;
|
|
65
|
+
type InferFieldType<F> = F extends Field<infer T, FieldModifiers, z.ZodTypeAny> ? T : F extends Field<infer T, FieldModifiers, any> ? T : never;
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
68
|
* Abstract base class for field builders.
|
|
@@ -94,7 +96,7 @@ declare abstract class BaseFieldBuilder<TS, Mods extends FieldModifiers = {}, ZB
|
|
|
94
96
|
protected applyModifiersToZod(baseSchema: z.ZodTypeAny): z.ZodTypeAny;
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
declare class StringFieldBuilder<TS = string, Mods extends FieldModifiers = {}, ZB extends z.
|
|
99
|
+
declare class StringFieldBuilder<TS = string, Mods extends FieldModifiers = {}, ZB extends z.ZodTypeAny = z.ZodTypeAny> extends BaseFieldBuilder<TS, Mods, ZB> {
|
|
98
100
|
readonly kind: "string";
|
|
99
101
|
get zodBase(): ZB;
|
|
100
102
|
drizzleColumn(name: string): SQLiteColumnBuilderBase;
|
|
@@ -141,8 +143,17 @@ declare class StringFieldBuilder<TS = string, Mods extends FieldModifiers = {},
|
|
|
141
143
|
max(this: StringFieldBuilder<TS, Mods>, n: number): StringFieldBuilder<TS, Mods & {
|
|
142
144
|
max: number;
|
|
143
145
|
}>;
|
|
146
|
+
serverOnly(this: StringFieldBuilder<TS, Mods>): StringFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
147
|
+
policy: 'serverOnly';
|
|
148
|
+
}>;
|
|
149
|
+
writeOnly(this: StringFieldBuilder<TS, Mods>): StringFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
150
|
+
policy: 'writeOnly';
|
|
151
|
+
}>;
|
|
152
|
+
readOnly(this: StringFieldBuilder<TS, Mods>): StringFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
153
|
+
policy: 'readOnly';
|
|
154
|
+
}>;
|
|
144
155
|
}
|
|
145
|
-
declare class UuidFieldBuilder<TS = string, Mods extends FieldModifiers = {}, ZB extends z.
|
|
156
|
+
declare class UuidFieldBuilder<TS = string, Mods extends FieldModifiers = {}, ZB extends z.ZodTypeAny = z.ZodTypeAny> extends BaseFieldBuilder<TS, Mods, ZB> {
|
|
146
157
|
readonly kind: "uuid";
|
|
147
158
|
get zodBase(): ZB;
|
|
148
159
|
drizzleColumn(name: string): SQLiteColumnBuilderBase;
|
|
@@ -183,8 +194,17 @@ declare class UuidFieldBuilder<TS = string, Mods extends FieldModifiers = {}, ZB
|
|
|
183
194
|
max(this: UuidFieldBuilder<TS, Mods>, n: number): UuidFieldBuilder<TS, Mods & {
|
|
184
195
|
max: number;
|
|
185
196
|
}>;
|
|
197
|
+
serverOnly(this: UuidFieldBuilder<TS, Mods>): UuidFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
198
|
+
policy: 'serverOnly';
|
|
199
|
+
}>;
|
|
200
|
+
writeOnly(this: UuidFieldBuilder<TS, Mods>): UuidFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
201
|
+
policy: 'writeOnly';
|
|
202
|
+
}>;
|
|
203
|
+
readOnly(this: UuidFieldBuilder<TS, Mods>): UuidFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
204
|
+
policy: 'readOnly';
|
|
205
|
+
}>;
|
|
186
206
|
}
|
|
187
|
-
declare class NumberFieldBuilder<TS = number, Mods extends FieldModifiers = {}, ZB extends z.
|
|
207
|
+
declare class NumberFieldBuilder<TS = number, Mods extends FieldModifiers = {}, ZB extends z.ZodTypeAny = z.ZodTypeAny> extends BaseFieldBuilder<TS, Mods, ZB> {
|
|
188
208
|
readonly kind: "number";
|
|
189
209
|
get zodBase(): ZB;
|
|
190
210
|
drizzleColumn(name: string): SQLiteColumnBuilderBase;
|
|
@@ -225,8 +245,17 @@ declare class NumberFieldBuilder<TS = number, Mods extends FieldModifiers = {},
|
|
|
225
245
|
max(this: NumberFieldBuilder<TS, Mods>, n: number): NumberFieldBuilder<TS, Mods & {
|
|
226
246
|
max: number;
|
|
227
247
|
}>;
|
|
248
|
+
serverOnly(this: NumberFieldBuilder<TS, Mods>): NumberFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
249
|
+
policy: 'serverOnly';
|
|
250
|
+
}>;
|
|
251
|
+
writeOnly(this: NumberFieldBuilder<TS, Mods>): NumberFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
252
|
+
policy: 'writeOnly';
|
|
253
|
+
}>;
|
|
254
|
+
readOnly(this: NumberFieldBuilder<TS, Mods>): NumberFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
255
|
+
policy: 'readOnly';
|
|
256
|
+
}>;
|
|
228
257
|
}
|
|
229
|
-
declare class IntegerFieldBuilder<TS = number, Mods extends FieldModifiers = {}, ZB extends z.
|
|
258
|
+
declare class IntegerFieldBuilder<TS = number, Mods extends FieldModifiers = {}, ZB extends z.ZodTypeAny = z.ZodTypeAny> extends BaseFieldBuilder<TS, Mods, ZB> {
|
|
230
259
|
readonly kind: "integer";
|
|
231
260
|
get zodBase(): ZB;
|
|
232
261
|
drizzleColumn(name: string): SQLiteColumnBuilderBase;
|
|
@@ -267,8 +296,17 @@ declare class IntegerFieldBuilder<TS = number, Mods extends FieldModifiers = {},
|
|
|
267
296
|
max(this: IntegerFieldBuilder<TS, Mods>, n: number): IntegerFieldBuilder<TS, Mods & {
|
|
268
297
|
max: number;
|
|
269
298
|
}>;
|
|
299
|
+
serverOnly(this: IntegerFieldBuilder<TS, Mods>): IntegerFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
300
|
+
policy: 'serverOnly';
|
|
301
|
+
}>;
|
|
302
|
+
writeOnly(this: IntegerFieldBuilder<TS, Mods>): IntegerFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
303
|
+
policy: 'writeOnly';
|
|
304
|
+
}>;
|
|
305
|
+
readOnly(this: IntegerFieldBuilder<TS, Mods>): IntegerFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
306
|
+
policy: 'readOnly';
|
|
307
|
+
}>;
|
|
270
308
|
}
|
|
271
|
-
declare class BooleanFieldBuilder<TS = boolean, Mods extends FieldModifiers = {}, ZB extends z.
|
|
309
|
+
declare class BooleanFieldBuilder<TS = boolean, Mods extends FieldModifiers = {}, ZB extends z.ZodTypeAny = z.ZodTypeAny> extends BaseFieldBuilder<TS, Mods, ZB> {
|
|
272
310
|
readonly kind: "boolean";
|
|
273
311
|
get zodBase(): ZB;
|
|
274
312
|
drizzleColumn(name: string): SQLiteColumnBuilderBase;
|
|
@@ -297,8 +335,17 @@ declare class BooleanFieldBuilder<TS = boolean, Mods extends FieldModifiers = {}
|
|
|
297
335
|
default(this: BooleanFieldBuilder<TS, Mods>, value: TS | (() => TS)): BooleanFieldBuilder<TS, Mods & {
|
|
298
336
|
hasDefault: true;
|
|
299
337
|
}>;
|
|
338
|
+
serverOnly(this: BooleanFieldBuilder<TS, Mods>): BooleanFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
339
|
+
policy: 'serverOnly';
|
|
340
|
+
}>;
|
|
341
|
+
writeOnly(this: BooleanFieldBuilder<TS, Mods>): BooleanFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
342
|
+
policy: 'writeOnly';
|
|
343
|
+
}>;
|
|
344
|
+
readOnly(this: BooleanFieldBuilder<TS, Mods>): BooleanFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
345
|
+
policy: 'readOnly';
|
|
346
|
+
}>;
|
|
300
347
|
}
|
|
301
|
-
declare class TimestampFieldBuilder<TS = Date, Mods extends FieldModifiers = {}, ZB extends z.
|
|
348
|
+
declare class TimestampFieldBuilder<TS = Date, Mods extends FieldModifiers = {}, ZB extends z.ZodTypeAny = z.ZodTypeAny> extends BaseFieldBuilder<TS, Mods, ZB> {
|
|
302
349
|
readonly kind: "timestamp";
|
|
303
350
|
get zodBase(): ZB;
|
|
304
351
|
drizzleColumn(name: string): SQLiteColumnBuilderBase;
|
|
@@ -327,15 +374,26 @@ declare class TimestampFieldBuilder<TS = Date, Mods extends FieldModifiers = {},
|
|
|
327
374
|
default(this: TimestampFieldBuilder<TS, Mods>, value: TS | (() => TS)): TimestampFieldBuilder<TS, Mods & {
|
|
328
375
|
hasDefault: true;
|
|
329
376
|
}>;
|
|
377
|
+
serverOnly(this: TimestampFieldBuilder<TS, Mods>): TimestampFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
378
|
+
policy: 'serverOnly';
|
|
379
|
+
}>;
|
|
380
|
+
writeOnly(this: TimestampFieldBuilder<TS, Mods>): TimestampFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
381
|
+
policy: 'writeOnly';
|
|
382
|
+
}>;
|
|
383
|
+
readOnly(this: TimestampFieldBuilder<TS, Mods>): TimestampFieldBuilder<TS, Omit<Mods, 'policy'> & {
|
|
384
|
+
policy: 'readOnly';
|
|
385
|
+
}>;
|
|
330
386
|
}
|
|
331
387
|
/**
|
|
332
388
|
* JSON フィールドビルダー。
|
|
333
389
|
*
|
|
334
|
-
*
|
|
335
|
-
* `
|
|
390
|
+
* `t.json(zodSchema)` 形式で Zod スキーマを渡すと runtime 検証が走る。
|
|
391
|
+
* スキーマ省略時は `z.unknown()` で後方互換を維持する。
|
|
336
392
|
*/
|
|
337
|
-
declare class JsonFieldBuilder<T = unknown, TS = T, Mods extends FieldModifiers = {}, ZB extends z.
|
|
393
|
+
declare class JsonFieldBuilder<T = unknown, TS = T, Mods extends FieldModifiers = {}, ZB extends z.ZodTypeAny = z.ZodTypeAny> extends BaseFieldBuilder<TS, Mods, ZB> {
|
|
338
394
|
readonly kind: "json";
|
|
395
|
+
private readonly _zodSchema;
|
|
396
|
+
constructor(modifiers?: Mods, zodSchema?: z.ZodTypeAny);
|
|
339
397
|
get zodBase(): ZB;
|
|
340
398
|
drizzleColumn(name: string): SQLiteColumnBuilderBase;
|
|
341
399
|
protected cloneWithModifiers<NewMods extends FieldModifiers>(mods: NewMods): JsonFieldBuilder<T, TS, NewMods>;
|
|
@@ -363,7 +421,18 @@ declare class JsonFieldBuilder<T = unknown, TS = T, Mods extends FieldModifiers
|
|
|
363
421
|
default(this: JsonFieldBuilder<T, TS, Mods>, value: TS | (() => TS)): JsonFieldBuilder<T, TS, Mods & {
|
|
364
422
|
hasDefault: true;
|
|
365
423
|
}>;
|
|
424
|
+
serverOnly(this: JsonFieldBuilder<T, TS, Mods>): JsonFieldBuilder<T, TS, Omit<Mods, 'policy'> & {
|
|
425
|
+
policy: 'serverOnly';
|
|
426
|
+
}>;
|
|
427
|
+
writeOnly(this: JsonFieldBuilder<T, TS, Mods>): JsonFieldBuilder<T, TS, Omit<Mods, 'policy'> & {
|
|
428
|
+
policy: 'writeOnly';
|
|
429
|
+
}>;
|
|
430
|
+
readOnly(this: JsonFieldBuilder<T, TS, Mods>): JsonFieldBuilder<T, TS, Omit<Mods, 'policy'> & {
|
|
431
|
+
policy: 'readOnly';
|
|
432
|
+
}>;
|
|
366
433
|
}
|
|
434
|
+
declare function jsonField<S extends z.ZodTypeAny>(schema: S): JsonFieldBuilder<z.infer<S>, z.infer<S>, {}>;
|
|
435
|
+
declare function jsonField<T = unknown>(): JsonFieldBuilder<T, T, {}>;
|
|
367
436
|
/**
|
|
368
437
|
* Field DSL factory for building type-safe database fields.
|
|
369
438
|
*
|
|
@@ -374,6 +443,7 @@ declare class JsonFieldBuilder<T = unknown, TS = T, Mods extends FieldModifiers
|
|
|
374
443
|
* const ageField = t.integer().min(0).max(150)
|
|
375
444
|
* const createdAtField = t.timestamp().default(() => new Date())
|
|
376
445
|
* const dataField = t.json<{ foo: string }>()
|
|
446
|
+
* const dataField2 = t.json(z.object({ foo: z.string() })) // runtime validation
|
|
377
447
|
*/
|
|
378
448
|
declare const t: {
|
|
379
449
|
string(): StringFieldBuilder<string, {}>;
|
|
@@ -383,20 +453,17 @@ declare const t: {
|
|
|
383
453
|
boolean(): BooleanFieldBuilder<boolean, {}>;
|
|
384
454
|
timestamp(): TimestampFieldBuilder<Date, {}>;
|
|
385
455
|
/**
|
|
386
|
-
* JSON
|
|
456
|
+
* JSON フィールド。
|
|
457
|
+
*
|
|
458
|
+
* `t.json(zodSchema)` 形式で Zod スキーマを渡すと runtime 検証が走る。
|
|
459
|
+
* スキーマ省略時は `z.unknown()` で後方互換を維持する。
|
|
387
460
|
*
|
|
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 で保証することはありません。
|
|
461
|
+
* `t.json(z.object({ foo: z.string() }))` でオブジェクト形状の runtime 検証が可能。
|
|
396
462
|
*
|
|
397
|
-
*
|
|
463
|
+
* @note codegen (`nanoka generate`) は `t.json(zodSchema)` を渡しても `$type<unknown>()` のまま出力する。
|
|
464
|
+
* Drizzle 型が欲しい場合は生成後に手動で書き換えるか `as` を使うこと。
|
|
398
465
|
*/
|
|
399
|
-
json
|
|
466
|
+
json: typeof jsonField;
|
|
400
467
|
};
|
|
401
468
|
|
|
402
|
-
export { type Field as F, type InferFieldType as I, type
|
|
469
|
+
export { type Field as F, type InferFieldType as I, type FieldPolicy as a, type FieldModifiers as b, t };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { D1Database } from '@cloudflare/workers-types';
|
|
2
2
|
import { BatchItem, BatchResponse } from 'drizzle-orm/batch';
|
|
3
3
|
import { BaseSQLiteDatabase, SQLiteTable } from 'drizzle-orm/sqlite-core';
|
|
4
|
-
import { F as Field, I as InferFieldType } from './factories-
|
|
5
|
-
export {
|
|
4
|
+
import { F as Field, I as InferFieldType, a as FieldPolicy } from './factories-Cmvx0495.js';
|
|
5
|
+
export { b as FieldModifiers, t } from './factories-Cmvx0495.js';
|
|
6
6
|
import { Hook } from '@hono/zod-validator';
|
|
7
7
|
import * as hono from 'hono';
|
|
8
8
|
import { ValidationTargets, Env, MiddlewareHandler, Hono } from 'hono';
|
|
@@ -40,6 +40,14 @@ interface Adapter<TSchema extends Record<string, unknown> = Record<string, never
|
|
|
40
40
|
*/
|
|
41
41
|
declare function d1Adapter<TSchema extends Record<string, unknown> = Record<string, never>>(d1: D1Database): Adapter<TSchema>;
|
|
42
42
|
|
|
43
|
+
type OpenAPISchemaObject = Record<string, unknown>;
|
|
44
|
+
interface OpenAPIModelComponent {
|
|
45
|
+
create: OpenAPISchemaObject;
|
|
46
|
+
update: OpenAPISchemaObject;
|
|
47
|
+
output: OpenAPISchemaObject;
|
|
48
|
+
}
|
|
49
|
+
type OpenAPIUsage = 'create' | 'update' | 'output';
|
|
50
|
+
|
|
43
51
|
/**
|
|
44
52
|
* Options for findMany query.
|
|
45
53
|
* `limit` is required (no default).
|
|
@@ -78,13 +86,84 @@ type RowType<Fields extends Record<string, Field<any, any, any>>> = {
|
|
|
78
86
|
[K in keyof Fields]: InferFieldType<Fields[K]>;
|
|
79
87
|
};
|
|
80
88
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
89
|
+
* @internal
|
|
90
|
+
* Extracts the policy from a Field's modifiers.
|
|
91
|
+
*
|
|
92
|
+
* Uses `Field<any, { policy: infer P }, any>` rather than a two-step
|
|
93
|
+
* `infer M` + `M extends { policy: infer P }` pattern.
|
|
94
|
+
* The two-step pattern is broken when TypeScript widens `M` to the constraint
|
|
95
|
+
* `FieldModifiers` (which has `policy?: FieldPolicy` as optional), causing
|
|
96
|
+
* `M extends { policy: infer P }` to be true for ALL fields regardless of their
|
|
97
|
+
* actual policy value. Directly matching `{ policy: infer P }` avoids this.
|
|
98
|
+
*/
|
|
99
|
+
type PolicyOf<F> = F extends Field<any, {
|
|
100
|
+
policy: infer P extends FieldPolicy;
|
|
101
|
+
}, any> ? P : never;
|
|
102
|
+
/**
|
|
103
|
+
* @internal
|
|
104
|
+
* Computes which field keys should be omitted based on policy and usage.
|
|
105
|
+
* Mirrors the runtime logic in derivePolicyOptions() in schema.ts.
|
|
106
|
+
*
|
|
107
|
+
* NOTE: `[PolicyOf<Fields[K]>] extends [never]` (non-distributive form) is used to
|
|
108
|
+
* short-circuit fields with no policy to `never` (do not omit). Without this guard,
|
|
109
|
+
* `never extends 'serverOnly'` evaluates to `true` (vacuously), causing every field
|
|
110
|
+
* without a policy to be incorrectly included in the omit set.
|
|
111
|
+
*/
|
|
112
|
+
type PolicyOmitKeys<Fields extends Record<string, Field<any, any, any>>, Usage extends 'input-create' | 'input-update' | 'output'> = {
|
|
113
|
+
[K in keyof Fields]: [PolicyOf<Fields[K]>] extends [never] ? never : PolicyOf<Fields[K]> extends 'serverOnly' ? K : Usage extends 'output' ? PolicyOf<Fields[K]> extends 'writeOnly' ? K : never : Usage extends 'input-create' | 'input-update' ? PolicyOf<Fields[K]> extends 'readOnly' ? K : never : never;
|
|
114
|
+
}[keyof Fields];
|
|
115
|
+
/**
|
|
116
|
+
* @internal
|
|
117
|
+
* Computes which field keys have the serverOnly policy.
|
|
118
|
+
* serverOnly fields are completely excluded from CreateInput
|
|
119
|
+
* (cannot be passed even from library internals — they are server-side only).
|
|
120
|
+
*
|
|
121
|
+
* Uses `[PolicyOf<Fields[K]>] extends [never]` (non-distributive form) to short-circuit
|
|
122
|
+
* fields with no policy to `never`. Without this guard, `never extends 'serverOnly'`
|
|
123
|
+
* evaluates to `true` (vacuously), causing every field without a policy to be included.
|
|
124
|
+
*/
|
|
125
|
+
type ServerOnlyKeys<Fields extends Record<string, Field<any, any, any>>> = {
|
|
126
|
+
[K in keyof Fields]: [PolicyOf<Fields[K]>] extends [never] ? never : PolicyOf<Fields[K]> extends 'serverOnly' ? K : never;
|
|
127
|
+
}[keyof Fields];
|
|
128
|
+
/**
|
|
129
|
+
* @internal
|
|
130
|
+
* Determines if a field is required for create input.
|
|
131
|
+
* A field is optional if it has a default, is optional, or is readOnly.
|
|
132
|
+
*
|
|
133
|
+
* Uses direct shape matching (`Field<any, { hasDefault: true }, any>`) to avoid
|
|
134
|
+
* the TypeScript infer-widening issue where `infer M` resolves to `FieldModifiers`
|
|
135
|
+
* (the constraint bound) instead of the concrete Mods type, causing `M extends
|
|
136
|
+
* { policy: 'readOnly' }` to be false even for readOnly fields.
|
|
137
|
+
*/
|
|
138
|
+
type IsRequired<F extends Field<any, any, any>> = F extends Field<any, {
|
|
139
|
+
hasDefault: true;
|
|
140
|
+
}, any> ? false : F extends Field<any, {
|
|
141
|
+
optional: true;
|
|
142
|
+
}, any> ? false : F extends Field<any, {
|
|
143
|
+
policy: 'readOnly';
|
|
144
|
+
}, any> ? false : true;
|
|
145
|
+
/**
|
|
146
|
+
* Create input with precise types:
|
|
147
|
+
* - `readOnly` fields are optional (library internals can pass them; API callers
|
|
148
|
+
* are excluded via inputSchema — but CreateInput itself keeps them as optional
|
|
149
|
+
* so handlers can supply generated values like `id` or `createdAt`)
|
|
150
|
+
* - fields with `default` are optional
|
|
151
|
+
* - fields marked `optional` are optional
|
|
152
|
+
* - all other fields are required
|
|
153
|
+
* - `serverOnly` fields are completely excluded (cannot be passed even internally)
|
|
154
|
+
* - `writeOnly` fields are included as required (they are input fields by design)
|
|
83
155
|
*/
|
|
84
|
-
type CreateInput<Fields extends Record<string, Field<any, any, any>>> =
|
|
156
|
+
type CreateInput<Fields extends Record<string, Field<any, any, any>>> = {
|
|
157
|
+
[K in keyof Fields as IsRequired<Fields[K]> extends true ? K extends ServerOnlyKeys<Fields> ? never : K : never]: InferFieldType<Fields[K]>;
|
|
158
|
+
} & {
|
|
159
|
+
[K in keyof Fields as IsRequired<Fields[K]> extends true ? never : K extends ServerOnlyKeys<Fields> ? never : K]?: InferFieldType<Fields[K]>;
|
|
160
|
+
};
|
|
161
|
+
type FieldAccessor<K extends string> = {
|
|
162
|
+
readonly [Key in K]: Key;
|
|
163
|
+
};
|
|
85
164
|
interface SchemaOptions<K extends string = string> {
|
|
86
|
-
readonly pick?: readonly K[];
|
|
87
|
-
readonly omit?: readonly K[];
|
|
165
|
+
readonly pick?: readonly K[] | ((f: FieldAccessor<K>) => readonly K[]);
|
|
166
|
+
readonly omit?: readonly K[] | ((f: FieldAccessor<K>) => readonly K[]);
|
|
88
167
|
readonly partial?: boolean;
|
|
89
168
|
}
|
|
90
169
|
/**
|
|
@@ -101,16 +180,22 @@ type FieldsToZodShape<Fields extends Record<string, Field<any, any, any>>> = {
|
|
|
101
180
|
* Utility to narrow array literal types to union of strings.
|
|
102
181
|
*/
|
|
103
182
|
type ArrayKeys<A> = A extends readonly (infer U)[] ? U : never;
|
|
183
|
+
/**
|
|
184
|
+
* @internal
|
|
185
|
+
* Resolves pick/omit option type to the array type.
|
|
186
|
+
* Handles both array form and accessor function form.
|
|
187
|
+
*/
|
|
188
|
+
type ResolveOptKeys<Opt> = Opt extends readonly string[] ? Opt : Opt extends (f: FieldAccessor<infer _K>) => readonly (infer R)[] ? readonly R[] : never;
|
|
104
189
|
/**
|
|
105
190
|
* @internal
|
|
106
191
|
* Apply pick transformation to a shape.
|
|
107
192
|
*/
|
|
108
|
-
type ApplyPickToShape<Shape extends z.ZodRawShape,
|
|
193
|
+
type ApplyPickToShape<Shape extends z.ZodRawShape, PickOpt> = ResolveOptKeys<PickOpt> extends readonly string[] ? Pick<Shape, ArrayKeys<ResolveOptKeys<PickOpt>> & keyof Shape> : Shape;
|
|
109
194
|
/**
|
|
110
195
|
* @internal
|
|
111
196
|
* Apply omit transformation to a shape.
|
|
112
197
|
*/
|
|
113
|
-
type ApplyOmitToShape<Shape extends z.ZodRawShape,
|
|
198
|
+
type ApplyOmitToShape<Shape extends z.ZodRawShape, OmitOpt> = ResolveOptKeys<OmitOpt> extends readonly string[] ? Omit<Shape, ArrayKeys<ResolveOptKeys<OmitOpt>> & keyof Shape> : Shape;
|
|
114
199
|
/**
|
|
115
200
|
* @internal
|
|
116
201
|
* Apply partial transformation to a shape.
|
|
@@ -118,38 +203,77 @@ type ApplyOmitToShape<Shape extends z.ZodRawShape, OmitKeys> = OmitKeys extends
|
|
|
118
203
|
type ApplyPartialToShape<Shape extends z.ZodRawShape> = {
|
|
119
204
|
[K in keyof Shape]: z.ZodOptional<Shape[K]>;
|
|
120
205
|
};
|
|
206
|
+
/**
|
|
207
|
+
* @internal
|
|
208
|
+
* Checks if an option value (array or function) is present (i.e. not undefined and not never).
|
|
209
|
+
* Uses distributive conditional to handle union types like `T | undefined`.
|
|
210
|
+
*/
|
|
211
|
+
type HasOpt<Opt> = undefined extends Opt ? false : [Opt] extends [never] ? false : true;
|
|
121
212
|
/**
|
|
122
213
|
* @internal
|
|
123
214
|
* Apply pick/omit/partial transformations to a Zod raw shape.
|
|
124
215
|
* Order: pick → omit → partial
|
|
216
|
+
* Handles both array form and accessor function form for pick/omit.
|
|
125
217
|
*/
|
|
126
|
-
type ApplyShape<Shape extends z.ZodRawShape, Opts extends SchemaOptions | undefined> = Opts extends
|
|
127
|
-
pick: readonly string[];
|
|
128
|
-
} ? Opts extends {
|
|
129
|
-
omit: readonly string[];
|
|
130
|
-
} ? Opts extends {
|
|
218
|
+
type ApplyShape<Shape extends z.ZodRawShape, Opts extends SchemaOptions | undefined> = Opts extends SchemaOptions ? HasOpt<Opts['pick']> extends true ? HasOpt<Opts['omit']> extends true ? Opts extends {
|
|
131
219
|
partial: true;
|
|
132
220
|
} ? ApplyPartialToShape<ApplyOmitToShape<ApplyPickToShape<Shape, Opts['pick']>, Opts['omit']>> : ApplyOmitToShape<ApplyPickToShape<Shape, Opts['pick']>, Opts['omit']> : Opts extends {
|
|
133
221
|
partial: true;
|
|
134
|
-
} ? ApplyPartialToShape<ApplyPickToShape<Shape, Opts['pick']>> : ApplyPickToShape<Shape, Opts['pick']> : Opts extends {
|
|
135
|
-
omit: readonly string[];
|
|
136
|
-
} ? Opts extends {
|
|
222
|
+
} ? ApplyPartialToShape<ApplyPickToShape<Shape, Opts['pick']>> : ApplyPickToShape<Shape, Opts['pick']> : HasOpt<Opts['omit']> extends true ? Opts extends {
|
|
137
223
|
partial: true;
|
|
138
224
|
} ? ApplyPartialToShape<ApplyOmitToShape<Shape, Opts['omit']>> : ApplyOmitToShape<Shape, Opts['omit']> : Opts extends {
|
|
139
225
|
partial: true;
|
|
140
|
-
} ? ApplyPartialToShape<Shape> : Shape;
|
|
226
|
+
} ? ApplyPartialToShape<Shape> : Shape : Shape;
|
|
141
227
|
/**
|
|
142
228
|
* @internal
|
|
143
229
|
* Returns the correct Zod object type after applying pick/omit/partial transformations.
|
|
144
230
|
*/
|
|
145
231
|
type Apply<Shape extends z.ZodRawShape, Opts extends SchemaOptions | undefined> = z.ZodObject<ApplyShape<Shape, Opts>>;
|
|
232
|
+
/**
|
|
233
|
+
* @internal
|
|
234
|
+
* Apply pick transformation to a TS record type.
|
|
235
|
+
*/
|
|
236
|
+
type ApplyPickToRecord<R, PickOpt> = ResolveOptKeys<PickOpt> extends readonly string[] ? Pick<R, ArrayKeys<ResolveOptKeys<PickOpt>> & keyof R> : R;
|
|
237
|
+
/**
|
|
238
|
+
* @internal
|
|
239
|
+
* Apply omit transformation to a TS record type.
|
|
240
|
+
*/
|
|
241
|
+
type ApplyOmitToRecord<R, OmitOpt> = ResolveOptKeys<OmitOpt> extends readonly string[] ? Omit<R, ArrayKeys<ResolveOptKeys<OmitOpt>> & keyof R> : R;
|
|
242
|
+
/**
|
|
243
|
+
* @internal
|
|
244
|
+
* Apply pick/omit/partial transformations to a TypeScript record type.
|
|
245
|
+
* Mirrors ApplyShape but operates on TS types directly, not Zod shapes.
|
|
246
|
+
* Used for Zod v3/v4 compatible middleware input/output type computation.
|
|
247
|
+
*/
|
|
248
|
+
type ApplyToRecord<R, Opts extends SchemaOptions | undefined> = Opts extends SchemaOptions ? HasOpt<Opts['pick']> extends true ? HasOpt<Opts['omit']> extends true ? Opts extends {
|
|
249
|
+
partial: true;
|
|
250
|
+
} ? Partial<ApplyOmitToRecord<ApplyPickToRecord<R, Opts['pick']>, Opts['omit']>> : ApplyOmitToRecord<ApplyPickToRecord<R, Opts['pick']>, Opts['omit']> : Opts extends {
|
|
251
|
+
partial: true;
|
|
252
|
+
} ? Partial<ApplyPickToRecord<R, Opts['pick']>> : ApplyPickToRecord<R, Opts['pick']> : HasOpt<Opts['omit']> extends true ? Opts extends {
|
|
253
|
+
partial: true;
|
|
254
|
+
} ? Partial<ApplyOmitToRecord<R, Opts['omit']>> : ApplyOmitToRecord<R, Opts['omit']> : Opts extends {
|
|
255
|
+
partial: true;
|
|
256
|
+
} ? Partial<R> : R : R;
|
|
146
257
|
/**
|
|
147
258
|
* @internal
|
|
148
259
|
* Mirrors @hono/zod-validator's middleware Input type.
|
|
149
260
|
* Aligned with @hono/zod-validator@0.4.x; revisit on version bump.
|
|
150
261
|
*/
|
|
151
262
|
type HasUndefined<T> = undefined extends T ? true : false;
|
|
152
|
-
|
|
263
|
+
/**
|
|
264
|
+
* @internal
|
|
265
|
+
* Hono middleware input/output type for validator middleware.
|
|
266
|
+
* Aligned with @hono/zod-validator@0.4.x; revisit on version bump.
|
|
267
|
+
*
|
|
268
|
+
* WARNING (Zod 4): `z.input<ZodTypeAny>` resolves to `unknown` in Zod 4, making
|
|
269
|
+
* `c.req.valid(target)` return `unknown` if `In`/`Out` are left as defaults.
|
|
270
|
+
* When using this type directly (outside of `ModelValidatorReturn`), always pass
|
|
271
|
+
* explicit `In` and `Out` type arguments — do NOT rely on the defaults.
|
|
272
|
+
*
|
|
273
|
+
* Internal usages in this file (ModelValidatorReturn and preset overloads) already
|
|
274
|
+
* pass `In`/`Out` explicitly via `ApplyToRecord` or `Omit<RowType<Fields>, ...>`.
|
|
275
|
+
*/
|
|
276
|
+
type ValidatorInput<Target extends keyof ValidationTargets, Schema extends z.ZodTypeAny, In = z.input<Schema>, Out = z.output<Schema>> = {
|
|
153
277
|
in: HasUndefined<In> extends true ? {
|
|
154
278
|
[K in Target]?: (In extends ValidationTargets[K] ? In : {
|
|
155
279
|
[K2 in keyof In]?: ValidationTargets[K][K2] | undefined;
|
|
@@ -167,8 +291,11 @@ type ValidatorInput<Target extends keyof ValidationTargets, Schema extends z.Zod
|
|
|
167
291
|
* @internal
|
|
168
292
|
* Type-safe Hono middleware handler return for Model.validator().
|
|
169
293
|
* Provides proper type narrowing for c.req.valid(target).
|
|
294
|
+
*
|
|
295
|
+
* Uses RowType<Fields> directly for input/output type computation
|
|
296
|
+
* to ensure Zod v3/v4 compatibility (z.input<ZodTypeAny> returns unknown in Zod v4).
|
|
170
297
|
*/
|
|
171
|
-
type ModelValidatorReturn<Fields extends Record<string, Field<any, any, any>>, Target extends keyof ValidationTargets, Opts extends SchemaOptions<keyof Fields & string> | undefined> = MiddlewareHandler<any, string, ValidatorInput<Target, Apply<FieldsToZodShape<Fields>, Opts>>>;
|
|
298
|
+
type ModelValidatorReturn<Fields extends Record<string, Field<any, any, any>>, Target extends keyof ValidationTargets, Opts extends SchemaOptions<keyof Fields & string> | undefined> = MiddlewareHandler<any, string, ValidatorInput<Target, Apply<FieldsToZodShape<Fields>, Opts>, ApplyToRecord<RowType<Fields>, Opts>, ApplyToRecord<RowType<Fields>, Opts>>>;
|
|
172
299
|
|
|
173
300
|
/**
|
|
174
301
|
* Represents a database model with type-safe schema derivation and CRUD operations.
|
|
@@ -185,22 +312,60 @@ interface Model<Fields extends Record<string, Field<any, any, any>>> {
|
|
|
185
312
|
* const CreateSchema = User.schema({ omit: ['passwordHash'] })
|
|
186
313
|
* const UpdateSchema = User.schema({ partial: true, pick: ['name', 'email'] })
|
|
187
314
|
*/
|
|
188
|
-
schema<Opts extends SchemaOptions<keyof Fields & string> | undefined
|
|
315
|
+
schema<Opts extends SchemaOptions<keyof Fields & string> | undefined>(opts?: Opts): Apply<FieldsToZodShape<Fields>, Opts>;
|
|
189
316
|
/**
|
|
190
317
|
* Returns a Hono middleware validator derived from this model's schema.
|
|
191
318
|
* Integrates with @hono/zod-validator to validate request inputs.
|
|
192
319
|
* The optional `hook` argument is passed through to @hono/zod-validator.
|
|
193
320
|
*
|
|
321
|
+
* Accepts a preset ('create' | 'update') as second argument to use inputSchema.
|
|
322
|
+
* When a preset is used, the return type is a MiddlewareHandler (loosely typed in Phase 2A).
|
|
323
|
+
* Precise type narrowing for preset is deferred to Phase 2B M2.3.
|
|
324
|
+
*
|
|
194
325
|
* @example
|
|
326
|
+
* app.post('/users', User.validator('json', 'create'), c => {
|
|
327
|
+
* const body = c.req.valid('json')
|
|
328
|
+
* })
|
|
195
329
|
* app.post('/users', User.validator('json', { omit: ['passwordHash'] }), c => {
|
|
196
330
|
* const body = c.req.valid('json')
|
|
197
331
|
* })
|
|
198
|
-
* // With hook
|
|
332
|
+
* // With hook:
|
|
199
333
|
* app.post('/users', User.validator('json', opts, (result, c) => {
|
|
200
334
|
* if (!result.success) return c.json({ error: 'Invalid request' }, 400)
|
|
201
335
|
* }), handler)
|
|
202
336
|
*/
|
|
203
|
-
validator<Target extends keyof ValidationTargets,
|
|
337
|
+
validator<Target extends keyof ValidationTargets, E extends Env = Env, P extends string = string>(target: Target, preset: 'create', hook?: Hook<Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-create'> & string>, E, P, Target>): MiddlewareHandler<E, P, ValidatorInput<Target, z.ZodObject<z.ZodRawShape>, Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-create'> & string>, Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-create'> & string>>>;
|
|
338
|
+
validator<Target extends keyof ValidationTargets, E extends Env = Env, P extends string = string>(target: Target, preset: 'update', hook?: Hook<Partial<Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-update'> & string>>, E, P, Target>): MiddlewareHandler<E, P, ValidatorInput<Target, z.ZodObject<z.ZodRawShape>, Partial<Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-update'> & string>>, Partial<Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-update'> & string>>>>;
|
|
339
|
+
validator<Target extends keyof ValidationTargets, Opts extends SchemaOptions<keyof Fields & string> | undefined, E extends Env = Env, P extends string = string>(target: Target, opts?: Opts, hook?: Hook<z.output<Apply<FieldsToZodShape<Fields>, Opts>>, E, P, Target>): ModelValidatorReturn<Fields, Target, Opts>;
|
|
340
|
+
/**
|
|
341
|
+
* Returns a Zod schema for API input, with policy-based field exclusions applied.
|
|
342
|
+
* - 'create': serverOnly and readOnly fields are excluded
|
|
343
|
+
* - 'update': same exclusions + all fields become optional (partial: true)
|
|
344
|
+
*
|
|
345
|
+
* The return type precisely reflects policy-derived omissions using PolicyOmitKeys.
|
|
346
|
+
*/
|
|
347
|
+
inputSchema<Opts extends SchemaOptions<keyof Fields & string> | undefined = undefined>(usage: 'create', opts?: Opts): z.ZodObject<ApplyShape<Omit<FieldsToZodShape<Fields>, PolicyOmitKeys<Fields, 'input-create'> & string>, Opts>>;
|
|
348
|
+
inputSchema<Opts extends SchemaOptions<keyof Fields & string> | undefined = undefined>(usage: 'update', opts?: Opts): z.ZodObject<ApplyShape<Omit<FieldsToZodShape<Fields>, PolicyOmitKeys<Fields, 'input-update'> & string>, Opts extends undefined ? {
|
|
349
|
+
partial: true;
|
|
350
|
+
} : Opts & {
|
|
351
|
+
partial: true;
|
|
352
|
+
}>>;
|
|
353
|
+
inputSchema(usage: 'create' | 'update', opts?: SchemaOptions<keyof Fields & string>): z.ZodObject<z.ZodRawShape>;
|
|
354
|
+
/**
|
|
355
|
+
* Returns a Zod schema for API output, with policy-based field exclusions applied.
|
|
356
|
+
* - serverOnly and writeOnly fields are excluded
|
|
357
|
+
* - readOnly fields remain present
|
|
358
|
+
*
|
|
359
|
+
* The return type precisely reflects policy-derived omissions using PolicyOmitKeys.
|
|
360
|
+
*/
|
|
361
|
+
outputSchema<Opts extends SchemaOptions<keyof Fields & string> | undefined = undefined>(opts?: Opts): z.ZodObject<ApplyShape<Omit<FieldsToZodShape<Fields>, PolicyOmitKeys<Fields, 'output'> & string>, Opts>>;
|
|
362
|
+
/**
|
|
363
|
+
* Parses a DB row through outputSchema and returns the safe response object.
|
|
364
|
+
* Equivalent to `User.outputSchema().parse(row)`.
|
|
365
|
+
*/
|
|
366
|
+
toResponse(row: RowType<Fields>): unknown;
|
|
367
|
+
toOpenAPIComponent(): OpenAPIModelComponent;
|
|
368
|
+
toOpenAPISchema(usage: OpenAPIUsage): OpenAPISchemaObject;
|
|
204
369
|
/**
|
|
205
370
|
* Fetches multiple rows with pagination and optional ordering.
|
|
206
371
|
* `limit` is required (no default) to prevent accidental unbounded queries.
|
|
@@ -286,8 +451,25 @@ interface NanokaModel<Fields extends Record<string, Field<any, any, any>>> {
|
|
|
286
451
|
/**
|
|
287
452
|
* Returns a Hono middleware validator for this model.
|
|
288
453
|
* The optional `hook` argument is passed through to @hono/zod-validator.
|
|
454
|
+
* Accepts a preset ('create' | 'update') as second argument to use inputSchema.
|
|
289
455
|
*/
|
|
456
|
+
validator<Target extends keyof hono.ValidationTargets, E extends Env$1 = Env$1, P extends string = string>(target: Target, preset: 'create', hook?: Hook<Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-create'> & string>, E, P, Target>): MiddlewareHandler<E, P, ValidatorInput<Target, z.ZodObject<z.ZodRawShape>, Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-create'> & string>, Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-create'> & string>>>;
|
|
457
|
+
validator<Target extends keyof hono.ValidationTargets, E extends Env$1 = Env$1, P extends string = string>(target: Target, preset: 'update', hook?: Hook<Partial<Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-update'> & string>>, E, P, Target>): MiddlewareHandler<E, P, ValidatorInput<Target, z.ZodObject<z.ZodRawShape>, Partial<Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-update'> & string>>, Partial<Omit<RowType<Fields>, PolicyOmitKeys<Fields, 'input-update'> & string>>>>;
|
|
290
458
|
validator<Target extends keyof hono.ValidationTargets, Opts extends SchemaOptions<keyof Fields & string> | undefined = undefined, E extends Env$1 = Env$1, P extends string = string>(target: Target, opts?: Opts, hook?: Hook<z.output<Apply<FieldsToZodShape<Fields>, Opts>>, E, P, Target>): ModelValidatorReturn<Fields, Target, Opts>;
|
|
459
|
+
/**
|
|
460
|
+
* Returns a Zod schema for API input, with policy-based field exclusions applied.
|
|
461
|
+
*/
|
|
462
|
+
inputSchema(usage: 'create' | 'update', opts?: SchemaOptions<keyof Fields & string>): z.ZodObject<z.ZodRawShape>;
|
|
463
|
+
/**
|
|
464
|
+
* Returns a Zod schema for API output, with policy-based field exclusions applied.
|
|
465
|
+
*/
|
|
466
|
+
outputSchema(opts?: SchemaOptions<keyof Fields & string>): z.ZodObject<z.ZodRawShape>;
|
|
467
|
+
/**
|
|
468
|
+
* Parses a DB row through outputSchema and returns the safe response object.
|
|
469
|
+
*/
|
|
470
|
+
toResponse(row: RowType<Fields>): unknown;
|
|
471
|
+
toOpenAPIComponent(): OpenAPIModelComponent;
|
|
472
|
+
toOpenAPISchema(usage: OpenAPIUsage): OpenAPISchemaObject;
|
|
291
473
|
/**
|
|
292
474
|
* Fetches multiple rows with pagination and optional ordering.
|
|
293
475
|
* `limit` is required (no default) to prevent accidental unbounded queries.
|
|
@@ -364,4 +546,4 @@ interface Nanoka<E extends Env$1 = BlankEnv> extends Hono<E> {
|
|
|
364
546
|
*/
|
|
365
547
|
declare function nanoka<E extends Env$1 = BlankEnv>(adapter: Adapter): Nanoka<E>;
|
|
366
548
|
|
|
367
|
-
export { type Adapter, type CreateInput, Field, type FindManyOptions, type IdOrWhere, InferFieldType, type Model, type Nanoka, type NanokaModel, type OrderBy, type RowType, type SchemaOptions, type Where, d1Adapter, defineModel, nanoka };
|
|
549
|
+
export { type Adapter, type CreateInput, Field, FieldPolicy, type FindManyOptions, type IdOrWhere, InferFieldType, type Model, type Nanoka, type NanokaModel, type OpenAPIModelComponent, type OpenAPISchemaObject, type OpenAPIUsage, type OrderBy, type RowType, type SchemaOptions, type Where, d1Adapter, defineModel, nanoka };
|