@flowblade/sqlduck 0.12.0 → 0.14.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/README.md CHANGED
@@ -29,7 +29,7 @@ import { conn } from "./db.config.ts";
29
29
 
30
30
  const dbManager = new DuckDatabaseManager(conn);
31
31
  const database = await dbManager.attach({
32
- type: 'memory', // can be 'duckdb', ...
32
+ type: 'memory', // can be 'filesystem', ...
33
33
  alias: 'mydb',
34
34
  options: { COMPRESS: 'false' },
35
35
  });
@@ -0,0 +1,118 @@
1
+ //#region src/validation/core/base-validators.ts
2
+ const duckIdentifierNameRegex = /^[a-z_]\w*$/i;
3
+ const duckStorageVersionRegexp = /^v?\d{1,4}\.\d{1,4}\.\d{1,4}$/;
4
+ //#endregion
5
+ //#region src/validation/core/duck-connections-options.ts
6
+ const duckConnectionsOptions = { types: [
7
+ "DUCKDB",
8
+ "SQLITE",
9
+ "MYSQL",
10
+ "PostgreSQL"
11
+ ] };
12
+ //#endregion
13
+ //#region src/validation/core/duck-reserved-keywords.ts
14
+ /**
15
+ * DuckDB reserved keywords that cannot be used as unquoted identifiers.
16
+ * @see https://duckdb.org/docs/sql/keywords-and-identifiers.html
17
+ */
18
+ const duckReservedKeywords = [
19
+ "ALL",
20
+ "ANALYSE",
21
+ "ANALYZE",
22
+ "AND",
23
+ "ANY",
24
+ "ARRAY",
25
+ "AS",
26
+ "ASC",
27
+ "ASYMMETRIC",
28
+ "BOTH",
29
+ "CASE",
30
+ "CAST",
31
+ "CHECK",
32
+ "COLLATE",
33
+ "COLUMN",
34
+ "CONSTRAINT",
35
+ "CREATE",
36
+ "CROSS",
37
+ "CURRENT_CATALOG",
38
+ "CURRENT_DATE",
39
+ "CURRENT_ROLE",
40
+ "CURRENT_SCHEMA",
41
+ "CURRENT_TIME",
42
+ "CURRENT_TIMESTAMP",
43
+ "CURRENT_USER",
44
+ "DEFAULT",
45
+ "DEFERRABLE",
46
+ "DESC",
47
+ "DISTINCT",
48
+ "DO",
49
+ "ELSE",
50
+ "END",
51
+ "EXCEPT",
52
+ "EXISTS",
53
+ "EXTRACT",
54
+ "FALSE",
55
+ "FETCH",
56
+ "FOR",
57
+ "FOREIGN",
58
+ "FROM",
59
+ "GRANT",
60
+ "GROUP",
61
+ "HAVING",
62
+ "IF",
63
+ "ILIKE",
64
+ "IN",
65
+ "INITIALLY",
66
+ "INNER",
67
+ "INTERSECT",
68
+ "INTO",
69
+ "IS",
70
+ "ISNULL",
71
+ "JOIN",
72
+ "LATERAL",
73
+ "LEADING",
74
+ "LEFT",
75
+ "LIKE",
76
+ "LIMIT",
77
+ "LOCALTIME",
78
+ "LOCALTIMESTAMP",
79
+ "NATURAL",
80
+ "NOT",
81
+ "NOTNULL",
82
+ "NULL",
83
+ "OFFSET",
84
+ "ON",
85
+ "ONLY",
86
+ "OR",
87
+ "ORDER",
88
+ "OUTER",
89
+ "OVERLAPS",
90
+ "PLACING",
91
+ "PRIMARY",
92
+ "REFERENCES",
93
+ "RETURNING",
94
+ "RIGHT",
95
+ "ROW",
96
+ "SELECT",
97
+ "SESSION_USER",
98
+ "SIMILAR",
99
+ "SOME",
100
+ "SYMMETRIC",
101
+ "TABLE",
102
+ "THEN",
103
+ "TO",
104
+ "TRAILING",
105
+ "TRUE",
106
+ "UNION",
107
+ "UNIQUE",
108
+ "USING",
109
+ "VARIADIC",
110
+ "VERBOSE",
111
+ "WHEN",
112
+ "WHERE",
113
+ "WINDOW",
114
+ "WITH"
115
+ ];
116
+ const duckdbReservedKeywordsSet = new Set(duckReservedKeywords);
117
+ //#endregion
118
+ export { duckStorageVersionRegexp as a, duckIdentifierNameRegex as i, duckdbReservedKeywordsSet as n, duckConnectionsOptions as r, duckReservedKeywords as t };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as DuckConnectionParams } from "./types-DCqYqEsa.mjs";
1
+ import { n as DuckConnectionParams } from "./types-dnhcognF.mjs";
2
2
  import * as _$_duckdb_node_api0 from "@duckdb/node-api";
3
3
  import { DuckDBConnection, DuckDBType } from "@duckdb/node-api";
4
4
  import * as _$_logtape_logtape0 from "@logtape/logtape";
@@ -143,6 +143,13 @@ type ToTableParams<TSchema extends TableSchemaZod> = {
143
143
  * @default true
144
144
  */
145
145
  autoCheckpoint?: boolean;
146
+ /**
147
+ * Checkpoint the table after 'n' chunks have been appended
148
+ *
149
+ * For example if the chunkSize is 2048, setting frequency to 2
150
+ * will checkpoint the table every 4096 rows (2x chunksize)
151
+ */
152
+ checkpointChunksFrequency?: number;
146
153
  };
147
154
  type ToTableResult = {
148
155
  /**
@@ -251,7 +258,7 @@ declare class DuckDatabaseManager {
251
258
  * ```typescript
252
259
  * const dbManager = new DuckDatabaseManager(conn);
253
260
  * const database = dbManager.attach({
254
- * type: 'memory', // can be 'duckdb', 's3'...
261
+ * type: 'memory', // can be 'filesystem'...
255
262
  * alias: 'mydb',
256
263
  * options: { COMPRESS: 'true' }
257
264
  * });
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
- import { a as assertValidAliasName, c as duckValidatorsZod, i as duckConnectionParamsZodSchema, l as duckReservedKeywords } from "./zod-CwR_oehs.mjs";
1
+ import { t as duckReservedKeywords } from "./duck-reserved-keywords-CUmaTbrD.mjs";
2
+ import { n as assertValidAliasName, o as duckConnectionParamsZodSchema, s as duckValidatorsZod } from "./zod-BRUUIdGW.mjs";
2
3
  import { BIGINT, BOOLEAN, DOUBLE, DuckDBDataChunk, DuckDBTimestampValue, FLOAT, HUGEINT, INTEGER, SMALLINT, TIMESTAMP, TINYINT, UBIGINT, UHUGEINT, UINTEGER, USMALLINT, UTINYINT, UUID, VARCHAR } from "@duckdb/node-api";
3
4
  import { getLogger } from "@logtape/logtape";
4
5
  import * as z from "zod";
@@ -163,7 +164,7 @@ var DuckDatabaseAttachCommand = class {
163
164
  case "memory":
164
165
  parts.push("':memory:'");
165
166
  break;
166
- case "duckdb":
167
+ case "filesystem":
167
168
  parts.push(`'${dbParams.path}'`);
168
169
  break;
169
170
  default: assertNever(type);
@@ -217,7 +218,7 @@ var DuckDatabaseManager = class {
217
218
  * ```typescript
218
219
  * const dbManager = new DuckDatabaseManager(conn);
219
220
  * const database = dbManager.attach({
220
- * type: 'memory', // can be 'duckdb', 's3'...
221
+ * type: 'memory', // can be 'filesystem'...
221
222
  * alias: 'mydb',
222
223
  * options: { COMPRESS: 'true' }
223
224
  * });
@@ -277,7 +278,7 @@ var DuckDatabaseManager = class {
277
278
  const result = await this.#conn.runAndReadAll(rawSql);
278
279
  const timeMs = Math.round(Date.now() - startTime);
279
280
  const data = result.getRowObjectsJS();
280
- this.#logger.info(`DuckDatabaseManager.${name} in ${timeMs}ms`, { timeMs });
281
+ this.#logger.debug(`DuckDatabaseManager.${name} in ${timeMs}ms`, { timeMs });
281
282
  return data;
282
283
  } catch (e) {
283
284
  const msg = `DuckDatabaseManager: failed to run "${name}" - ${e?.message ?? ""}`;
@@ -514,8 +515,12 @@ var SqlDuck = class {
514
515
  * ```
515
516
  */
516
517
  toTable = async (params) => {
517
- const { table, schema, chunkSize = 2048, rowStream, createOptions, onDataAppended, autoCheckpoint = true } = params;
518
+ const { table, schema, chunkSize = 2048, rowStream, createOptions, onDataAppended, autoCheckpoint = true, checkpointChunksFrequency = 10 } = params;
518
519
  if (!Number.isSafeInteger(chunkSize) || chunkSize < 1 || chunkSize > 2048) throw new Error("chunkSize must be a number between 1 and 2048");
520
+ if (autoCheckpoint && typeof table.databaseName !== "string") throw new Error("autoCheckpoint requires table.databaseName to be provided.");
521
+ if (checkpointChunksFrequency && typeof table.databaseName !== "string") throw new Error("checkpointChunksFrequency requires table.databaseName to be provided.");
522
+ if (checkpointChunksFrequency !== void 0 && checkpointChunksFrequency < 1) throw new Error("checkpointChunksFrequency must be a positive number.");
523
+ const dbManager = new DuckDatabaseManager(this.#conn);
519
524
  const timeStart = Date.now();
520
525
  const { columnTypes, ddl } = await createTableFromZod({
521
526
  conn: this.#conn,
@@ -531,6 +536,7 @@ var SqlDuck = class {
531
536
  rows: rowStream,
532
537
  chunkSize
533
538
  });
539
+ let appendedChunkCount = 0;
534
540
  try {
535
541
  for await (const dataChunk of columnStream) {
536
542
  const chunk = DuckDBDataChunk.create(chunkTypes);
@@ -539,21 +545,24 @@ var SqlDuck = class {
539
545
  chunk.setColumns(dataChunk);
540
546
  appender.appendDataChunk(chunk);
541
547
  appender.flushSync();
548
+ appendedChunkCount += 1;
542
549
  if (onDataAppended !== void 0) {
543
550
  const payload = dataAppendedCollector(totalRows);
544
551
  if (isOnDataAppendedAsyncCb(onDataAppended)) await onDataAppended(payload);
545
552
  else onDataAppended(payload);
546
553
  }
547
- }
548
- appender.closeSync();
549
- if (autoCheckpoint && typeof table.databaseName === "string") {
550
- const dbManager = new DuckDatabaseManager(this.#conn);
551
- try {
554
+ if (checkpointChunksFrequency !== void 0 && appendedChunkCount % checkpointChunksFrequency === 0 && typeof table.databaseName === "string") try {
552
555
  await dbManager.checkpoint(table.databaseName);
553
556
  } catch (e) {
554
- this.#logger.warning(`Failed to checkpoint database '${table.databaseName}' after appending data into table '${table.getFullName()}' - ${e?.message ?? ""}`, { table: table.getFullName() });
557
+ this.#logger.warning(`Failed to checkpoint database '${table.databaseName}' after appending chunk into table '${table.getFullName()}' - ${e?.message ?? ""}`, { table: table.getFullName() });
555
558
  }
556
559
  }
560
+ appender.closeSync();
561
+ if (autoCheckpoint && typeof table.databaseName === "string") try {
562
+ await dbManager.checkpoint(table.databaseName);
563
+ } catch (e) {
564
+ this.#logger.warning(`Failed to checkpoint database '${table.databaseName}' after appending data into table '${table.getFullName()}' - ${e?.message ?? ""}`, { table: table.getFullName() });
565
+ }
557
566
  const timeMs = Math.round(Date.now() - timeStart);
558
567
  this.#logger.info(`Successfully appended ${totalRows} rows into '${table.getFullName()}' in ${timeMs}ms`, {
559
568
  table: table.getFullName(),
@@ -10,6 +10,8 @@ declare const duckAllConnectionOptionsZodSchema: z.ZodObject<{
10
10
  type: z.ZodOptional<z.ZodEnum<{
11
11
  DUCKDB: "DUCKDB";
12
12
  SQLITE: "SQLITE";
13
+ MYSQL: "MYSQL";
14
+ PostgreSQL: "PostgreSQL";
13
15
  }>>;
14
16
  blockSize: z.ZodOptional<z.ZodInt32>;
15
17
  rowGroupSize: z.ZodOptional<z.ZodInt32>;
@@ -33,6 +35,8 @@ declare const duckConnectionParamsZodSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
33
35
  type: z.ZodOptional<z.ZodEnum<{
34
36
  DUCKDB: "DUCKDB";
35
37
  SQLITE: "SQLITE";
38
+ MYSQL: "MYSQL";
39
+ PostgreSQL: "PostgreSQL";
36
40
  }>>;
37
41
  blockSize: z.ZodOptional<z.ZodInt32>;
38
42
  rowGroupSize: z.ZodOptional<z.ZodInt32>;
@@ -45,7 +49,7 @@ declare const duckConnectionParamsZodSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
45
49
  }>>;
46
50
  }, z.core.$strict>>;
47
51
  }, z.core.$strict>, z.ZodObject<{
48
- type: z.ZodLiteral<"duckdb">;
52
+ type: z.ZodLiteral<"filesystem">;
49
53
  path: z.ZodString;
50
54
  alias: z.ZodString;
51
55
  options: z.ZodOptional<z.ZodObject<{
@@ -57,6 +61,8 @@ declare const duckConnectionParamsZodSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
57
61
  type: z.ZodOptional<z.ZodEnum<{
58
62
  DUCKDB: "DUCKDB";
59
63
  SQLITE: "SQLITE";
64
+ MYSQL: "MYSQL";
65
+ PostgreSQL: "PostgreSQL";
60
66
  }>>;
61
67
  blockSize: z.ZodOptional<z.ZodInt32>;
62
68
  rowGroupSize: z.ZodOptional<z.ZodInt32>;
@@ -0,0 +1,127 @@
1
+ import * as v from "valibot";
2
+
3
+ //#region src/validation/valibot/duck-connection-params-valibot-schema.d.ts
4
+ declare const duckAllConnectionOptionsValibotSchema: v.ObjectSchema<{
5
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
6
+ readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
7
+ readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
8
+ readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
9
+ readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
10
+ readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
11
+ readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
12
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
13
+ }, undefined>;
14
+ type DuckAllConnectionOptionsValibotSchema = v.InferOutput<typeof duckAllConnectionOptionsValibotSchema>;
15
+ declare const duckConnectionParamsValibotSchema: v.VariantSchema<"type", [v.ObjectSchema<{
16
+ readonly type: v.LiteralSchema<"memory", undefined>;
17
+ readonly alias: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
18
+ readonly options: v.OptionalSchema<v.ObjectSchema<{
19
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
20
+ readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
21
+ readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
22
+ readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
23
+ readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
24
+ readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
25
+ readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
26
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
27
+ }, undefined>, undefined>;
28
+ }, undefined>, v.ObjectSchema<{
29
+ readonly type: v.LiteralSchema<"filesystem", undefined>;
30
+ readonly path: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid database filename - it must be a safe filename (no path traversal, no absolute paths, no reserved names, etc.)">, v.CheckAction<string, "Invalid database pathname - it must be an absolute path with no traversal">]>;
31
+ readonly alias: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
32
+ readonly options: v.OptionalSchema<v.ObjectSchema<{
33
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
34
+ readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
35
+ readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
36
+ readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
37
+ readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
38
+ readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
39
+ readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
40
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
41
+ }, undefined>, undefined>;
42
+ }, undefined>], undefined>;
43
+ //#endregion
44
+ //#region src/validation/valibot/duck-dsn-valibot-schema.d.ts
45
+ declare const duckDsnValibotSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, (input: v.CheckIssue<string>) => string>, v.TransformAction<string, {
46
+ type: "memory";
47
+ alias: string;
48
+ options?: {
49
+ accessMode?: "READ_ONLY" | "READ_WRITE" | undefined;
50
+ compress?: boolean | undefined;
51
+ type?: "DUCKDB" | "SQLITE" | "MYSQL" | "PostgreSQL" | undefined;
52
+ blockSize?: number | undefined;
53
+ rowGroupSize?: number | undefined;
54
+ storageVersion?: string | undefined;
55
+ encryptionKey?: string | undefined;
56
+ encryptionCipher?: "CBC" | "CTR" | "GCM" | undefined;
57
+ } | undefined;
58
+ } | {
59
+ type: "filesystem";
60
+ path: string;
61
+ alias: string;
62
+ options?: {
63
+ accessMode?: "READ_ONLY" | "READ_WRITE" | undefined;
64
+ compress?: boolean | undefined;
65
+ type?: "DUCKDB" | "SQLITE" | "MYSQL" | "PostgreSQL" | undefined;
66
+ blockSize?: number | undefined;
67
+ rowGroupSize?: number | undefined;
68
+ storageVersion?: string | undefined;
69
+ encryptionKey?: string | undefined;
70
+ encryptionCipher?: "CBC" | "CTR" | "GCM" | undefined;
71
+ } | undefined;
72
+ }>, v.VariantSchema<"type", [v.ObjectSchema<{
73
+ readonly type: v.LiteralSchema<"memory", undefined>;
74
+ readonly alias: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
75
+ readonly options: v.OptionalSchema<v.ObjectSchema<{
76
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
77
+ readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
78
+ readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
79
+ readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
80
+ readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
81
+ readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
82
+ readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
83
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
84
+ }, undefined>, undefined>;
85
+ }, undefined>, v.ObjectSchema<{
86
+ readonly type: v.LiteralSchema<"filesystem", undefined>;
87
+ readonly path: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid database filename - it must be a safe filename (no path traversal, no absolute paths, no reserved names, etc.)">, v.CheckAction<string, "Invalid database pathname - it must be an absolute path with no traversal">]>;
88
+ readonly alias: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
89
+ readonly options: v.OptionalSchema<v.ObjectSchema<{
90
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
91
+ readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
92
+ readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
93
+ readonly blockSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 16384, undefined>, v.MaxValueAction<number, 262144, undefined>]>, undefined>;
94
+ readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
95
+ readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
96
+ readonly encryptionKey: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 8, undefined>]>, undefined>;
97
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<["CBC", "CTR", "GCM"], undefined>, undefined>;
98
+ }, undefined>, undefined>;
99
+ }, undefined>], undefined>]>;
100
+ //#endregion
101
+ //#region src/validation/valibot/duck-identifier-valibot-schema.d.ts
102
+ /**
103
+ * Check whether a table name identifier is valid
104
+ */
105
+ declare const duckIdentifierValibotSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
106
+ //#endregion
107
+ //#region src/validation/valibot/duck-validators-valibot.d.ts
108
+ /**
109
+ * Common validators for duckdb parameters, tables...
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * import { duckValidatorsValibot } from '@flowblade/sqlduck/valibot';
114
+ *
115
+ * ```
116
+ */
117
+ declare const duckValidatorsValibot: {
118
+ /**
119
+ * Validate duckdb objects names like table, alias, and schemas
120
+ * for validity.
121
+ */
122
+ readonly aliasName: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
123
+ readonly schemaName: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
124
+ readonly tableName: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>, v.RegexAction<string, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores">, v.CheckAction<string, "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier">]>;
125
+ };
126
+ //#endregion
127
+ export { type DuckAllConnectionOptionsValibotSchema, duckAllConnectionOptionsValibotSchema, duckConnectionParamsValibotSchema, duckDsnValibotSchema, duckIdentifierValibotSchema, duckValidatorsValibot };
@@ -0,0 +1,73 @@
1
+ import { a as duckStorageVersionRegexp, i as duckIdentifierNameRegex, n as duckdbReservedKeywordsSet, r as duckConnectionsOptions } from "../../duck-reserved-keywords-CUmaTbrD.mjs";
2
+ import isSafeFilename from "is-safe-filename";
3
+ import { parseDsn, parseDsnOrThrow } from "@httpx/dsn-parser";
4
+ import * as v from "valibot";
5
+ //#region src/validation/valibot/duck-identifier-valibot-schema.ts
6
+ /**
7
+ * Check whether a table name identifier is valid
8
+ */
9
+ const duckIdentifierValibotSchema = v.pipe(v.string(), v.minLength(1), v.maxLength(120), v.regex(duckIdentifierNameRegex, "Identifier must start with a letter or underscore, and contain only letters, numbers and underscores"), v.check((value) => !duckdbReservedKeywordsSet.has(value.toUpperCase()), "Identifier value is a DuckDB reserved keyword and cannot be used as an identifier"));
10
+ //#endregion
11
+ //#region src/validation/valibot/duck-validators-valibot.ts
12
+ /**
13
+ * Common validators for duckdb parameters, tables...
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { duckValidatorsValibot } from '@flowblade/sqlduck/valibot';
18
+ *
19
+ * ```
20
+ */
21
+ const duckValidatorsValibot = {
22
+ aliasName: duckIdentifierValibotSchema,
23
+ schemaName: duckIdentifierValibotSchema,
24
+ tableName: duckIdentifierValibotSchema
25
+ };
26
+ //#endregion
27
+ //#region src/validation/valibot/duck-connection-params-valibot-schema.ts
28
+ const duckAllConnectionOptionsValibotSchema = v.object({
29
+ accessMode: v.optional(v.picklist(["READ_ONLY", "READ_WRITE"])),
30
+ compress: v.optional(v.boolean()),
31
+ type: v.optional(v.picklist(duckConnectionsOptions.types)),
32
+ blockSize: v.optional(v.pipe(v.number(), v.integer(), v.minValue(16384), v.maxValue(262144))),
33
+ rowGroupSize: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1))),
34
+ storageVersion: v.optional(v.pipe(v.string(), v.startsWith("v"), v.regex(duckStorageVersionRegexp))),
35
+ encryptionKey: v.optional(v.pipe(v.string(), v.minLength(8))),
36
+ encryptionCipher: v.optional(v.picklist([
37
+ "CBC",
38
+ "CTR",
39
+ "GCM"
40
+ ]))
41
+ });
42
+ const duckConnectionParamsValibotSchema = v.variant("type", [v.object({
43
+ type: v.literal("memory"),
44
+ alias: duckValidatorsValibot.aliasName,
45
+ options: v.optional(duckAllConnectionOptionsValibotSchema)
46
+ }), v.object({
47
+ type: v.literal("filesystem"),
48
+ path: v.pipe(v.string(), v.check((path) => {
49
+ const filename = path.replace("\\", "/").split("/").at(-1);
50
+ return typeof filename === "string" && isSafeFilename(filename);
51
+ }, "Invalid database filename - it must be a safe filename (no path traversal, no absolute paths, no reserved names, etc.)"), v.check((path) => {
52
+ const pathname = "/" + path.replace("\\", "/").split("/").slice(0, -1).filter(Boolean).join("/");
53
+ return pathname.length > 0 && pathname.startsWith("/") && !pathname.includes("..");
54
+ }, "Invalid database pathname - it must be an absolute path with no traversal")),
55
+ alias: duckValidatorsValibot.aliasName,
56
+ options: v.optional(duckAllConnectionOptionsValibotSchema)
57
+ })]);
58
+ //#endregion
59
+ //#region src/validation/valibot/duck-dsn-valibot-schema.ts
60
+ const duckDsnValibotSchema = v.pipe(v.string(), v.check((dsn) => parseDsn(dsn).success, (input) => {
61
+ return parseDsn(input.input)?.message ?? "Invalid DSN";
62
+ }), v.transform((dsn) => {
63
+ const parsed = parseDsnOrThrow(dsn);
64
+ const { path, ...options } = parsed.params ?? {};
65
+ return {
66
+ type: parsed.host,
67
+ alias: parsed.db,
68
+ ...path ? { path } : {},
69
+ options: { ...options }
70
+ };
71
+ }), duckConnectionParamsValibotSchema);
72
+ //#endregion
73
+ export { duckAllConnectionOptionsValibotSchema, duckConnectionParamsValibotSchema, duckDsnValibotSchema, duckIdentifierValibotSchema, duckValidatorsValibot };
@@ -1,11 +1,92 @@
1
- import { a as duckAllConnectionOptionsZodSchema, i as DuckTableName, n as DuckConnectionParams, o as duckConnectionParamsZodSchema, r as DuckSchemaName, t as DuckAliasName } from "../../types-DCqYqEsa.mjs";
2
- import * as _$zod from "zod";
1
+ import { a as duckAllConnectionOptionsZodSchema, i as DuckTableName, o as duckConnectionParamsZodSchema, r as DuckSchemaName, t as DuckAliasName } from "../../types-dnhcognF.mjs";
2
+ import * as z from "zod";
3
3
 
4
4
  //#region src/validation/zod/duck-asserts-zod.d.ts
5
5
  declare function assertValidAliasName(aliasName: string): asserts aliasName is DuckAliasName;
6
6
  declare function assertValidSchemaName(schemaName: string): asserts schemaName is DuckSchemaName;
7
7
  declare function assertValidTableName(tableName: string): asserts tableName is DuckTableName;
8
8
  //#endregion
9
+ //#region src/validation/zod/duck-dsn-zod-schema.d.ts
10
+ declare const duckDsnZodSchema: z.ZodPipe<z.ZodString, z.ZodPipe<z.ZodTransform<{
11
+ type: "memory";
12
+ alias: string;
13
+ options?: {
14
+ accessMode?: "READ_ONLY" | "READ_WRITE" | undefined;
15
+ compress?: boolean | undefined;
16
+ type?: "DUCKDB" | "SQLITE" | "MYSQL" | "PostgreSQL" | undefined;
17
+ blockSize?: number | undefined;
18
+ rowGroupSize?: number | undefined;
19
+ storageVersion?: string | undefined;
20
+ encryptionKey?: string | undefined;
21
+ encryptionCipher?: "CBC" | "CTR" | "GCM" | undefined;
22
+ } | undefined;
23
+ } | {
24
+ type: "filesystem";
25
+ path: string;
26
+ alias: string;
27
+ options?: {
28
+ accessMode?: "READ_ONLY" | "READ_WRITE" | undefined;
29
+ compress?: boolean | undefined;
30
+ type?: "DUCKDB" | "SQLITE" | "MYSQL" | "PostgreSQL" | undefined;
31
+ blockSize?: number | undefined;
32
+ rowGroupSize?: number | undefined;
33
+ storageVersion?: string | undefined;
34
+ encryptionKey?: string | undefined;
35
+ encryptionCipher?: "CBC" | "CTR" | "GCM" | undefined;
36
+ } | undefined;
37
+ }, string>, z.ZodDiscriminatedUnion<[z.ZodObject<{
38
+ type: z.ZodLiteral<"memory">;
39
+ alias: z.ZodString;
40
+ options: z.ZodOptional<z.ZodObject<{
41
+ accessMode: z.ZodOptional<z.ZodEnum<{
42
+ READ_ONLY: "READ_ONLY";
43
+ READ_WRITE: "READ_WRITE";
44
+ }>>;
45
+ compress: z.ZodOptional<z.ZodBoolean>;
46
+ type: z.ZodOptional<z.ZodEnum<{
47
+ DUCKDB: "DUCKDB";
48
+ SQLITE: "SQLITE";
49
+ MYSQL: "MYSQL";
50
+ PostgreSQL: "PostgreSQL";
51
+ }>>;
52
+ blockSize: z.ZodOptional<z.ZodInt32>;
53
+ rowGroupSize: z.ZodOptional<z.ZodInt32>;
54
+ storageVersion: z.ZodOptional<z.ZodString>;
55
+ encryptionKey: z.ZodOptional<z.ZodString>;
56
+ encryptionCipher: z.ZodOptional<z.ZodEnum<{
57
+ CBC: "CBC";
58
+ CTR: "CTR";
59
+ GCM: "GCM";
60
+ }>>;
61
+ }, z.core.$strict>>;
62
+ }, z.core.$strict>, z.ZodObject<{
63
+ type: z.ZodLiteral<"filesystem">;
64
+ path: z.ZodString;
65
+ alias: z.ZodString;
66
+ options: z.ZodOptional<z.ZodObject<{
67
+ accessMode: z.ZodOptional<z.ZodEnum<{
68
+ READ_ONLY: "READ_ONLY";
69
+ READ_WRITE: "READ_WRITE";
70
+ }>>;
71
+ compress: z.ZodOptional<z.ZodBoolean>;
72
+ type: z.ZodOptional<z.ZodEnum<{
73
+ DUCKDB: "DUCKDB";
74
+ SQLITE: "SQLITE";
75
+ MYSQL: "MYSQL";
76
+ PostgreSQL: "PostgreSQL";
77
+ }>>;
78
+ blockSize: z.ZodOptional<z.ZodInt32>;
79
+ rowGroupSize: z.ZodOptional<z.ZodInt32>;
80
+ storageVersion: z.ZodOptional<z.ZodString>;
81
+ encryptionKey: z.ZodOptional<z.ZodString>;
82
+ encryptionCipher: z.ZodOptional<z.ZodEnum<{
83
+ CBC: "CBC";
84
+ CTR: "CTR";
85
+ GCM: "GCM";
86
+ }>>;
87
+ }, z.core.$strict>>;
88
+ }, z.core.$strict>], "type">>>;
89
+ //#endregion
9
90
  //#region src/validation/zod/duck-validators-zod.d.ts
10
91
  /**
11
92
  * Common validators for duckdb parameters, tables...
@@ -23,15 +104,9 @@ declare const duckValidatorsZod: {
23
104
  * Validate duckdb objects names like table, alias, and schemas
24
105
  * for validity.
25
106
  */
26
- readonly aliasName: _$zod.ZodString;
27
- readonly schemaName: _$zod.ZodString;
28
- readonly tableName: _$zod.ZodString;
107
+ readonly aliasName: z.ZodString;
108
+ readonly schemaName: z.ZodString;
109
+ readonly tableName: z.ZodString;
29
110
  };
30
111
  //#endregion
31
- //#region src/validation/zod/is-parsable-duck-dsn-zod.d.ts
32
- declare const isParsableDuckDsnZod: (dsn: unknown) => boolean;
33
- //#endregion
34
- //#region src/validation/zod/parse-duck-dsn-zod.d.ts
35
- declare const parseDuckDSNZod: (dsn: string) => DuckConnectionParams;
36
- //#endregion
37
- export { assertValidAliasName, assertValidSchemaName, assertValidTableName, duckAllConnectionOptionsZodSchema, duckConnectionParamsZodSchema, duckValidatorsZod, isParsableDuckDsnZod, parseDuckDSNZod };
112
+ export { assertValidAliasName, assertValidSchemaName, assertValidTableName, duckAllConnectionOptionsZodSchema, duckConnectionParamsZodSchema, duckDsnZodSchema, duckValidatorsZod };
@@ -1,2 +1,2 @@
1
- import { a as assertValidAliasName, c as duckValidatorsZod, i as duckConnectionParamsZodSchema, n as parseDuckDSNZod, o as assertValidSchemaName, r as duckAllConnectionOptionsZodSchema, s as assertValidTableName, t as isParsableDuckDsnZod } from "../../zod-CwR_oehs.mjs";
2
- export { assertValidAliasName, assertValidSchemaName, assertValidTableName, duckAllConnectionOptionsZodSchema, duckConnectionParamsZodSchema, duckValidatorsZod, isParsableDuckDsnZod, parseDuckDSNZod };
1
+ import { a as duckAllConnectionOptionsZodSchema, i as assertValidTableName, n as assertValidAliasName, o as duckConnectionParamsZodSchema, r as assertValidSchemaName, s as duckValidatorsZod, t as duckDsnZodSchema } from "../../zod-BRUUIdGW.mjs";
2
+ export { assertValidAliasName, assertValidSchemaName, assertValidTableName, duckAllConnectionOptionsZodSchema, duckConnectionParamsZodSchema, duckDsnZodSchema, duckValidatorsZod };
@@ -1,121 +1,8 @@
1
+ import { a as duckStorageVersionRegexp, i as duckIdentifierNameRegex, n as duckdbReservedKeywordsSet, r as duckConnectionsOptions } from "./duck-reserved-keywords-CUmaTbrD.mjs";
2
+ import isSafeFilename from "is-safe-filename";
1
3
  import * as z from "zod";
2
4
  import { parseDsn } from "@httpx/dsn-parser";
3
- //#region src/validation/core/create-assert-error.ts
4
- const createAssertError = (msgOrErrorFactory, fallbackMsg) => {
5
- if (typeof msgOrErrorFactory === "string" || msgOrErrorFactory === void 0) return new TypeError(msgOrErrorFactory ?? fallbackMsg ?? "Assertion did not pass.");
6
- return msgOrErrorFactory();
7
- };
8
- //#endregion
9
- //#region src/validation/core/base-validators.ts
10
- const duckIdentifierNameRegex = /^[a-z_]\w*$/i;
11
- const duckStorageVersionRegexp = /^v?\d{1,4}\.\d{1,4}\.\d{1,4}$/;
12
- //#endregion
13
- //#region src/validation/core/duck-reserved-keywords.ts
14
- /**
15
- * DuckDB reserved keywords that cannot be used as unquoted identifiers.
16
- * @see https://duckdb.org/docs/sql/keywords-and-identifiers.html
17
- */
18
- const duckReservedKeywords = [
19
- "ALL",
20
- "ANALYSE",
21
- "ANALYZE",
22
- "AND",
23
- "ANY",
24
- "ARRAY",
25
- "AS",
26
- "ASC",
27
- "ASYMMETRIC",
28
- "BOTH",
29
- "CASE",
30
- "CAST",
31
- "CHECK",
32
- "COLLATE",
33
- "COLUMN",
34
- "CONSTRAINT",
35
- "CREATE",
36
- "CROSS",
37
- "CURRENT_CATALOG",
38
- "CURRENT_DATE",
39
- "CURRENT_ROLE",
40
- "CURRENT_SCHEMA",
41
- "CURRENT_TIME",
42
- "CURRENT_TIMESTAMP",
43
- "CURRENT_USER",
44
- "DEFAULT",
45
- "DEFERRABLE",
46
- "DESC",
47
- "DISTINCT",
48
- "DO",
49
- "ELSE",
50
- "END",
51
- "EXCEPT",
52
- "EXISTS",
53
- "EXTRACT",
54
- "FALSE",
55
- "FETCH",
56
- "FOR",
57
- "FOREIGN",
58
- "FROM",
59
- "GRANT",
60
- "GROUP",
61
- "HAVING",
62
- "IF",
63
- "ILIKE",
64
- "IN",
65
- "INITIALLY",
66
- "INNER",
67
- "INTERSECT",
68
- "INTO",
69
- "IS",
70
- "ISNULL",
71
- "JOIN",
72
- "LATERAL",
73
- "LEADING",
74
- "LEFT",
75
- "LIKE",
76
- "LIMIT",
77
- "LOCALTIME",
78
- "LOCALTIMESTAMP",
79
- "NATURAL",
80
- "NOT",
81
- "NOTNULL",
82
- "NULL",
83
- "OFFSET",
84
- "ON",
85
- "ONLY",
86
- "OR",
87
- "ORDER",
88
- "OUTER",
89
- "OVERLAPS",
90
- "PLACING",
91
- "PRIMARY",
92
- "REFERENCES",
93
- "RETURNING",
94
- "RIGHT",
95
- "ROW",
96
- "SELECT",
97
- "SESSION_USER",
98
- "SIMILAR",
99
- "SOME",
100
- "SYMMETRIC",
101
- "TABLE",
102
- "THEN",
103
- "TO",
104
- "TRAILING",
105
- "TRUE",
106
- "UNION",
107
- "UNIQUE",
108
- "USING",
109
- "VARIADIC",
110
- "VERBOSE",
111
- "WHEN",
112
- "WHERE",
113
- "WINDOW",
114
- "WITH"
115
- ];
116
- //#endregion
117
5
  //#region src/validation/zod/duck-identifier-zod-schema.ts
118
- const duckdbReservedKeywordsSet = new Set(duckReservedKeywords.map((k) => k.toUpperCase()));
119
6
  /**
120
7
  * Check whether a table name identifier is valid
121
8
  */
@@ -139,25 +26,11 @@ const duckValidatorsZod = {
139
26
  tableName: duckIdentifierZodSchema
140
27
  };
141
28
  //#endregion
142
- //#region src/validation/zod/duck-asserts-zod.ts
143
- function assertValidAliasName(aliasName) {
144
- const parsed = z.safeParse(duckValidatorsZod.aliasName, aliasName);
145
- if (parsed.error) throw createAssertError(`'${aliasName}' is not a valid alias name: ${parsed.error.message}`);
146
- }
147
- function assertValidSchemaName(schemaName) {
148
- const parsed = z.safeParse(duckValidatorsZod.schemaName, schemaName);
149
- if (parsed.error) throw createAssertError(`'${schemaName}' is not a valid schema name: ${parsed.error.message}`);
150
- }
151
- function assertValidTableName(tableName) {
152
- const parsed = z.safeParse(duckValidatorsZod.tableName, tableName);
153
- if (parsed.error) throw createAssertError(`'${tableName}' is not a valid table name: ${parsed.error.message}`);
154
- }
155
- //#endregion
156
29
  //#region src/validation/zod/duck-connection-params-zod-schema.ts
157
30
  const duckAllConnectionOptionsZodSchema = z.strictObject({
158
31
  accessMode: z.optional(z.enum(["READ_ONLY", "READ_WRITE"])),
159
32
  compress: z.optional(z.boolean()),
160
- type: z.optional(z.enum(["DUCKDB", "SQLITE"])),
33
+ type: z.optional(z.enum(duckConnectionsOptions.types)),
161
34
  blockSize: z.optional(z.int32().min(16384).max(262144)),
162
35
  rowGroupSize: z.optional(z.int32().positive()),
163
36
  storageVersion: z.optional(z.string().startsWith("v").regex(duckStorageVersionRegexp)),
@@ -173,35 +46,58 @@ const duckConnectionParamsZodSchema = z.discriminatedUnion("type", [z.strictObje
173
46
  alias: duckValidatorsZod.aliasName,
174
47
  options: z.optional(duckAllConnectionOptionsZodSchema)
175
48
  }), z.strictObject({
176
- type: z.literal("duckdb"),
177
- path: z.string().min(4).endsWith(".db"),
49
+ type: z.literal("filesystem"),
50
+ path: z.string().refine((path) => {
51
+ const filename = path.replace("\\", "/").split("/").at(-1);
52
+ return typeof filename === "string" && isSafeFilename(filename);
53
+ }, { message: "Invalid database filename - it must be a safe filename (no path traversal, no absolute paths, no reserved names, etc.)" }).refine((path) => {
54
+ const pathname = "/" + path.replace("\\", "/").split("/").slice(0, -1).filter(Boolean).join("/");
55
+ return pathname.length > 0 && pathname.startsWith("/") && pathname.includes("..") === false;
56
+ }, { message: "Invalid database pathname - it must be an absolute path with no traversal" }),
178
57
  alias: duckValidatorsZod.aliasName,
179
58
  options: z.optional(duckAllConnectionOptionsZodSchema)
180
59
  })]);
181
60
  //#endregion
182
- //#region src/validation/zod/parse-duck-dsn-zod.ts
183
- const parseDuckDSNZod = (dsn) => {
184
- const result = parseDsn(dsn);
185
- if (!result.success) throw new Error(`Invalid DuckDB DSN - ${result.message}`);
186
- const parsed = result.value;
187
- const { path, ...options } = parsed.params ?? {};
188
- return duckConnectionParamsZodSchema.parse({
189
- type: parsed.host,
190
- alias: parsed.db,
191
- ...path ? { path } : {},
192
- options: { ...options }
193
- });
61
+ //#region src/validation/core/create-assert-error.ts
62
+ const createAssertError = (msgOrErrorFactory, fallbackMsg) => {
63
+ if (typeof msgOrErrorFactory === "string" || msgOrErrorFactory === void 0) return new TypeError(msgOrErrorFactory ?? fallbackMsg ?? "Assertion did not pass.");
64
+ return msgOrErrorFactory();
194
65
  };
195
66
  //#endregion
196
- //#region src/validation/zod/is-parsable-duck-dsn-zod.ts
197
- const isParsableDuckDsnZod = (dsn) => {
198
- if (typeof dsn !== "string") return false;
199
- try {
200
- parseDuckDSNZod(dsn);
201
- return true;
202
- } catch {
203
- return false;
67
+ //#region src/validation/zod/duck-asserts-zod.ts
68
+ function assertValidAliasName(aliasName) {
69
+ const parsed = z.safeParse(duckValidatorsZod.aliasName, aliasName);
70
+ if (parsed.error) throw createAssertError(`'${aliasName}' is not a valid alias name: ${parsed.error.message}`);
71
+ }
72
+ function assertValidSchemaName(schemaName) {
73
+ const parsed = z.safeParse(duckValidatorsZod.schemaName, schemaName);
74
+ if (parsed.error) throw createAssertError(`'${schemaName}' is not a valid schema name: ${parsed.error.message}`);
75
+ }
76
+ function assertValidTableName(tableName) {
77
+ const parsed = z.safeParse(duckValidatorsZod.tableName, tableName);
78
+ if (parsed.error) throw createAssertError(`'${tableName}' is not a valid table name: ${parsed.error.message}`);
79
+ }
80
+ //#endregion
81
+ //#region src/validation/zod/duck-dsn-zod-schema.ts
82
+ const duckDsnZodSchema = z.string().pipe(z.preprocess((dsn, ctx) => {
83
+ const result = parseDsn(dsn);
84
+ if (result.success) {
85
+ const parsed = result.value;
86
+ const { path, ...options } = parsed.params ?? {};
87
+ return {
88
+ type: parsed.host,
89
+ alias: parsed.db,
90
+ ...path ? { path } : {},
91
+ options: { ...options }
92
+ };
93
+ } else {
94
+ ctx.issues.push({
95
+ code: "custom",
96
+ message: result.message,
97
+ input: dsn
98
+ });
99
+ return z.NEVER;
204
100
  }
205
- };
101
+ }, duckConnectionParamsZodSchema));
206
102
  //#endregion
207
- export { assertValidAliasName as a, duckValidatorsZod as c, duckConnectionParamsZodSchema as i, duckReservedKeywords as l, parseDuckDSNZod as n, assertValidSchemaName as o, duckAllConnectionOptionsZodSchema as r, assertValidTableName as s, isParsableDuckDsnZod as t };
103
+ export { duckAllConnectionOptionsZodSchema as a, assertValidTableName as i, assertValidAliasName as n, duckConnectionParamsZodSchema as o, assertValidSchemaName as r, duckValidatorsZod as s, duckDsnZodSchema as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowblade/sqlduck",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "exports": {
@@ -12,6 +12,10 @@
12
12
  "types": "./dist/validation/zod/index.d.mts",
13
13
  "default": "./dist/validation/zod/index.mjs"
14
14
  },
15
+ "./valibot": {
16
+ "types": "./dist/validation/valibot/index.d.mts",
17
+ "default": "./dist/validation/valibot/index.mjs"
18
+ },
15
19
  "./package.json": "./package.json"
16
20
  },
17
21
  "author": {
@@ -55,42 +59,49 @@
55
59
  "@flowblade/core": "^0.2.26",
56
60
  "@flowblade/source-duckdb": "^0.20.1",
57
61
  "@flowblade/sql-tag": "^0.3.2",
58
- "@httpx/assert": "^0.16.8",
62
+ "@httpx/assert": "^0.16.9",
59
63
  "@httpx/dsn-parser": "^1.9.9",
60
64
  "@httpx/plain-object": "^2.1.8",
61
65
  "@logtape/logtape": "^2.0.5",
62
66
  "@standard-schema/spec": "^1.1.0",
63
- "p-queue": "9.1.0",
67
+ "is-safe-filename": "0.1.1",
68
+ "p-queue": "9.1.1",
64
69
  "zod": "^4.3.6"
65
70
  },
66
71
  "peerDependencies": {
67
- "@duckdb/node-api": "^1.5.0-r.1"
72
+ "@duckdb/node-api": "^1.5.0-r.1",
73
+ "valibot": "^1.3.1"
74
+ },
75
+ "peerDependenciesMeta": {
76
+ "valibot": {
77
+ "optional": true
78
+ }
68
79
  },
69
80
  "devDependencies": {
70
- "@belgattitude/eslint-config-bases": "8.10.0",
81
+ "@belgattitude/eslint-config-bases": "8.12.0",
71
82
  "@dotenvx/dotenvx": "1.59.1",
72
83
  "@duckdb/node-api": "1.5.1-r.1",
73
84
  "@faker-js/faker": "10.4.0",
74
85
  "@flowblade/source-kysely": "^1.3.0",
75
- "@httpx/assert": "0.16.8",
86
+ "@httpx/assert": "0.16.9",
76
87
  "@mitata/counters": "0.0.8",
77
88
  "@size-limit/esbuild": "12.0.1",
78
89
  "@size-limit/file": "12.0.1",
79
90
  "@testcontainers/mssqlserver": "11.13.0",
80
91
  "@total-typescript/ts-reset": "0.6.1",
81
- "@types/node": "25.5.0",
92
+ "@types/node": "25.5.2",
82
93
  "@typescript-eslint/eslint-plugin": "8.58.0",
83
94
  "@typescript-eslint/parser": "8.58.0",
84
- "@typescript/native-preview": "7.0.0-dev.20260324.1",
95
+ "@typescript/native-preview": "7.0.0-dev.20260406.1",
85
96
  "@vitest/coverage-v8": "4.1.2",
86
97
  "@vitest/ui": "4.1.2",
87
98
  "ansis": "4.2.0",
88
99
  "browserslist-to-esbuild": "2.1.1",
89
100
  "core-js": "3.49.0",
90
101
  "cross-env": "10.1.0",
91
- "es-check": "9.6.3",
102
+ "es-check": "9.6.4",
92
103
  "es-toolkit": "1.45.1",
93
- "esbuild": "0.27.4",
104
+ "esbuild": "0.28.0",
94
105
  "eslint": "8.57.1",
95
106
  "execa": "9.6.1",
96
107
  "is-in-ci": "2.0.0",
@@ -111,6 +122,7 @@
111
122
  "typedoc": "0.28.18",
112
123
  "typedoc-plugin-markdown": "4.11.0",
113
124
  "typescript": "6.0.2",
125
+ "valibot": "1.3.1",
114
126
  "vitest": "4.1.2"
115
127
  },
116
128
  "files": [