@malloydata/db-duckdb 0.0.406 → 0.0.407

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.
@@ -47,6 +47,7 @@ exports.sqlStringLiteral = sqlStringLiteral;
47
47
  exports.sqlStringListLiteral = sqlStringListLiteral;
48
48
  exports.stringifyDuckDBOption = stringifyDuckDBOption;
49
49
  const path_1 = __importDefault(require("path"));
50
+ const url_1 = require("url");
50
51
  const malloy_1 = require("@malloydata/malloy");
51
52
  const pathSecurity = __importStar(require("./path_security"));
52
53
  class DuckDBConfigValidationError extends Error {
@@ -348,9 +349,32 @@ function canonicalizeDatabasePath(databasePath) {
348
349
  }
349
350
  return canonicalizeConfigPath(databasePath, 'databasePath');
350
351
  }
352
+ // A config path can arrive as a `file://` URL rather than a plain path —
353
+ // notably `workingDirectory`, which defaults to `config.rootDirectory` (the
354
+ // config stack carries it as a URL string). Left as a URL, `path.resolve`
355
+ // treats `file:` as a relative segment and joins it to the process cwd,
356
+ // silently breaking relative `read_parquet`/glob resolution. Decode file URLs
357
+ // to a real path so every downstream consumer (FILE_SEARCH_PATH,
358
+ // allowed_directories, …) sees one. Plain paths and non-file schemes pass
359
+ // through untouched; a malformed file URL throws and surfaces as the caller's
360
+ // field-specific validation error.
361
+ function maybeFileURLToPath(input) {
362
+ // Cheap guard so plain paths (the common case) skip URL parsing entirely.
363
+ if (!/^[a-z][a-z0-9+.-]*:/i.test(input)) {
364
+ return input;
365
+ }
366
+ let url;
367
+ try {
368
+ url = new URL(input);
369
+ }
370
+ catch {
371
+ return input; // not a URL — treat as a plain path
372
+ }
373
+ return url.protocol === 'file:' ? (0, url_1.fileURLToPath)(url) : input;
374
+ }
351
375
  function canonicalizeConfigPath(input, fieldName, options = {}) {
352
376
  try {
353
- return pathSecurity.canonicalizePath(input, options);
377
+ return pathSecurity.canonicalizePath(maybeFileURLToPath(input), options);
354
378
  }
355
379
  catch (error) {
356
380
  throw new DuckDBConfigValidationError(`${fieldName} is invalid: ${errorMessage(error)}`);
@@ -214,6 +214,22 @@ function unwrapTable(table) {
214
214
  return table.toArray().map(row => unwrapRow(row, table.schema));
215
215
  }
216
216
  const isNode = () => { var _a; return typeof process !== 'undefined' && typeof ((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node) === 'string'; };
217
+ // `workingDirectory` defaults to `config.rootDirectory`, which the config
218
+ // stack carries as a URL string. DuckDB-Wasm's virtual filesystem wants a plain
219
+ // POSIX path; a `file://` URL left intact becomes a bogus FILE_SEARCH_PATH and
220
+ // breaks relative reads. Decode file URLs to their path. Browser-safe — uses
221
+ // the WHATWG `URL` (the native connection's Node `fileURLToPath` is unavailable
222
+ // here). Plain paths and non-file schemes pass through untouched.
223
+ function fileURLToVirtualPath(input) {
224
+ if (!/^file:\/\//i.test(input)) {
225
+ return input;
226
+ }
227
+ const decoded = decodeURIComponent(new URL(input).pathname);
228
+ // Drop a trailing separator but keep the filesystem root '/'.
229
+ return decoded.length > 1 && decoded.endsWith('/')
230
+ ? decoded.slice(0, -1)
231
+ : decoded;
232
+ }
217
233
  class DuckDBWASMConnection extends duckdb_common_1.DuckDBCommon {
218
234
  constructor(arg, arg2, workingDirectory, queryOptions) {
219
235
  var _a, _b;
@@ -233,7 +249,7 @@ class DuckDBWASMConnection extends duckdb_common_1.DuckDBCommon {
233
249
  this.databasePath = arg2;
234
250
  }
235
251
  if (typeof workingDirectory === 'string') {
236
- this.workingDirectory = workingDirectory;
252
+ this.workingDirectory = fileURLToVirtualPath(workingDirectory);
237
253
  }
238
254
  if (queryOptions) {
239
255
  this.queryOptions = queryOptions;
@@ -248,7 +264,7 @@ class DuckDBWASMConnection extends duckdb_common_1.DuckDBCommon {
248
264
  this.databasePath = arg.databasePath;
249
265
  }
250
266
  if (typeof arg.workingDirectory === 'string') {
251
- this.workingDirectory = arg.workingDirectory;
267
+ this.workingDirectory = fileURLToVirtualPath(arg.workingDirectory);
252
268
  }
253
269
  if (typeof arg.motherDuckToken === 'string') {
254
270
  this.motherDuckToken = arg.motherDuckToken;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/db-duckdb",
3
- "version": "0.0.406",
3
+ "version": "0.0.407",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -61,7 +61,7 @@
61
61
  "dependencies": {
62
62
  "@duckdb/duckdb-wasm": "1.33.1-dev45.0",
63
63
  "@duckdb/node-api": "1.5.3-r.2",
64
- "@malloydata/malloy": "0.0.406",
64
+ "@malloydata/malloy": "0.0.407",
65
65
  "@motherduck/wasm-client": "^0.6.6",
66
66
  "apache-arrow": "^17.0.0",
67
67
  "web-worker": "^1.5.0"