@drzl/analyzer 1.17.1 → 1.17.2

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/README.md CHANGED
@@ -51,7 +51,7 @@ Per column, beyond the type: `nullable`, `hasDefault`, `defaultValue` (literal d
51
51
  `isGenerated`, `enumValues`, `maxLength` (characters), `maxBytes` (MySQL's TEXT family is a byte
52
52
  budget, which is a different measurement on the same kind of column), `min`/`max`,
53
53
  `arrayDimensions`, `format`, and `shape` for values that are not scalars (json, buffer, tuple,
54
- vector, bitstring, customType).
54
+ numberObject, vector, bitstring, customType).
55
55
 
56
56
  `DRZL_ANL_UNKNOWN_COLUMN` is reported for any column whose validator would accept anything, which
57
57
  is the shape a missing type mapping takes: nothing throws, and every row passes.
package/dist/index.cjs CHANGED
@@ -63,13 +63,18 @@ var PG_FLOAT4_INPUT_MAX = "340282356779733661637539395458142568448";
63
63
  var PG_FLOAT4_RANGE = [`-${PG_FLOAT4_INPUT_MAX}`, PG_FLOAT4_INPUT_MAX];
64
64
  var MYSQL_FLOAT_RANGE = [`-${FLOAT32_MAX}`, FLOAT32_MAX];
65
65
  var JS_SAFE_INTEGER_BOUNDS = ["-9007199254740991", "9007199254740991"];
66
- var TUPLE_CLASS_SHAPES = {
66
+ var GEOMETRIC_CLASS_SHAPES = {
67
67
  // `line()` is the trap here: its `drizzle:entityKind` is `PgLine` while its constructor is
68
68
  // `PgLineTuple`, and this path matches on the constructor.
69
69
  PgPointTuple: { kind: "tuple", length: 2 },
70
- PgLineTuple: { kind: "tuple", length: 3 }
70
+ PgLineTuple: { kind: "tuple", length: 3 },
71
+ // The object modes. `line({ mode: 'abc' })` is a `PgLineABC` and not a `PgLineObject`, and any
72
+ // mode but `'tuple'` builds the object class: `point({ mode: 'abc' })` is a `PgPointObject` too.
73
+ PgPointObject: { kind: "numberObject", fields: ["x", "y"] },
74
+ PgLineABC: { kind: "numberObject", fields: ["a", "b", "c"] }
71
75
  };
72
76
  var V1_ONLY_ENTITY_KINDS = /^(?:MsSql|Cockroach)/;
77
+ var NUMBER_VECTOR_CLASSES = /* @__PURE__ */ new Set(["PgVector", "PgHalfVector"]);
73
78
  var BYTE_STRING_CLASSES = /* @__PURE__ */ new Set([
74
79
  "MySqlBinary",
75
80
  "MySqlVarBinary",
@@ -190,18 +195,38 @@ function describeV1Column(column) {
190
195
  };
191
196
  break;
192
197
  }
198
+ // Two modes per builder, and v1 states which in the JS half of the dataType it already
199
+ // carries: the tuple modes say `array point` / `array line` / `array geometry` and the object
200
+ // modes say `object point` / `object line` / `object geometry`. Read off real 1.0.0-rc.4
201
+ // columns rather than assumed. Both used to reach these arms and be called tuples, so a select
202
+ // schema for `point({ mode: 'xy' })` rejected every row the driver returned, on the major that
203
+ // describes the column outright.
204
+ //
205
+ // `js` rather than the codec, which also distinguishes them here (`point:tuple` against
206
+ // `point`): three dialects state a semantic with no codec at all on this release, so the codec
207
+ // is the weaker of the two signals and this file already prefers `js` elsewhere for the same
208
+ // reason.
193
209
  case "point":
194
210
  case "geometry":
195
- out.tsType = "[number, number]";
211
+ out.tsType = js === "object" ? "{ x: number; y: number }" : "[number, number]";
196
212
  out.dbType = semantic.toUpperCase();
197
- out.shape = { kind: "tuple", length: 2 };
213
+ out.shape = js === "object" ? { kind: "numberObject", fields: ["x", "y"] } : { kind: "tuple", length: 2 };
198
214
  break;
199
215
  case "line":
200
- out.tsType = "[number, number, number]";
216
+ out.tsType = js === "object" ? "{ a: number; b: number; c: number }" : "[number, number, number]";
201
217
  out.dbType = "LINE";
202
- out.shape = { kind: "tuple", length: 3 };
218
+ out.shape = js === "object" ? { kind: "numberObject", fields: ["a", "b", "c"] } : { kind: "tuple", length: 3 };
203
219
  break;
220
+ // `halfvec` beside `vector`, because they differ in storage width and in nothing a validator
221
+ // can see: `mapFromDriverValue` on both hands back `[1, 2, 3]`. It had no arm and came back
222
+ // `unknown` on this path too, which the fuzzer found.
223
+ //
224
+ // `sparsevec` is deliberately not here. Its name says vector and its value is the string
225
+ // `{1:1.5,3:2}/3`, so typing it `number[]` for symmetry would reject every row the database
226
+ // returns. Its codec already answers `string` on its own, which is the same conclusion reached
227
+ // without this arm.
204
228
  case "vector":
229
+ case "halfvec":
205
230
  out.tsType = "number[]";
206
231
  out.dbType = "VECTOR";
207
232
  out.shape = { kind: "numberVector", length: declaredLength(column) };
@@ -593,6 +618,23 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
593
618
  case "MySqlEnumColumn":
594
619
  case "SingleStoreEnumColumn":
595
620
  return { tsType: "string", dbType: "TEXT" };
621
+ // The pgvector family, found by the analyzer fuzzer: all three came back `unknown` on this
622
+ // path, so their validators accepted anything. The answers are drizzle's own mappers rather
623
+ // than the type names, and the three do not agree with each other:
624
+ //
625
+ // vector(3) SELECT gives [1,2,3] INSERT sends "[1,2,3]"
626
+ // halfvec(3) SELECT gives [1,2,3] INSERT sends "[1,2,3]"
627
+ // sparsevec(3) SELECT gives "{1:1.5,3:2}/3" INSERT sends "{1:1.5,3:2}/3"
628
+ //
629
+ // So the two dense ones are number arrays and the sparse one is a string. Typing `sparsevec`
630
+ // as a vector for symmetry would reject every row the database returns, which is the defect
631
+ // this family was filed under to begin with. The `shape` carries the dimension count where
632
+ // one is declared, as the codec path already did for `vector`.
633
+ case "PgVector":
634
+ case "PgHalfVector":
635
+ return { tsType: "number[]", dbType: "VECTOR" };
636
+ case "PgSparseVector":
637
+ return { tsType: "string", dbType: "TEXT" };
596
638
  case "PgInteger":
597
639
  case "PgSmallInt":
598
640
  return { tsType: "number", dbType: "INTEGER" };
@@ -658,6 +700,15 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
658
700
  return { tsType: "[number, number]", dbType: "POINT" };
659
701
  case "PgLineTuple":
660
702
  return { tsType: "[number, number, number]", dbType: "LINE" };
703
+ // The object modes, which the same regex answered `string` for and which are not tuples
704
+ // either. `point({ mode: 'xy' })` returns `{ x, y }` and `line({ mode: 'abc' })` returns
705
+ // `{ a, b, c }`, read back from PGlite through drizzle 0.45.2; the same column refuses
706
+ // `[1, 2]` and `'1,2'`, both of which `mapToDriverValue` renders `(undefined,undefined)`.
707
+ // v1 says the same thing about the same two columns through `dataType: 'object point'`.
708
+ case "PgPointObject":
709
+ return { tsType: "{ x: number; y: number }", dbType: "POINT" };
710
+ case "PgLineABC":
711
+ return { tsType: "{ a: number; b: number; c: number }", dbType: "LINE" };
661
712
  case "PgJson":
662
713
  case "PgJsonb":
663
714
  return { tsType: "any", dbType: ctor === "PgJsonb" ? "JSONB" : "JSON" };
@@ -678,7 +729,6 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
678
729
  if (/^Pg/.test(ctor)) {
679
730
  if (/Text|Varchar|Char|Uuid/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
680
731
  if (/Inet|Cidr|Macaddr8?|Uuid/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
681
- if (/Point|Line/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
682
732
  if (/TimestampString|DateString/i.test(ctor))
683
733
  return { tsType: "string", dbType: "TIMESTAMP" };
684
734
  if (/Timestamptz/i.test(ctor)) return { tsType: "Date", dbType: "TIMESTAMPTZ" };
@@ -800,7 +850,7 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
800
850
  const sqlType = sqlKind.startsWith("MySql") && typeof col?.getSQLType === "function" ? String(col.getSQLType()).toLowerCase() : void 0;
801
851
  const byteCap = sqlType ? MYSQL_TEXT_CAPS[sqlType] : void 0;
802
852
  const ctorName = String(col?.constructor?.name ?? "");
803
- const fallbackShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : BYTE_STRING_CLASSES.has(ctorName) ? { kind: "byteString", length: declaredLength(col) } : TUPLE_CLASS_SHAPES[ctorName];
853
+ const fallbackShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : BYTE_STRING_CLASSES.has(ctorName) ? { kind: "byteString", length: declaredLength(col) } : NUMBER_VECTOR_CLASSES.has(ctorName) ? { kind: "numberVector", length: declaredLength(col) } : GEOMETRIC_CLASS_SHAPES[ctorName];
804
854
  if (fallbackShape?.kind === "byteString") delete constraints.maxLength;
805
855
  const shape = (v1?.shape ?? fallbackShape)?.kind;
806
856
  const finalTs = v1?.tsType ?? tsType;
package/dist/index.d.cts CHANGED
@@ -121,11 +121,33 @@ type ColumnShape =
121
121
  | {
122
122
  kind: 'json';
123
123
  }
124
- /** `point`, `line`, `geometry`: a fixed-length tuple of numbers. */
124
+ /** `point`, `line`, `geometry` in their tuple modes: a fixed-length tuple of numbers. */
125
125
  | {
126
126
  kind: 'tuple';
127
127
  length: number;
128
128
  }
129
+ /**
130
+ * The same three columns in their object modes: an object of named number fields.
131
+ *
132
+ * `point({ mode: 'xy' })` hands back `{ x, y }`, `line({ mode: 'abc' })` hands back
133
+ * `{ a, b, c }`, and `geometry({ type: 'point', mode: 'xy' })` hands back `{ x, y }`. The names
134
+ * are carried rather than derived from a length, because the two arities have different keys and
135
+ * nothing else on the column states them.
136
+ *
137
+ * Not a tuple, on either major, and the difference is a value the database refuses. Asked of
138
+ * PGlite through drizzle 0.45.2 and again through 1.0.0-rc.4: `mapToDriverValue` reads `.x`/`.y`
139
+ * off whatever it is handed, so `[1, 2]` and `'1,2'` both become the literal
140
+ * `(undefined,undefined)` and Postgres answers `invalid input syntax for type point`, while
141
+ * `{ x: 1.5, y: -2.25 }` is stored as `(1.5,-2.25)` and read back unchanged.
142
+ *
143
+ * Every field is required and unlisted keys are ignored, both measured on the same server:
144
+ * `{ x: 1 }` renders `(1,undefined)` and is refused, and `{ x: 1, y: 2, z: 3 }` is accepted and
145
+ * stored as `(1,2)`.
146
+ */
147
+ | {
148
+ kind: 'numberObject';
149
+ fields: string[];
150
+ }
129
151
  /** `vector`, `halfvec`: a numeric vector, with a fixed length where one is declared. */
130
152
  | {
131
153
  kind: 'numberVector';
package/dist/index.d.ts CHANGED
@@ -121,11 +121,33 @@ type ColumnShape =
121
121
  | {
122
122
  kind: 'json';
123
123
  }
124
- /** `point`, `line`, `geometry`: a fixed-length tuple of numbers. */
124
+ /** `point`, `line`, `geometry` in their tuple modes: a fixed-length tuple of numbers. */
125
125
  | {
126
126
  kind: 'tuple';
127
127
  length: number;
128
128
  }
129
+ /**
130
+ * The same three columns in their object modes: an object of named number fields.
131
+ *
132
+ * `point({ mode: 'xy' })` hands back `{ x, y }`, `line({ mode: 'abc' })` hands back
133
+ * `{ a, b, c }`, and `geometry({ type: 'point', mode: 'xy' })` hands back `{ x, y }`. The names
134
+ * are carried rather than derived from a length, because the two arities have different keys and
135
+ * nothing else on the column states them.
136
+ *
137
+ * Not a tuple, on either major, and the difference is a value the database refuses. Asked of
138
+ * PGlite through drizzle 0.45.2 and again through 1.0.0-rc.4: `mapToDriverValue` reads `.x`/`.y`
139
+ * off whatever it is handed, so `[1, 2]` and `'1,2'` both become the literal
140
+ * `(undefined,undefined)` and Postgres answers `invalid input syntax for type point`, while
141
+ * `{ x: 1.5, y: -2.25 }` is stored as `(1.5,-2.25)` and read back unchanged.
142
+ *
143
+ * Every field is required and unlisted keys are ignored, both measured on the same server:
144
+ * `{ x: 1 }` renders `(1,undefined)` and is refused, and `{ x: 1, y: 2, z: 3 }` is accepted and
145
+ * stored as `(1,2)`.
146
+ */
147
+ | {
148
+ kind: 'numberObject';
149
+ fields: string[];
150
+ }
129
151
  /** `vector`, `halfvec`: a numeric vector, with a fixed length where one is declared. */
130
152
  | {
131
153
  kind: 'numberVector';
package/dist/index.js CHANGED
@@ -22,13 +22,18 @@ var PG_FLOAT4_INPUT_MAX = "340282356779733661637539395458142568448";
22
22
  var PG_FLOAT4_RANGE = [`-${PG_FLOAT4_INPUT_MAX}`, PG_FLOAT4_INPUT_MAX];
23
23
  var MYSQL_FLOAT_RANGE = [`-${FLOAT32_MAX}`, FLOAT32_MAX];
24
24
  var JS_SAFE_INTEGER_BOUNDS = ["-9007199254740991", "9007199254740991"];
25
- var TUPLE_CLASS_SHAPES = {
25
+ var GEOMETRIC_CLASS_SHAPES = {
26
26
  // `line()` is the trap here: its `drizzle:entityKind` is `PgLine` while its constructor is
27
27
  // `PgLineTuple`, and this path matches on the constructor.
28
28
  PgPointTuple: { kind: "tuple", length: 2 },
29
- PgLineTuple: { kind: "tuple", length: 3 }
29
+ PgLineTuple: { kind: "tuple", length: 3 },
30
+ // The object modes. `line({ mode: 'abc' })` is a `PgLineABC` and not a `PgLineObject`, and any
31
+ // mode but `'tuple'` builds the object class: `point({ mode: 'abc' })` is a `PgPointObject` too.
32
+ PgPointObject: { kind: "numberObject", fields: ["x", "y"] },
33
+ PgLineABC: { kind: "numberObject", fields: ["a", "b", "c"] }
30
34
  };
31
35
  var V1_ONLY_ENTITY_KINDS = /^(?:MsSql|Cockroach)/;
36
+ var NUMBER_VECTOR_CLASSES = /* @__PURE__ */ new Set(["PgVector", "PgHalfVector"]);
32
37
  var BYTE_STRING_CLASSES = /* @__PURE__ */ new Set([
33
38
  "MySqlBinary",
34
39
  "MySqlVarBinary",
@@ -149,18 +154,38 @@ function describeV1Column(column) {
149
154
  };
150
155
  break;
151
156
  }
157
+ // Two modes per builder, and v1 states which in the JS half of the dataType it already
158
+ // carries: the tuple modes say `array point` / `array line` / `array geometry` and the object
159
+ // modes say `object point` / `object line` / `object geometry`. Read off real 1.0.0-rc.4
160
+ // columns rather than assumed. Both used to reach these arms and be called tuples, so a select
161
+ // schema for `point({ mode: 'xy' })` rejected every row the driver returned, on the major that
162
+ // describes the column outright.
163
+ //
164
+ // `js` rather than the codec, which also distinguishes them here (`point:tuple` against
165
+ // `point`): three dialects state a semantic with no codec at all on this release, so the codec
166
+ // is the weaker of the two signals and this file already prefers `js` elsewhere for the same
167
+ // reason.
152
168
  case "point":
153
169
  case "geometry":
154
- out.tsType = "[number, number]";
170
+ out.tsType = js === "object" ? "{ x: number; y: number }" : "[number, number]";
155
171
  out.dbType = semantic.toUpperCase();
156
- out.shape = { kind: "tuple", length: 2 };
172
+ out.shape = js === "object" ? { kind: "numberObject", fields: ["x", "y"] } : { kind: "tuple", length: 2 };
157
173
  break;
158
174
  case "line":
159
- out.tsType = "[number, number, number]";
175
+ out.tsType = js === "object" ? "{ a: number; b: number; c: number }" : "[number, number, number]";
160
176
  out.dbType = "LINE";
161
- out.shape = { kind: "tuple", length: 3 };
177
+ out.shape = js === "object" ? { kind: "numberObject", fields: ["a", "b", "c"] } : { kind: "tuple", length: 3 };
162
178
  break;
179
+ // `halfvec` beside `vector`, because they differ in storage width and in nothing a validator
180
+ // can see: `mapFromDriverValue` on both hands back `[1, 2, 3]`. It had no arm and came back
181
+ // `unknown` on this path too, which the fuzzer found.
182
+ //
183
+ // `sparsevec` is deliberately not here. Its name says vector and its value is the string
184
+ // `{1:1.5,3:2}/3`, so typing it `number[]` for symmetry would reject every row the database
185
+ // returns. Its codec already answers `string` on its own, which is the same conclusion reached
186
+ // without this arm.
163
187
  case "vector":
188
+ case "halfvec":
164
189
  out.tsType = "number[]";
165
190
  out.dbType = "VECTOR";
166
191
  out.shape = { kind: "numberVector", length: declaredLength(column) };
@@ -552,6 +577,23 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
552
577
  case "MySqlEnumColumn":
553
578
  case "SingleStoreEnumColumn":
554
579
  return { tsType: "string", dbType: "TEXT" };
580
+ // The pgvector family, found by the analyzer fuzzer: all three came back `unknown` on this
581
+ // path, so their validators accepted anything. The answers are drizzle's own mappers rather
582
+ // than the type names, and the three do not agree with each other:
583
+ //
584
+ // vector(3) SELECT gives [1,2,3] INSERT sends "[1,2,3]"
585
+ // halfvec(3) SELECT gives [1,2,3] INSERT sends "[1,2,3]"
586
+ // sparsevec(3) SELECT gives "{1:1.5,3:2}/3" INSERT sends "{1:1.5,3:2}/3"
587
+ //
588
+ // So the two dense ones are number arrays and the sparse one is a string. Typing `sparsevec`
589
+ // as a vector for symmetry would reject every row the database returns, which is the defect
590
+ // this family was filed under to begin with. The `shape` carries the dimension count where
591
+ // one is declared, as the codec path already did for `vector`.
592
+ case "PgVector":
593
+ case "PgHalfVector":
594
+ return { tsType: "number[]", dbType: "VECTOR" };
595
+ case "PgSparseVector":
596
+ return { tsType: "string", dbType: "TEXT" };
555
597
  case "PgInteger":
556
598
  case "PgSmallInt":
557
599
  return { tsType: "number", dbType: "INTEGER" };
@@ -617,6 +659,15 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
617
659
  return { tsType: "[number, number]", dbType: "POINT" };
618
660
  case "PgLineTuple":
619
661
  return { tsType: "[number, number, number]", dbType: "LINE" };
662
+ // The object modes, which the same regex answered `string` for and which are not tuples
663
+ // either. `point({ mode: 'xy' })` returns `{ x, y }` and `line({ mode: 'abc' })` returns
664
+ // `{ a, b, c }`, read back from PGlite through drizzle 0.45.2; the same column refuses
665
+ // `[1, 2]` and `'1,2'`, both of which `mapToDriverValue` renders `(undefined,undefined)`.
666
+ // v1 says the same thing about the same two columns through `dataType: 'object point'`.
667
+ case "PgPointObject":
668
+ return { tsType: "{ x: number; y: number }", dbType: "POINT" };
669
+ case "PgLineABC":
670
+ return { tsType: "{ a: number; b: number; c: number }", dbType: "LINE" };
620
671
  case "PgJson":
621
672
  case "PgJsonb":
622
673
  return { tsType: "any", dbType: ctor === "PgJsonb" ? "JSONB" : "JSON" };
@@ -637,7 +688,6 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
637
688
  if (/^Pg/.test(ctor)) {
638
689
  if (/Text|Varchar|Char|Uuid/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
639
690
  if (/Inet|Cidr|Macaddr8?|Uuid/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
640
- if (/Point|Line/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
641
691
  if (/TimestampString|DateString/i.test(ctor))
642
692
  return { tsType: "string", dbType: "TIMESTAMP" };
643
693
  if (/Timestamptz/i.test(ctor)) return { tsType: "Date", dbType: "TIMESTAMPTZ" };
@@ -759,7 +809,7 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
759
809
  const sqlType = sqlKind.startsWith("MySql") && typeof col?.getSQLType === "function" ? String(col.getSQLType()).toLowerCase() : void 0;
760
810
  const byteCap = sqlType ? MYSQL_TEXT_CAPS[sqlType] : void 0;
761
811
  const ctorName = String(col?.constructor?.name ?? "");
762
- const fallbackShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : BYTE_STRING_CLASSES.has(ctorName) ? { kind: "byteString", length: declaredLength(col) } : TUPLE_CLASS_SHAPES[ctorName];
812
+ const fallbackShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : BYTE_STRING_CLASSES.has(ctorName) ? { kind: "byteString", length: declaredLength(col) } : NUMBER_VECTOR_CLASSES.has(ctorName) ? { kind: "numberVector", length: declaredLength(col) } : GEOMETRIC_CLASS_SHAPES[ctorName];
763
813
  if (fallbackShape?.kind === "byteString") delete constraints.maxLength;
764
814
  const shape = (v1?.shape ?? fallbackShape)?.kind;
765
815
  const finalTs = v1?.tsType ?? tsType;
package/package.json CHANGED
@@ -1,16 +1,22 @@
1
1
  {
2
2
  "name": "@drzl/analyzer",
3
- "version": "1.17.1",
3
+ "version": "1.17.2",
4
4
  "private": false,
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
- "main": "dist/index.js",
8
- "types": "dist/index.d.ts",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
9
10
  "exports": {
10
11
  ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js",
13
- "require": "./dist/index.cjs"
12
+ "import": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "require": {
17
+ "types": "./dist/index.d.cts",
18
+ "default": "./dist/index.cjs"
19
+ }
14
20
  }
15
21
  },
16
22
  "files": [
@@ -22,6 +28,7 @@
22
28
  },
23
29
  "devDependencies": {
24
30
  "drizzle-orm": "^0.45.2",
31
+ "drizzle-orm-v1": "npm:drizzle-orm@1.0.0-rc.4",
25
32
  "tsup": "^8.5.1",
26
33
  "typescript": "^5.9.3"
27
34
  },
@@ -45,6 +52,8 @@
45
52
  "scripts": {
46
53
  "build": "tsup src/index.ts --dts --format esm,cjs --clean",
47
54
  "lint": "eslint . --ext .ts",
48
- "test": "vitest run --testTimeout=20000"
55
+ "test": "vitest run --testTimeout=20000",
56
+ "fuzz": "node test/fuzz/run.mjs",
57
+ "fuzz:gate": "node test/fuzz/run.mjs --gate"
49
58
  }
50
59
  }