@flowblade/sqlduck 0.14.0 → 0.15.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.
@@ -3,12 +3,20 @@ const duckIdentifierNameRegex = /^[a-z_]\w*$/i;
3
3
  const duckStorageVersionRegexp = /^v?\d{1,4}\.\d{1,4}\.\d{1,4}$/;
4
4
  //#endregion
5
5
  //#region src/validation/core/duck-connections-options.ts
6
- const duckConnectionsOptions = { types: [
7
- "DUCKDB",
8
- "SQLITE",
9
- "MYSQL",
10
- "PostgreSQL"
11
- ] };
6
+ const duckConnectionsOptions = {
7
+ types: [
8
+ "DUCKDB",
9
+ "SQLITE",
10
+ "MYSQL",
11
+ "PostgreSQL"
12
+ ],
13
+ accessModes: ["READ_ONLY", "READ_WRITE"],
14
+ encryptionCiphers: [
15
+ "CBC",
16
+ "CTR",
17
+ "GCM"
18
+ ]
19
+ };
12
20
  //#endregion
13
21
  //#region src/validation/core/duck-reserved-keywords.ts
14
22
  /**
package/dist/index.d.mts CHANGED
@@ -283,6 +283,15 @@ declare class DuckDatabaseManager {
283
283
  analyze: () => Promise<boolean>;
284
284
  checkpoint: (dbAlias: string) => Promise<boolean>;
285
285
  vacuum: () => Promise<boolean>;
286
+ /**
287
+ * Helper to create an initial database file.
288
+ */
289
+ createDatabaseFile: (params: {
290
+ path: string;
291
+ createDirectory?: boolean;
292
+ }) => Promise<{
293
+ status: "exists" | "created";
294
+ }>;
286
295
  }
287
296
  //#endregion
288
297
  //#region src/config/flowblade-logtape-sqlduck.config.d.ts
package/dist/index.mjs CHANGED
@@ -1,7 +1,9 @@
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";
3
- import { BIGINT, BOOLEAN, DOUBLE, DuckDBDataChunk, DuckDBTimestampValue, FLOAT, HUGEINT, INTEGER, SMALLINT, TIMESTAMP, TINYINT, UBIGINT, UHUGEINT, UINTEGER, USMALLINT, UTINYINT, UUID, VARCHAR } from "@duckdb/node-api";
1
+ import { t as duckReservedKeywords } from "./duck-reserved-keywords-B8XUjnaY.mjs";
2
+ import { n as assertValidAliasName, o as duckConnectionParamsZodSchema, s as duckValidatorsZod } from "./zod-CuPjTLv8.mjs";
3
+ import { BIGINT, BOOLEAN, DOUBLE, DuckDBDataChunk, DuckDBInstanceCache, DuckDBTimestampValue, FLOAT, HUGEINT, INTEGER, SMALLINT, TIMESTAMP, TINYINT, UBIGINT, UHUGEINT, UINTEGER, USMALLINT, UTINYINT, UUID, VARCHAR } from "@duckdb/node-api";
4
4
  import { getLogger } from "@logtape/logtape";
5
+ import fs from "node:fs";
6
+ import { basename, dirname } from "node:path";
5
7
  import * as z from "zod";
6
8
  import { assertNever } from "@httpx/assert";
7
9
  import { isPlainObject } from "@httpx/plain-object";
@@ -128,6 +130,81 @@ const flowbladeLogtapeSqlduckConfig = { categories: ["flowblade", "sqlduck"] };
128
130
  //#region src/logger/sqlduck-default-logtape-logger.ts
129
131
  const sqlduckDefaultLogtapeLogger = getLogger(flowbladeLogtapeSqlduckConfig.categories);
130
132
  //#endregion
133
+ //#region src/filesystem/file-system-utils.ts
134
+ var FileSystemUtils = class {
135
+ #logger;
136
+ constructor(params) {
137
+ this.#logger = params?.logger ?? sqlduckDefaultLogtapeLogger.with({ source: "FileSystemUtils" });
138
+ }
139
+ /**
140
+ * Create a directory recursively if it doesn't exist
141
+ *
142
+ * @throws Error if it can't be created
143
+ */
144
+ createDirectory = (path) => {
145
+ try {
146
+ fs.mkdirSync(path, { recursive: true });
147
+ } catch (err) {
148
+ if (err.code !== "EEXIST") throw err;
149
+ }
150
+ };
151
+ /**
152
+ * Create a directory recursively if it doesn't exist and ensure it's writable
153
+ */
154
+ createAndEnsureWritableDirectory = (label, path) => {
155
+ if (path === void 0) return;
156
+ if (!fs.existsSync(path)) try {
157
+ this.createDirectory(path);
158
+ } catch (e) {
159
+ throw new Error(`Failed to create ${label} '${path}' - ${e?.message ?? ""}`);
160
+ }
161
+ if (!fs.statSync(path).isDirectory()) throw new Error(`${label} '${path}' must be a directory`);
162
+ try {
163
+ fs.accessSync(path, fs.constants.W_OK);
164
+ } catch {
165
+ throw new Error(`${label} '${path}' must be writable`);
166
+ }
167
+ };
168
+ /**
169
+ * Check if a path is a regular file and exists
170
+ */
171
+ isFile = (path) => {
172
+ try {
173
+ return fs.statSync(path).isFile();
174
+ } catch {
175
+ return false;
176
+ }
177
+ };
178
+ /**
179
+ * Check if a path is a directory and exists
180
+ */
181
+ isDirectory = (path) => {
182
+ try {
183
+ return fs.statSync(path).isDirectory();
184
+ } catch {
185
+ return false;
186
+ }
187
+ };
188
+ parsePath = (path) => {
189
+ const dir = dirname(path);
190
+ if (dir.trim() === "") throw new Error(`Invalid path, missing directory '${path}'`);
191
+ const base = basename(path);
192
+ if (base.trim() === "") throw new Error(`Invalid path, missing filename '${path}'`);
193
+ return {
194
+ directory: dir,
195
+ filename: base
196
+ };
197
+ };
198
+ removeFileIfExists = (path) => {
199
+ try {
200
+ fs.rmSync(path);
201
+ return true;
202
+ } catch {
203
+ return false;
204
+ }
205
+ };
206
+ };
207
+ //#endregion
131
208
  //#region src/objects/database.ts
132
209
  var Database = class {
133
210
  #params;
@@ -207,6 +284,7 @@ var DuckDatabaseAttachCommand = class {
207
284
  var DuckDatabaseManager = class {
208
285
  #conn;
209
286
  #logger;
287
+ #fs;
210
288
  constructor(conn, params) {
211
289
  this.#conn = conn;
212
290
  this.#logger = params?.logger ?? sqlduckDefaultLogtapeLogger.with({ source: "DuckDatabaseManager" });
@@ -229,7 +307,12 @@ var DuckDatabaseManager = class {
229
307
  attach = async (dbParams, options) => {
230
308
  const params = duckConnectionParamsZodSchema.parse(dbParams);
231
309
  const rawSql = new DuckDatabaseAttachCommand(params, options).getRawSql();
232
- await this.#executeRawSqlCommand(`attach(${params.alias})`, rawSql);
310
+ const { behaviour } = options ?? {};
311
+ await this.#executeRawSqlCommand([
312
+ `attach(${params.alias}`,
313
+ behaviour ?? null,
314
+ ")"
315
+ ].filter(Boolean).join(","), rawSql);
233
316
  return new Database({ alias: params.alias });
234
317
  };
235
318
  attachOrReplace = async (dbParams) => {
@@ -272,6 +355,32 @@ var DuckDatabaseManager = class {
272
355
  await this.#executeRawSqlCommand("vacuum()", "VACUUM");
273
356
  return true;
274
357
  };
358
+ /**
359
+ * Helper to create an initial database file.
360
+ */
361
+ createDatabaseFile = async (params) => {
362
+ const startTime = Date.now();
363
+ const { path, createDirectory = true } = params;
364
+ const fs = this.#getFs();
365
+ if (fs.isFile(path)) return { status: "exists" };
366
+ if (createDirectory) {
367
+ const { directory } = fs.parsePath(path);
368
+ fs.createAndEnsureWritableDirectory("database file directory", directory);
369
+ }
370
+ const instanceCache = new DuckDBInstanceCache();
371
+ try {
372
+ (await (await instanceCache.getOrCreateInstance(path)).connect()).closeSync();
373
+ const timeMs = Math.round(Date.now() - startTime);
374
+ this.#logger.info(`DuckDatabaseManager.createDatabaseFile('${path}') in ${timeMs}ms`, {
375
+ timeMs,
376
+ path
377
+ });
378
+ } catch (e) {
379
+ this.#logger.error(`DuckDatabaseManager.createDatabaseFile('${path}') failed - ${e?.message ?? ""}`, { path });
380
+ throw e;
381
+ }
382
+ return { status: "created" };
383
+ };
275
384
  #executeRawSqlCommand = async (name, rawSql) => {
276
385
  const startTime = Date.now();
277
386
  try {
@@ -291,6 +400,10 @@ var DuckDatabaseManager = class {
291
400
  throw new Error(msg, { cause: e });
292
401
  }
293
402
  };
403
+ #getFs = () => {
404
+ if (this.#fs === void 0) this.#fs = new FileSystemUtils({ logger: this.#logger });
405
+ return this.#fs;
406
+ };
294
407
  };
295
408
  //#endregion
296
409
  //#region src/table/get-duckdb-number-column-type.ts
@@ -2,42 +2,42 @@ import * as v from "valibot";
2
2
 
3
3
  //#region src/validation/valibot/duck-connection-params-valibot-schema.d.ts
4
4
  declare const duckAllConnectionOptionsValibotSchema: v.ObjectSchema<{
5
- readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
5
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<readonly ["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
6
6
  readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
7
7
  readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
8
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
9
  readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
10
10
  readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
11
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>;
12
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<readonly ["CBC", "CTR", "GCM"], undefined>, undefined>;
13
13
  }, undefined>;
14
14
  type DuckAllConnectionOptionsValibotSchema = v.InferOutput<typeof duckAllConnectionOptionsValibotSchema>;
15
15
  declare const duckConnectionParamsValibotSchema: v.VariantSchema<"type", [v.ObjectSchema<{
16
16
  readonly type: v.LiteralSchema<"memory", undefined>;
17
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
18
  readonly options: v.OptionalSchema<v.ObjectSchema<{
19
- readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
19
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<readonly ["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
20
20
  readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
21
21
  readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
22
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
23
  readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
24
24
  readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
25
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>;
26
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<readonly ["CBC", "CTR", "GCM"], undefined>, undefined>;
27
27
  }, undefined>, undefined>;
28
28
  }, undefined>, v.ObjectSchema<{
29
29
  readonly type: v.LiteralSchema<"filesystem", undefined>;
30
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
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
32
  readonly options: v.OptionalSchema<v.ObjectSchema<{
33
- readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
33
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<readonly ["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
34
34
  readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
35
35
  readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
36
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
37
  readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
38
38
  readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
39
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>;
40
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<readonly ["CBC", "CTR", "GCM"], undefined>, undefined>;
41
41
  }, undefined>, undefined>;
42
42
  }, undefined>], undefined>;
43
43
  //#endregion
@@ -73,28 +73,28 @@ declare const duckDsnValibotSchema: v.SchemaWithPipe<readonly [v.StringSchema<un
73
73
  readonly type: v.LiteralSchema<"memory", undefined>;
74
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
75
  readonly options: v.OptionalSchema<v.ObjectSchema<{
76
- readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
76
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<readonly ["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
77
77
  readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
78
78
  readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
79
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
80
  readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
81
81
  readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
82
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>;
83
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<readonly ["CBC", "CTR", "GCM"], undefined>, undefined>;
84
84
  }, undefined>, undefined>;
85
85
  }, undefined>, v.ObjectSchema<{
86
86
  readonly type: v.LiteralSchema<"filesystem", undefined>;
87
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
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
89
  readonly options: v.OptionalSchema<v.ObjectSchema<{
90
- readonly accessMode: v.OptionalSchema<v.PicklistSchema<["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
90
+ readonly accessMode: v.OptionalSchema<v.PicklistSchema<readonly ["READ_ONLY", "READ_WRITE"], undefined>, undefined>;
91
91
  readonly compress: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
92
92
  readonly type: v.OptionalSchema<v.PicklistSchema<readonly ["DUCKDB", "SQLITE", "MYSQL", "PostgreSQL"], undefined>, undefined>;
93
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
94
  readonly rowGroupSize: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, undefined>;
95
95
  readonly storageVersion: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.StartsWithAction<string, "v", undefined>, v.RegexAction<string, undefined>]>, undefined>;
96
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>;
97
+ readonly encryptionCipher: v.OptionalSchema<v.PicklistSchema<readonly ["CBC", "CTR", "GCM"], undefined>, undefined>;
98
98
  }, undefined>, undefined>;
99
99
  }, undefined>], undefined>]>;
100
100
  //#endregion
@@ -1,4 +1,4 @@
1
- import { a as duckStorageVersionRegexp, i as duckIdentifierNameRegex, n as duckdbReservedKeywordsSet, r as duckConnectionsOptions } from "../../duck-reserved-keywords-CUmaTbrD.mjs";
1
+ import { a as duckStorageVersionRegexp, i as duckIdentifierNameRegex, n as duckdbReservedKeywordsSet, r as duckConnectionsOptions } from "../../duck-reserved-keywords-B8XUjnaY.mjs";
2
2
  import isSafeFilename from "is-safe-filename";
3
3
  import { parseDsn, parseDsnOrThrow } from "@httpx/dsn-parser";
4
4
  import * as v from "valibot";
@@ -26,18 +26,14 @@ const duckValidatorsValibot = {
26
26
  //#endregion
27
27
  //#region src/validation/valibot/duck-connection-params-valibot-schema.ts
28
28
  const duckAllConnectionOptionsValibotSchema = v.object({
29
- accessMode: v.optional(v.picklist(["READ_ONLY", "READ_WRITE"])),
29
+ accessMode: v.optional(v.picklist(duckConnectionsOptions.accessModes)),
30
30
  compress: v.optional(v.boolean()),
31
31
  type: v.optional(v.picklist(duckConnectionsOptions.types)),
32
32
  blockSize: v.optional(v.pipe(v.number(), v.integer(), v.minValue(16384), v.maxValue(262144))),
33
33
  rowGroupSize: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1))),
34
34
  storageVersion: v.optional(v.pipe(v.string(), v.startsWith("v"), v.regex(duckStorageVersionRegexp))),
35
35
  encryptionKey: v.optional(v.pipe(v.string(), v.minLength(8))),
36
- encryptionCipher: v.optional(v.picklist([
37
- "CBC",
38
- "CTR",
39
- "GCM"
40
- ]))
36
+ encryptionCipher: v.optional(v.picklist(duckConnectionsOptions.encryptionCiphers))
41
37
  });
42
38
  const duckConnectionParamsValibotSchema = v.variant("type", [v.object({
43
39
  type: v.literal("memory"),
@@ -1,2 +1,2 @@
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";
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-CuPjTLv8.mjs";
2
2
  export { assertValidAliasName, assertValidSchemaName, assertValidTableName, duckAllConnectionOptionsZodSchema, duckConnectionParamsZodSchema, duckDsnZodSchema, duckValidatorsZod };
@@ -1,4 +1,4 @@
1
- import { a as duckStorageVersionRegexp, i as duckIdentifierNameRegex, n as duckdbReservedKeywordsSet, r as duckConnectionsOptions } from "./duck-reserved-keywords-CUmaTbrD.mjs";
1
+ import { a as duckStorageVersionRegexp, i as duckIdentifierNameRegex, n as duckdbReservedKeywordsSet, r as duckConnectionsOptions } from "./duck-reserved-keywords-B8XUjnaY.mjs";
2
2
  import isSafeFilename from "is-safe-filename";
3
3
  import * as z from "zod";
4
4
  import { parseDsn } from "@httpx/dsn-parser";
@@ -28,18 +28,14 @@ const duckValidatorsZod = {
28
28
  //#endregion
29
29
  //#region src/validation/zod/duck-connection-params-zod-schema.ts
30
30
  const duckAllConnectionOptionsZodSchema = z.strictObject({
31
- accessMode: z.optional(z.enum(["READ_ONLY", "READ_WRITE"])),
31
+ accessMode: z.optional(z.enum(duckConnectionsOptions.accessModes)),
32
32
  compress: z.optional(z.boolean()),
33
33
  type: z.optional(z.enum(duckConnectionsOptions.types)),
34
34
  blockSize: z.optional(z.int32().min(16384).max(262144)),
35
35
  rowGroupSize: z.optional(z.int32().positive()),
36
36
  storageVersion: z.optional(z.string().startsWith("v").regex(duckStorageVersionRegexp)),
37
37
  encryptionKey: z.optional(z.string().min(8)),
38
- encryptionCipher: z.optional(z.enum([
39
- "CBC",
40
- "CTR",
41
- "GCM"
42
- ]))
38
+ encryptionCipher: z.optional(z.enum(duckConnectionsOptions.encryptionCiphers))
43
39
  });
44
40
  const duckConnectionParamsZodSchema = z.discriminatedUnion("type", [z.strictObject({
45
41
  type: z.literal("memory"),
@@ -52,7 +48,7 @@ const duckConnectionParamsZodSchema = z.discriminatedUnion("type", [z.strictObje
52
48
  return typeof filename === "string" && isSafeFilename(filename);
53
49
  }, { message: "Invalid database filename - it must be a safe filename (no path traversal, no absolute paths, no reserved names, etc.)" }).refine((path) => {
54
50
  const pathname = "/" + path.replace("\\", "/").split("/").slice(0, -1).filter(Boolean).join("/");
55
- return pathname.length > 0 && pathname.startsWith("/") && pathname.includes("..") === false;
51
+ return pathname.length > 0 && pathname.startsWith("/") && !pathname.includes("..");
56
52
  }, { message: "Invalid database pathname - it must be an absolute path with no traversal" }),
57
53
  alias: duckValidatorsZod.aliasName,
58
54
  options: z.optional(duckAllConnectionOptionsZodSchema)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowblade/sqlduck",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "exports": {
@@ -53,7 +53,7 @@
53
53
  "fix-staged": "lint-staged --allow-empty",
54
54
  "check-dist": "es-check --config=.escheckrc.json",
55
55
  "check-pub": "publint",
56
- "check-size": "size-limit"
56
+ "check-size-disabled": "size-limit"
57
57
  },
58
58
  "dependencies": {
59
59
  "@flowblade/core": "^0.2.26",
@@ -90,11 +90,11 @@
90
90
  "@testcontainers/mssqlserver": "11.13.0",
91
91
  "@total-typescript/ts-reset": "0.6.1",
92
92
  "@types/node": "25.5.2",
93
- "@typescript-eslint/eslint-plugin": "8.58.0",
94
- "@typescript-eslint/parser": "8.58.0",
93
+ "@typescript-eslint/eslint-plugin": "8.58.1",
94
+ "@typescript-eslint/parser": "8.58.1",
95
95
  "@typescript/native-preview": "7.0.0-dev.20260406.1",
96
- "@vitest/coverage-v8": "4.1.2",
97
- "@vitest/ui": "4.1.2",
96
+ "@vitest/coverage-v8": "4.1.3",
97
+ "@vitest/ui": "4.1.3",
98
98
  "ansis": "4.2.0",
99
99
  "browserslist-to-esbuild": "2.1.1",
100
100
  "core-js": "3.49.0",
@@ -123,7 +123,7 @@
123
123
  "typedoc-plugin-markdown": "4.11.0",
124
124
  "typescript": "6.0.2",
125
125
  "valibot": "1.3.1",
126
- "vitest": "4.1.2"
126
+ "vitest": "4.1.3"
127
127
  },
128
128
  "files": [
129
129
  "dist"