@lightdash/cli 2.339.1 → 2.340.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.
@@ -1 +1 @@
1
- {"version":3,"file":"duckdb.d.ts","sourceRoot":"","sources":["../../../src/dbt/targets/duckdb.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,uBAAuB,EAO1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,KAAK,qBAAqB,GAAG;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACnC,CAAC;AAEF,KAAK,cAAc,GAAG;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAC7D,MAAM,EACN,OAAO,CACV,CAAC;CACL,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE;QACP,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC7B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,MAAM,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;CAC9B,CAAC;AA6LF,eAAO,MAAM,mBAAmB,WACpB,MAAM,KACf,uBAmBF,CAAC"}
1
+ {"version":3,"file":"duckdb.d.ts","sourceRoot":"","sources":["../../../src/dbt/targets/duckdb.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,uBAAuB,EAQ1B,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,KAAK,qBAAqB,GAAG;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACnC,CAAC;AAEF,KAAK,cAAc,GAAG;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAC7D,MAAM,EACN,OAAO,CACV,CAAC;CACL,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE;QACP,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC7B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,MAAM,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;CAC9B,CAAC;AAiOF,eAAO,MAAM,mBAAmB,WACpB,MAAM,KACf,uBAwBF,CAAC"}
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.convertDuckdbSchema = void 0;
4
+ const tslib_1 = require("tslib");
4
5
  const common_1 = require("@lightdash/common");
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = tslib_1.__importDefault(require("node:path"));
5
8
  const fail = (target, message) => {
6
9
  throw new common_1.ParseError(`Couldn't read profiles.yml file for ${target.type}:\n${message}`);
7
10
  };
@@ -19,8 +22,8 @@ const validateDuckdbTarget = (target) => {
19
22
  return target;
20
23
  };
21
24
  const parseMotherDuck = (target) => {
22
- const path = target.path ?? '';
23
- const motherduckPath = path.slice(3);
25
+ const targetPath = target.path ?? '';
26
+ const motherduckPath = targetPath.slice(3);
24
27
  const [database, queryString = ''] = motherduckPath.split('?', 2);
25
28
  const motherduckToken = target.settings?.motherduck_token ||
26
29
  new URLSearchParams(queryString).get('motherduck_token');
@@ -145,6 +148,43 @@ const parseDucklake = (target) => {
145
148
  dataPath: parseDucklakeDataPath(dataPath, secrets),
146
149
  };
147
150
  };
151
+ // Keep identical to EMBEDDED_DATASET_PATTERN in packages/warehouses/src/warehouseClients/DuckdbWarehouseClient.ts
152
+ const EMBEDDED_DATASET_PATTERN = /^[a-z0-9_-]+$/;
153
+ /**
154
+ * A plain file path is accepted only when it names a `.duckdb` file that sits
155
+ * directly inside PLAYGROUND_DATA_DIR (the directory the server's embedded
156
+ * DuckDB client reads). The result is an embedded dataset reference, which the
157
+ * warehouse client opens read-only, so no user-supplied path is ever opened.
158
+ */
159
+ const parseEmbeddedLocalPath = (target, filePath) => {
160
+ const dataDirectory = process.env.PLAYGROUND_DATA_DIR;
161
+ if (!dataDirectory)
162
+ return undefined;
163
+ let realDirectory;
164
+ let realFile;
165
+ try {
166
+ realDirectory = (0, node_fs_1.realpathSync)(dataDirectory);
167
+ realFile = (0, node_fs_1.realpathSync)(node_path_1.default.resolve(filePath));
168
+ if (!(0, node_fs_1.statSync)(realFile).isFile())
169
+ return undefined;
170
+ }
171
+ catch {
172
+ return undefined;
173
+ }
174
+ if (node_path_1.default.dirname(realFile) !== realDirectory)
175
+ return undefined;
176
+ if (node_path_1.default.extname(realFile) !== '.duckdb')
177
+ return undefined;
178
+ const dataset = node_path_1.default.basename(realFile, '.duckdb');
179
+ if (!EMBEDDED_DATASET_PATTERN.test(dataset))
180
+ return undefined;
181
+ return {
182
+ type: common_1.WarehouseTypes.DUCKDB,
183
+ connectionType: common_1.DuckdbConnectionType.EMBEDDED,
184
+ dataset,
185
+ schema: target.schema,
186
+ };
187
+ };
148
188
  const convertDuckdbSchema = (target) => {
149
189
  const t = validateDuckdbTarget(target);
150
190
  const hasDucklakeAttach = (t.attach ?? []).some((a) => a.path.startsWith('ducklake:'));
@@ -154,6 +194,11 @@ const convertDuckdbSchema = (target) => {
154
194
  if (t.path?.startsWith('md:')) {
155
195
  return parseMotherDuck(t);
156
196
  }
157
- return fail(target, "Lightdash supports MotherDuck targets (path starting with 'md:') and DuckLake targets (attach entry with a 'ducklake:' path).");
197
+ if (t.path) {
198
+ const embedded = parseEmbeddedLocalPath(t, t.path);
199
+ if (embedded)
200
+ return embedded;
201
+ }
202
+ return fail(target, "Lightdash supports MotherDuck targets (path starting with 'md:'), DuckLake targets (attach entry with a 'ducklake:' path), and a local .duckdb file inside PLAYGROUND_DATA_DIR.");
158
203
  };
159
204
  exports.convertDuckdbSchema = convertDuckdbSchema;
@@ -1 +1 @@
1
- {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../src/handlers/dbt/apiClient.ts"],"names":[],"mappings":"AACA,OAAO,EAGH,WAAW,EAIX,WAAW,EAEX,KAAK,6BAA6B,EAGrC,MAAM,mBAAmB,CAAC;AAC3B,OAAc,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS5D,KAAK,iBAAiB,GAAG;IACrB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC9B,CAAC;AAEF,KAAK,oBAAoB,GAAG,iBAAiB,GAAG;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAAC;AAKF,eAAO,MAAM,cAAc,YAAa,OAAO,SAE9C,CAAC;AAEF,eAAO,MAAM,eAAe,oDAKzB,oBAAoB,KAAG,OAAO,CAAC,QAAQ,CA8BzC,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,CAAC,SAAS,WAAW,CAAC,SAAS,CAAC,0BAIhE,iBAAiB,KAAG,OAAO,CAAC,CAAC,CAgD/B,CAAC;AAEF,eAAO,MAAM,cAAc,QACb,OAAO,CAAC,6BAA6B,CAKzC,CAAC;AAEX,MAAM,MAAM,8BAA8B,GAAG;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,mBAAmB,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,iCAAiC,gBAC7B,MAAM,KACpB,OAAO,CAAC,8BAA8B,CAiGxC,CAAC;AAEF,eAAO,MAAM,8BAA8B,wBAClB,MAAM,GAAG,SAAS,eAC1B,WAAW,KACzB,OAAO,CAAC,IAAI,CA+Gd,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAa,OAAO,CAAC,IAAI,CA2B1D,CAAC"}
1
+ {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../src/handlers/dbt/apiClient.ts"],"names":[],"mappings":"AACA,OAAO,EAGH,WAAW,EAIX,WAAW,EAEX,KAAK,6BAA6B,EAGrC,MAAM,mBAAmB,CAAC;AAC3B,OAAc,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS5D,KAAK,iBAAiB,GAAG;IACrB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC9B,CAAC;AAEF,KAAK,oBAAoB,GAAG,iBAAiB,GAAG;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAAC;AAKF,eAAO,MAAM,cAAc,YAAa,OAAO,SAE9C,CAAC;AAqCF,eAAO,MAAM,eAAe,oDAKzB,oBAAoB,KAAG,OAAO,CAAC,QAAQ,CA8BzC,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,CAAC,SAAS,WAAW,CAAC,SAAS,CAAC,0BAIhE,iBAAiB,KAAG,OAAO,CAAC,CAAC,CAgD/B,CAAC;AAEF,eAAO,MAAM,cAAc,QACb,OAAO,CAAC,6BAA6B,CAKzC,CAAC;AAEX,MAAM,MAAM,8BAA8B,GAAG;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,mBAAmB,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,iCAAiC,gBAC7B,MAAM,KACpB,OAAO,CAAC,8BAA8B,CAiGxC,CAAC;AAEF,eAAO,MAAM,8BAA8B,wBAClB,MAAM,GAAG,SAAS,eAC1B,WAAW,KACzB,OAAO,CAAC,IAAI,CA+Gd,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAa,OAAO,CAAC,IAAI,CA2B1D,CAAC"}
@@ -18,6 +18,38 @@ const setGzipEnabled = (enabled) => {
18
18
  gzipEnabled = enabled;
19
19
  };
20
20
  exports.setGzipEnabled = setGzipEnabled;
21
+ /**
22
+ * Optional per-request deadline. Unset (the default) keeps today's behaviour:
23
+ * a request waits as long as the server takes. Set by hosts that run the CLI
24
+ * unattended, such as the Learn sandbox, so a stalled server surfaces as an
25
+ * error instead of a hang.
26
+ */
27
+ const getRequestTimeoutMs = () => {
28
+ const raw = process.env.LIGHTDASH_API_TIMEOUT_MS;
29
+ if (!raw)
30
+ return undefined;
31
+ const value = Number.parseInt(raw, 10);
32
+ return Number.isFinite(value) && value > 0 ? value : undefined;
33
+ };
34
+ const fetchWithTimeout = async (fullUrl, init) => {
35
+ const timeoutMs = getRequestTimeoutMs();
36
+ if (timeoutMs === undefined)
37
+ return (0, node_fetch_1.default)(fullUrl, init);
38
+ const controller = new AbortController();
39
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
40
+ try {
41
+ return await (0, node_fetch_1.default)(fullUrl, { ...init, signal: controller.signal });
42
+ }
43
+ catch (error) {
44
+ if (error.name === 'AbortError') {
45
+ throw new Error(`Request to ${fullUrl} timed out after ${timeoutMs}ms`);
46
+ }
47
+ throw error;
48
+ }
49
+ finally {
50
+ clearTimeout(timer);
51
+ }
52
+ };
21
53
  const lightdashRawApi = async ({ method, url, body, headers: requestHeaders = {}, }) => {
22
54
  const config = await (0, config_1.getConfig)();
23
55
  if (!(config.context?.apiKey && config.context.serverUrl)) {
@@ -29,7 +61,7 @@ const lightdashRawApi = async ({ method, url, body, headers: requestHeaders = {}
29
61
  };
30
62
  const fullUrl = new url_1.URL(url, config.context.serverUrl).href;
31
63
  globalState_1.default.debug(`> Making HTTP ${method} request to: ${fullUrl}`);
32
- const response = await (0, node_fetch_1.default)(fullUrl, { method, headers, body });
64
+ const response = await fetchWithTimeout(fullUrl, { method, headers, body });
33
65
  globalState_1.default.debug(`> HTTP request returned status: ${response.status}`);
34
66
  if (!response.ok) {
35
67
  const contentType = response.headers.get('content-type');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "2.339.1",
3
+ "version": "2.340.0",
4
4
  "description": "Lightdash CLI tool",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -22,8 +22,8 @@
22
22
  "@actions/core": "1.11.1",
23
23
  "@aws-sdk/credential-providers": "3.995.0",
24
24
  "@casl/ability": "6.8.0",
25
- "@lightdash/common": "2.339.1",
26
- "@lightdash/warehouses": "2.339.1",
25
+ "@lightdash/common": "2.340.0",
26
+ "@lightdash/warehouses": "2.340.0",
27
27
  "@sidvind/better-ajv-errors": "7.0.0",
28
28
  "@types/columnify": "1.5.1",
29
29
  "ajv": "8.18.0",