@graphenedata/cli 0.0.17 → 0.0.19

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.
Files changed (42) hide show
  1. package/README.md +4 -2
  2. package/dist/cli/athena-WROJBSLV.js +136 -0
  3. package/dist/cli/athena-WROJBSLV.js.map +7 -0
  4. package/dist/cli/{bigQuery-OQUNH3VT.js → bigQuery-3A7HPXZS.js} +2 -2
  5. package/dist/cli/{chunk-56K2FF57.js → chunk-KW66YQ62.js} +4 -2
  6. package/dist/cli/chunk-KW66YQ62.js.map +7 -0
  7. package/dist/cli/{chunk-TZTTALAV.js → chunk-KYTXXLSS.js} +5401 -4664
  8. package/dist/cli/chunk-KYTXXLSS.js.map +7 -0
  9. package/dist/cli/chunk-OVF4UUFF.js +28 -0
  10. package/dist/cli/chunk-OVF4UUFF.js.map +7 -0
  11. package/dist/cli/cli.js +249 -20
  12. package/dist/cli/{duckdb-TKVMONRK.js → duckdb-YOIX6QOQ.js} +2 -2
  13. package/dist/cli/installBrowser.js +11 -0
  14. package/dist/cli/installBrowser.js.map +7 -0
  15. package/dist/cli/postgres-NF43BPZY.js +147 -0
  16. package/dist/cli/postgres-NF43BPZY.js.map +7 -0
  17. package/dist/cli/{serve2-S2LL4D4D.js → serve2-XALOUIFB.js} +7 -3
  18. package/dist/cli/{serve2-S2LL4D4D.js.map → serve2-XALOUIFB.js.map} +2 -2
  19. package/dist/cli/{snowflake-3VPDEYYP.js → snowflake-GX4FSSWT.js} +2 -2
  20. package/dist/index.d.ts +4 -4
  21. package/dist/lang/index.d.ts +4 -4
  22. package/dist/skills/graphene/SKILL.md +19 -12
  23. package/dist/skills/graphene/references/dropdown.md +12 -0
  24. package/dist/skills/graphene/references/gsql.md +26 -23
  25. package/dist/ui/component-utilities/enrich.ts +92 -53
  26. package/dist/ui/component-utilities/format.ts +36 -21
  27. package/dist/ui/component-utilities/theme.ts +0 -1
  28. package/dist/ui/components/AreaChart.svelte +4 -3
  29. package/dist/ui/components/BarChart.svelte +5 -4
  30. package/dist/ui/components/LineChart.svelte +4 -3
  31. package/dist/ui/components/ScatterPlot.svelte +4 -3
  32. package/dist/ui/components/_Table.svelte +3 -1
  33. package/dist/ui/internal/LocalApp.svelte +5 -1
  34. package/dist/ui/internal/PageNavGroup.svelte +2 -2
  35. package/dist/ui/internal/Sidebar.svelte +7 -7
  36. package/dist/ui/internal/sidebar.svelte.js +11 -1
  37. package/package.json +13 -4
  38. package/dist/cli/chunk-56K2FF57.js.map +0 -7
  39. package/dist/cli/chunk-TZTTALAV.js.map +0 -7
  40. /package/dist/cli/{bigQuery-OQUNH3VT.js.map → bigQuery-3A7HPXZS.js.map} +0 -0
  41. /package/dist/cli/{duckdb-TKVMONRK.js.map → duckdb-YOIX6QOQ.js.map} +0 -0
  42. /package/dist/cli/{snowflake-3VPDEYYP.js.map → snowflake-GX4FSSWT.js.map} +0 -0
@@ -0,0 +1,28 @@
1
+ // installBrowser.ts
2
+ import { spawn } from "child_process";
3
+ import { createRequire } from "module";
4
+ import path from "path";
5
+ var nodeRequire = createRequire(import.meta.url);
6
+ async function installBrowser(options = {}) {
7
+ if (options.postinstall && process.env.PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD) {
8
+ console.log("Skipping Graphene browser install because PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD is set.");
9
+ return true;
10
+ }
11
+ let cliPath = path.join(path.dirname(nodeRequire.resolve("playwright-core")), "cli.js");
12
+ let args = [cliPath, "install", "--only-shell", ...options.withDeps ? ["--with-deps"] : [], "chromium"];
13
+ let result = await new Promise((resolve, reject) => {
14
+ let child = spawn(process.execPath, args, { stdio: "inherit" });
15
+ child.on("error", reject);
16
+ child.on("close", (code) => resolve(code ?? 1));
17
+ });
18
+ if (result === 0) return true;
19
+ if (!options.postinstall) return false;
20
+ console.warn("Graphene could not install its headless browser during package install.");
21
+ console.warn("Run `graphene install-browser` before using `graphene run --headless` screenshots.");
22
+ return true;
23
+ }
24
+
25
+ export {
26
+ installBrowser
27
+ };
28
+ //# sourceMappingURL=chunk-OVF4UUFF.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../installBrowser.ts"],
4
+ "sourcesContent": ["import {spawn} from 'child_process'\nimport {createRequire} from 'module'\nimport path from 'path'\n\nconst nodeRequire = createRequire(import.meta.url)\n\nexport async function installBrowser(options: {withDeps?: boolean; postinstall?: boolean} = {}) {\n if (options.postinstall && process.env.PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD) {\n console.log('Skipping Graphene browser install because PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD is set.')\n return true\n }\n\n let cliPath = path.join(path.dirname(nodeRequire.resolve('playwright-core')), 'cli.js')\n let args = [cliPath, 'install', '--only-shell', ...(options.withDeps ? ['--with-deps'] : []), 'chromium']\n let result = await new Promise<number>((resolve, reject) => {\n let child = spawn(process.execPath, args, {stdio: 'inherit'})\n child.on('error', reject)\n child.on('close', code => resolve(code ?? 1))\n })\n\n if (result === 0) return true\n if (!options.postinstall) return false\n\n console.warn('Graphene could not install its headless browser during package install.')\n console.warn('Run `graphene install-browser` before using `graphene run --headless` screenshots.')\n return true\n}\n"],
5
+ "mappings": ";AAAA,SAAQ,aAAY;AACpB,SAAQ,qBAAoB;AAC5B,OAAO,UAAU;AAEjB,IAAM,cAAc,cAAc,YAAY,GAAG;AAEjD,eAAsB,eAAe,UAAuD,CAAC,GAAG;AAC9F,MAAI,QAAQ,eAAe,QAAQ,IAAI,kCAAkC;AACvE,YAAQ,IAAI,oFAAoF;AAChG,WAAO;AAAA,EACT;AAEA,MAAI,UAAU,KAAK,KAAK,KAAK,QAAQ,YAAY,QAAQ,iBAAiB,CAAC,GAAG,QAAQ;AACtF,MAAI,OAAO,CAAC,SAAS,WAAW,gBAAgB,GAAI,QAAQ,WAAW,CAAC,aAAa,IAAI,CAAC,GAAI,UAAU;AACxG,MAAI,SAAS,MAAM,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC1D,QAAI,QAAQ,MAAM,QAAQ,UAAU,MAAM,EAAC,OAAO,UAAS,CAAC;AAC5D,UAAM,GAAG,SAAS,MAAM;AACxB,UAAM,GAAG,SAAS,UAAQ,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAC9C,CAAC;AAED,MAAI,WAAW,EAAG,QAAO;AACzB,MAAI,CAAC,QAAQ,YAAa,QAAO;AAEjC,UAAQ,KAAK,yEAAyE;AACtF,UAAQ,KAAK,oFAAoF;AACjG,SAAO;AACT;",
6
+ "names": []
7
+ }
package/dist/cli/cli.js CHANGED
@@ -20,18 +20,21 @@ import {
20
20
  runServeInBackground,
21
21
  stopGrapheneIfRunning,
22
22
  toSql
23
- } from "./chunk-TZTTALAV.js";
23
+ } from "./chunk-KYTXXLSS.js";
24
+ import {
25
+ installBrowser
26
+ } from "./chunk-OVF4UUFF.js";
24
27
  import {
25
28
  config,
26
29
  loadConfig,
27
30
  setGlobalConfig
28
- } from "./chunk-56K2FF57.js";
31
+ } from "./chunk-KW66YQ62.js";
29
32
 
30
33
  // cli.ts
31
34
  import { Command } from "commander";
32
35
  import dotenv from "dotenv";
33
- import fs from "fs-extra";
34
- import path2 from "path";
36
+ import fs2 from "fs-extra";
37
+ import path3 from "path";
35
38
  import { fileURLToPath } from "url";
36
39
 
37
40
  // check.ts
@@ -47,9 +50,9 @@ async function check(options) {
47
50
  let files = await loadWorkspace(config.root, !targetFile, config.ignoredFiles);
48
51
  options.telemetry?.event("workspace_scanned", { command: "check", ...getWorkspaceScanCounts(files) });
49
52
  if (process.env.NODE_ENV == "test") {
50
- for (let [path3, contents] of Object.entries(mockFileMap)) {
51
- if (targetFile && path3 != targetFile) continue;
52
- upsertFile(files, { path: path3, contents });
53
+ for (let [path4, contents] of Object.entries(mockFileMap)) {
54
+ if (targetFile && path4 != targetFile) continue;
55
+ upsertFile(files, { path: path4, contents });
53
56
  }
54
57
  }
55
58
  if (targetFile) {
@@ -75,12 +78,226 @@ function upsertFile(files, next) {
75
78
  else files.push(next);
76
79
  }
77
80
 
81
+ // updateNotifier.ts
82
+ import ci from "ci-info";
83
+ import { randomUUID } from "node:crypto";
84
+ import * as fs from "node:fs/promises";
85
+ import path2 from "node:path";
86
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
87
+ var NOTICE_INTERVAL_MS = 7 * 24 * 60 * 60 * 1e3;
88
+ var DEFAULT_UPDATE_CHECK_URL = "https://registry.npmjs.org/%40graphenedata%2Fcli/latest";
89
+ var GITHUB_RELEASE_URL = "https://github.com/graphene-data/graphene/releases/tag";
90
+ var PACKAGE_NAME = "@graphenedata/cli";
91
+ async function showCachedUpdateNotice(options) {
92
+ let env = options.env || process.env;
93
+ let stderr = options.stderr || process.stderr;
94
+ if (!isUpdateNotifierEnabled(options.config, env, stderr, options.packageIsPrivate)) return;
95
+ let now = options.now || Date.now();
96
+ let stateTarget = await getUpdateStateTarget(options);
97
+ if (!stateTarget) return;
98
+ let state = await readUpdateState(stateTarget.filePath);
99
+ if (state.latestVersion && isNewerVersion(state.latestVersion, options.currentVersion) && shouldShowNotice(state, now)) {
100
+ let command = await getUpgradeCommand(options.config.root, env);
101
+ stderr.write(`Graphene ${state.latestVersion} is available. You are using ${options.currentVersion}.
102
+ `);
103
+ stderr.write(`Update: ${command}
104
+ `);
105
+ stderr.write(`Release notes: ${GITHUB_RELEASE_URL}/v${state.latestVersion}
106
+ `);
107
+ state = { ...state, lastNoticeVersion: state.latestVersion, lastNoticeAt: now };
108
+ await writeUpdateState(stateTarget, state);
109
+ }
110
+ }
111
+ async function checkForUpdate(options) {
112
+ let env = options.env || process.env;
113
+ let stderr = options.stderr || process.stderr;
114
+ if (!isUpdateNotifierEnabled(options.config, env, stderr, options.packageIsPrivate)) return;
115
+ let now = options.now || Date.now();
116
+ let stateTarget = await getUpdateStateTarget(options);
117
+ if (!stateTarget) return;
118
+ let state = await readUpdateState(stateTarget.filePath);
119
+ if (!shouldCheckForUpdate(state, now)) return;
120
+ await writeUpdateState(stateTarget, { ...state, lastCheckedAt: now });
121
+ let latestVersion = await (options.fetchLatestVersion || fetchLatestVersion)(env.GRAPHENE_UPDATE_CHECK_URL || DEFAULT_UPDATE_CHECK_URL);
122
+ if (latestVersion && isStrictSemver(latestVersion)) await writeUpdateState(stateTarget, { ...state, lastCheckedAt: now, latestVersion });
123
+ }
124
+ function isUpdateNotifierEnabled(config2, env = process.env, stderr = process.stderr, packageIsPrivate = false) {
125
+ if (packageIsPrivate) return false;
126
+ if (config2.updateNotifier === false) return false;
127
+ if (env.GRAPHENE_NO_UPDATE_NOTIFIER == "1") return false;
128
+ if (env.NODE_ENV == "test") return false;
129
+ if (isCiEnv(env)) return false;
130
+ if (!stderr.isTTY) return false;
131
+ return true;
132
+ }
133
+ function isNewerVersion(candidate, current) {
134
+ if (!isStrictSemver(candidate) || !isStrictSemver(current)) return false;
135
+ let candidateParts = candidate.split(".").map(Number);
136
+ let currentParts = current.split(".").map(Number);
137
+ for (let i = 0; i < candidateParts.length; i++) {
138
+ if (candidateParts[i] > currentParts[i]) return true;
139
+ if (candidateParts[i] < currentParts[i]) return false;
140
+ }
141
+ return false;
142
+ }
143
+ async function getUpgradeCommand(projectRoot, env = process.env) {
144
+ let packageManager = await detectPackageManager(projectRoot, env);
145
+ let dependencyFlag = await getGrapheneDependencyType(projectRoot) == "devDependencies" ? devDependencyFlag(packageManager) : "";
146
+ let command = `${packageManager} ${packageManager == "npm" ? "install" : "add"} ${PACKAGE_NAME}@latest`;
147
+ return dependencyFlag ? `${command} ${dependencyFlag}` : command;
148
+ }
149
+ async function detectPackageManager(projectRoot, env = process.env) {
150
+ let packageManager = await findPackageManagerField(projectRoot);
151
+ if (packageManager) return packageManager;
152
+ let lockfilePackageManager = await findLockfilePackageManager(projectRoot);
153
+ if (lockfilePackageManager) return lockfilePackageManager;
154
+ return parsePackageManager(env.npm_config_user_agent) || "npm";
155
+ }
156
+ function shouldShowNotice(state, now) {
157
+ if (state.lastNoticeVersion != state.latestVersion) return true;
158
+ return !state.lastNoticeAt || now - state.lastNoticeAt >= NOTICE_INTERVAL_MS;
159
+ }
160
+ function shouldCheckForUpdate(state, now) {
161
+ return !state.lastCheckedAt || now - state.lastCheckedAt >= CHECK_INTERVAL_MS;
162
+ }
163
+ async function fetchLatestVersion(url) {
164
+ let controller = new AbortController();
165
+ let timeout = setTimeout(() => controller.abort(), 500);
166
+ timeout.unref?.();
167
+ try {
168
+ let response = await fetch(url, { signal: controller.signal });
169
+ if (!response.ok) return null;
170
+ let body = await response.json();
171
+ return typeof body.version == "string" ? body.version : null;
172
+ } catch {
173
+ return null;
174
+ } finally {
175
+ clearTimeout(timeout);
176
+ }
177
+ }
178
+ async function getUpdateStateTarget(options) {
179
+ if (options.statePath) return { filePath: options.statePath };
180
+ let nodeModulesPath = path2.join(options.config.root, "node_modules");
181
+ try {
182
+ if (!(await fs.stat(nodeModulesPath)).isDirectory()) return null;
183
+ } catch {
184
+ return null;
185
+ }
186
+ return { filePath: path2.join(nodeModulesPath, ".graphene", "update-check.json"), requiredDir: nodeModulesPath };
187
+ }
188
+ async function readUpdateState(filePath) {
189
+ try {
190
+ return normalizeUpdateState(JSON.parse(await fs.readFile(filePath, "utf-8")));
191
+ } catch {
192
+ return {};
193
+ }
194
+ }
195
+ async function writeUpdateState(target, state) {
196
+ let filePath = target.filePath;
197
+ let tmpPath = `${filePath}.tmp-${randomUUID()}`;
198
+ try {
199
+ if (target.requiredDir && !(await fs.stat(target.requiredDir)).isDirectory()) return;
200
+ await fs.mkdir(path2.dirname(filePath), { recursive: true });
201
+ await fs.writeFile(tmpPath, JSON.stringify(state, null, 2) + "\n");
202
+ await fs.rename(tmpPath, filePath);
203
+ } catch {
204
+ try {
205
+ await fs.unlink(tmpPath);
206
+ } catch {
207
+ }
208
+ }
209
+ }
210
+ function normalizeUpdateState(state) {
211
+ return {
212
+ ...typeof state.lastCheckedAt == "number" ? { lastCheckedAt: state.lastCheckedAt } : {},
213
+ ...typeof state.latestVersion == "string" ? { latestVersion: state.latestVersion } : {},
214
+ ...typeof state.lastNoticeVersion == "string" ? { lastNoticeVersion: state.lastNoticeVersion } : {},
215
+ ...typeof state.lastNoticeAt == "number" ? { lastNoticeAt: state.lastNoticeAt } : {}
216
+ };
217
+ }
218
+ async function findPackageManagerField(projectRoot) {
219
+ for (let dir of ancestorDirs(projectRoot)) {
220
+ let packageJson = await readPackageJson(path2.join(dir, "package.json"));
221
+ let packageManager = parsePackageManager(packageJson?.packageManager);
222
+ if (packageManager) return packageManager;
223
+ }
224
+ return null;
225
+ }
226
+ async function findLockfilePackageManager(projectRoot) {
227
+ let lockfiles = [
228
+ ["pnpm-lock.yaml", "pnpm"],
229
+ ["yarn.lock", "yarn"],
230
+ ["package-lock.json", "npm"],
231
+ ["npm-shrinkwrap.json", "npm"],
232
+ ["bun.lock", "bun"],
233
+ ["bun.lockb", "bun"]
234
+ ];
235
+ for (let dir of ancestorDirs(projectRoot)) {
236
+ for (let [file, packageManager] of lockfiles) {
237
+ try {
238
+ await fs.access(path2.join(dir, file));
239
+ return packageManager;
240
+ } catch {
241
+ }
242
+ }
243
+ }
244
+ return null;
245
+ }
246
+ async function getGrapheneDependencyType(projectRoot) {
247
+ let packageJson = await readPackageJson(path2.join(projectRoot, "package.json"));
248
+ if (packageJson?.devDependencies?.[PACKAGE_NAME]) return "devDependencies";
249
+ if (packageJson?.dependencies?.[PACKAGE_NAME]) return "dependencies";
250
+ return null;
251
+ }
252
+ async function readPackageJson(filePath) {
253
+ try {
254
+ return JSON.parse(await fs.readFile(filePath, "utf-8"));
255
+ } catch {
256
+ return null;
257
+ }
258
+ }
259
+ function parsePackageManager(value) {
260
+ if (typeof value != "string") return null;
261
+ let normalized = value.toLowerCase();
262
+ if (normalized.includes("pnpm")) return "pnpm";
263
+ if (normalized.includes("yarn")) return "yarn";
264
+ if (normalized.includes("bun")) return "bun";
265
+ if (normalized.includes("npm")) return "npm";
266
+ return null;
267
+ }
268
+ function devDependencyFlag(packageManager) {
269
+ if (packageManager == "bun") return "-d";
270
+ return "-D";
271
+ }
272
+ function isStrictSemver(version) {
273
+ return /^\d+\.\d+\.\d+$/.test(version);
274
+ }
275
+ function isCiEnv(env) {
276
+ if (env === process.env) return ci.isCI;
277
+ return env.CI == "true" || env.CI == "1" || !!env.GITHUB_ACTIONS || !!env.BUILDKITE || !!env.CIRCLECI;
278
+ }
279
+ function ancestorDirs(startDir) {
280
+ let dirs = [];
281
+ let current = path2.resolve(startDir);
282
+ while (true) {
283
+ dirs.push(current);
284
+ let parent = path2.dirname(current);
285
+ if (parent == current) return dirs;
286
+ current = parent;
287
+ }
288
+ }
289
+
78
290
  // cli.ts
79
291
  var program = new Command();
80
- var __dirname = path2.dirname(fileURLToPath(import.meta.url));
81
- var pkgPath = fs.existsSync(path2.join(__dirname, "package.json")) ? path2.join(__dirname, "package.json") : path2.join(__dirname, "../../package.json");
82
- var libPkg = fs.readJsonSync(pkgPath);
292
+ var __dirname = path3.dirname(fileURLToPath(import.meta.url));
293
+ var pkgPath = fs2.existsSync(path3.join(__dirname, "package.json")) ? path3.join(__dirname, "package.json") : path3.join(__dirname, "../../package.json");
294
+ var libPkg = fs2.readJsonSync(pkgPath);
83
295
  program.name("graphene").description("Graphene CLI").version(libPkg.version, "-v, --version");
296
+ registerInstallBrowserCommand(program);
297
+ if (process.argv[2] === "install-browser") {
298
+ await program.parseAsync(process.argv);
299
+ process.exit(0);
300
+ }
84
301
  var cfg = await loadConfig(process.cwd(), (envFiles) => {
85
302
  dotenv.config({ quiet: true, path: envFiles });
86
303
  });
@@ -97,20 +314,24 @@ program.command("compile").description("Translate a query to SQL and print it").
97
314
  console.log(toSql(query));
98
315
  })
99
316
  );
100
- program.command("run").description("Run a query or screenshot a Graphene page").argument("[input]", 'Path to file, a raw string, or "-" for stdin').option("-c, --chart <chartTitleOrComponentId>", "Title or component ID of a specific chart to capture").option("-q, --query <queryName>", "Query or table name to run from a markdown page").option("--input <key=value>", "Input value to use for parameters; repeat for multiple values", (value, previous) => previous.concat(value), []).action(
317
+ program.command("run").description("Run a query or screenshot a Graphene page").argument("[input]", 'Path to file, a raw string, or "-" for stdin').option("-c, --chart <chartTitleOrComponentId>", "Title or component ID of a specific chart to capture").option("--headless", "Run markdown pages in a headless browser instead of opening the system browser").option("-q, --query <queryName>", "Query or table name to run from a markdown page").option("--input <key=value>", "Input value to use for parameters; repeat for multiple values", (value, previous) => previous.concat(value), []).action(
101
318
  withTelemetry("run", async (exit, input, options) => {
102
319
  if (options.chart && options.query) {
103
320
  console.error("Cannot use --chart and --query together");
104
321
  return exit(1);
105
322
  }
323
+ if (options.headless && options.query) {
324
+ console.error("Cannot use --headless and --query together");
325
+ return exit(1);
326
+ }
106
327
  let inputs = parseRunInputs(options.input || [], exit);
107
328
  let inputPath = getExistingPath(input);
108
329
  if (inputPath && inputPath.endsWith(".md")) {
109
- let res2 = options.query ? await runNamedQueryFromMd(inputPath, options.query, { inputs, telemetry }) : await runMdFile({ mdArg: inputPath, chart: options.chart, inputs, telemetry });
330
+ let res2 = options.query ? await runNamedQueryFromMd(inputPath, options.query, { inputs, telemetry }) : await runMdFile({ mdArg: inputPath, chart: options.chart, headless: options.headless, inputs, telemetry });
110
331
  return exit(res2 ? 0 : 1);
111
332
  }
112
- if (options.chart || options.query) {
113
- console.error("--chart and --query can only be used with a markdown file path");
333
+ if (options.chart || options.headless || options.query) {
334
+ console.error("--chart, --headless, and --query can only be used with a markdown file path");
114
335
  return exit(1);
115
336
  }
116
337
  if (inputPath && inputPath.endsWith(".gsql")) {
@@ -193,7 +414,7 @@ program.command("serve").description("Run the local server").option("--bg", "Run
193
414
  await runServeInBackground();
194
415
  return exit(0);
195
416
  } else {
196
- let mod = await import("./serve2-S2LL4D4D.js");
417
+ let mod = await import("./serve2-XALOUIFB.js");
197
418
  await mod.serve2(telemetry);
198
419
  }
199
420
  })
@@ -217,6 +438,12 @@ program.command("login").description("Log in to Graphene Cloud").action(
217
438
  })
218
439
  );
219
440
  program.parse(process.argv);
441
+ function registerInstallBrowserCommand(program2) {
442
+ program2.command("install-browser").description("Install the browser used by graphene run --headless screenshots").option("--with-deps", "Also install browser system dependencies where supported").action(async (options) => {
443
+ let ok = await installBrowser({ withDeps: options.withDeps });
444
+ process.exit(ok ? 0 : 1);
445
+ });
446
+ }
220
447
  async function readInput(arg) {
221
448
  if (!arg || arg === "-") {
222
449
  return await new Promise((resolve) => {
@@ -227,16 +454,16 @@ async function readInput(arg) {
227
454
  process.stdin.resume();
228
455
  });
229
456
  }
230
- let absolutePath = path2.resolve(arg);
231
- if (fs.existsSync(absolutePath)) {
232
- return await fs.promises.readFile(absolutePath, "utf-8");
457
+ let absolutePath = path3.resolve(arg);
458
+ if (fs2.existsSync(absolutePath)) {
459
+ return await fs2.promises.readFile(absolutePath, "utf-8");
233
460
  }
234
461
  return arg;
235
462
  }
236
463
  function getExistingPath(arg) {
237
464
  if (!arg || arg === "-") return null;
238
- let absolutePath = path2.resolve(arg);
239
- return fs.existsSync(absolutePath) ? absolutePath : null;
465
+ let absolutePath = path3.resolve(arg);
466
+ return fs2.existsSync(absolutePath) ? absolutePath : null;
240
467
  }
241
468
  function validateInputQuery(analysis, exit) {
242
469
  if (analysis.diagnostics.length) {
@@ -287,6 +514,7 @@ function withTelemetry(command, action) {
287
514
  let exitCalled = false;
288
515
  let caughtError;
289
516
  telemetry.event("cli_command_started", { command, flags: getPresentFlags(command, process.argv.slice(2)) });
517
+ await showCachedUpdateNotice({ config, currentVersion: libPkg.version, packageIsPrivate: libPkg.private });
290
518
  let exit = (code = 0) => {
291
519
  exitCalled = true;
292
520
  exitCode = code;
@@ -306,6 +534,7 @@ function withTelemetry(command, action) {
306
534
  if (fromVersion) telemetry.event("cli_upgraded", { from_version: fromVersion, to_version: libPkg.version });
307
535
  }
308
536
  telemetry.event("cli_command_completed", { command, success, exit_code: exitCode, duration_ms: Date.now() - startedAt });
537
+ await checkForUpdate({ config, currentVersion: libPkg.version, packageIsPrivate: libPkg.private });
309
538
  }
310
539
  if (caughtError) throw caughtError;
311
540
  else if (exitCalled) process.exit(exitCode);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  config
3
- } from "./chunk-56K2FF57.js";
3
+ } from "./chunk-KW66YQ62.js";
4
4
 
5
5
  // connections/duckdb.ts
6
6
  import { DuckDBTimestampValue, DuckDBInstance, DuckDBDateValue, DuckDBDecimalValue } from "@duckdb/node-api";
@@ -84,4 +84,4 @@ var DuckDBConnection = class {
84
84
  export {
85
85
  DuckDBConnection
86
86
  };
87
- //# sourceMappingURL=duckdb-TKVMONRK.js.map
87
+ //# sourceMappingURL=duckdb-YOIX6QOQ.js.map
@@ -0,0 +1,11 @@
1
+ import {
2
+ installBrowser
3
+ } from "./chunk-OVF4UUFF.js";
4
+
5
+ // installBrowserEntry.ts
6
+ var ok = await installBrowser({
7
+ withDeps: process.argv.includes("--with-deps"),
8
+ postinstall: process.argv.includes("--postinstall")
9
+ });
10
+ process.exit(ok ? 0 : 1);
11
+ //# sourceMappingURL=installBrowser.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../installBrowserEntry.ts"],
4
+ "sourcesContent": ["import {installBrowser} from './installBrowser.ts'\n\nlet ok = await installBrowser({\n withDeps: process.argv.includes('--with-deps'),\n postinstall: process.argv.includes('--postinstall'),\n})\nprocess.exit(ok ? 0 : 1)\n"],
5
+ "mappings": ";;;;;AAEA,IAAI,KAAK,MAAM,eAAe;AAAA,EAC5B,UAAU,QAAQ,KAAK,SAAS,aAAa;AAAA,EAC7C,aAAa,QAAQ,KAAK,SAAS,eAAe;AACpD,CAAC;AACD,QAAQ,KAAK,KAAK,IAAI,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,147 @@
1
+ import {
2
+ config
3
+ } from "./chunk-KW66YQ62.js";
4
+
5
+ // connections/postgres.ts
6
+ import pg from "pg";
7
+ var NUMERIC_OIDS = /* @__PURE__ */ new Set([20, 21, 23, 26, 700, 701, 1700]);
8
+ var DATE_OID = 1082;
9
+ var TIMESTAMP_OIDS = /* @__PURE__ */ new Set([1114, 1184]);
10
+ var { Pool } = pg;
11
+ var PostgresConnection = class {
12
+ pool;
13
+ defaultSchema;
14
+ onClose;
15
+ constructor(options = {}) {
16
+ this.defaultSchema = options.schema || config.postgres?.schema || config.defaultNamespace || "public";
17
+ this.onClose = options.onClose;
18
+ this.pool = options.pool || new Pool({
19
+ connectionString: options.connectionString,
20
+ host: options.host,
21
+ port: options.port,
22
+ database: options.database,
23
+ user: options.user || options.username,
24
+ password: options.password,
25
+ ssl: options.ssl,
26
+ max: options.max,
27
+ idleTimeoutMillis: options.idleTimeoutMillis,
28
+ connectionTimeoutMillis: options.connectionTimeoutMillis,
29
+ query_timeout: options.queryTimeout,
30
+ statement_timeout: options.statementTimeout,
31
+ application_name: "Graphene"
32
+ });
33
+ }
34
+ async runQuery(sql, params) {
35
+ let [preparedSql, preparedParams] = preparePostgresParams(sql, params);
36
+ let result = await this.pool.query(preparedSql, preparedParams);
37
+ let rows = result.rows.map((row) => normalizeRow(row, result.fields));
38
+ return { rows, totalRows: result.rowCount ?? rows.length };
39
+ }
40
+ async listDatasets() {
41
+ let res = await this.runQuery(`
42
+ select schema_name
43
+ from information_schema.schemata
44
+ where schema_name not in ('information_schema', 'pg_catalog')
45
+ and schema_name not like 'pg_toast%'
46
+ and schema_name not like 'pg_temp%'
47
+ order by schema_name
48
+ `);
49
+ return res.rows.map((row) => String(row["schema_name"]).toLowerCase());
50
+ }
51
+ async listTables(schema = this.defaultSchema) {
52
+ let sql = `
53
+ select table_name
54
+ from information_schema.tables
55
+ where lower(table_schema) = lower($1)
56
+ and table_type in ('BASE TABLE', 'VIEW')
57
+ order by table_name
58
+ `.trim();
59
+ let res = await this.runQuery(sql, [schema]);
60
+ return res.rows.map((row) => String(row["table_name"]).toLowerCase());
61
+ }
62
+ async describeTable(target) {
63
+ let parts = target.split(".").filter(Boolean);
64
+ let table = parts.pop() || "";
65
+ let schema = parts.join(".") || this.defaultSchema;
66
+ let sql = `
67
+ select column_name, data_type, udt_name, ordinal_position
68
+ from information_schema.columns
69
+ where lower(table_schema) = lower($1)
70
+ and lower(table_name) = lower($2)
71
+ order by ordinal_position
72
+ `.trim();
73
+ let res = await this.runQuery(sql, [schema, table]);
74
+ return res.rows.map((row) => ({ name: String(row["column_name"]).toLowerCase(), dataType: postgresDisplayType(row) }));
75
+ }
76
+ async close() {
77
+ try {
78
+ await this.pool.end();
79
+ } finally {
80
+ await this.onClose?.();
81
+ }
82
+ }
83
+ };
84
+ function preparePostgresParams(sql, params) {
85
+ if (!params) return [sql, void 0];
86
+ if (Array.isArray(params)) return [sql, params];
87
+ let values = [];
88
+ let indexes = /* @__PURE__ */ new Map();
89
+ let inString = false;
90
+ let out = "";
91
+ for (let i = 0; i < sql.length; i++) {
92
+ let ch = sql[i];
93
+ if (ch == "'") {
94
+ out += ch;
95
+ if (inString && sql[i + 1] == "'") {
96
+ out += sql[++i];
97
+ continue;
98
+ }
99
+ inString = !inString;
100
+ continue;
101
+ }
102
+ let match = !inString && ch == "$" ? sql.slice(i).match(/^\$([A-Za-z_][A-Za-z0-9_]*)/) : null;
103
+ if (!match) {
104
+ out += ch;
105
+ continue;
106
+ }
107
+ let name = match[1];
108
+ if (!(name in params)) throw new Error(`Missing param $${name}`);
109
+ if (!indexes.has(name)) {
110
+ values.push(params[name]);
111
+ indexes.set(name, values.length);
112
+ }
113
+ out += `$${indexes.get(name)}`;
114
+ i += name.length;
115
+ }
116
+ return [out, values];
117
+ }
118
+ function normalizeRow(row, fields) {
119
+ let out = {};
120
+ for (let [key, value] of Object.entries(row)) {
121
+ let field = fields.find((f) => f.name == key);
122
+ out[key] = normalizeValue(value, field?.dataTypeID);
123
+ }
124
+ return out;
125
+ }
126
+ function normalizeValue(value, oid) {
127
+ if (value === null) return null;
128
+ if (typeof value === "bigint") return Number(value);
129
+ if (typeof value === "string" && oid && NUMERIC_OIDS.has(oid) && value !== "") return Number(value);
130
+ if (value instanceof Date && oid == DATE_OID) return value.toISOString().slice(0, 10);
131
+ if (value instanceof Date && oid && TIMESTAMP_OIDS.has(oid)) return value.toISOString();
132
+ if (Array.isArray(value)) return value.map((item) => normalizeValue(item));
133
+ return value;
134
+ }
135
+ function postgresDisplayType(row) {
136
+ let dataType = String(row["data_type"]);
137
+ let udtName = String(row["udt_name"] || "");
138
+ let udtAliases = { int2: "smallint", int4: "integer", int8: "bigint", float4: "real", float8: "double precision", bool: "boolean", varchar: "character varying" };
139
+ if (dataType == "ARRAY" && udtName.startsWith("_")) return `${udtAliases[udtName.slice(1)] || udtName.slice(1)}[]`;
140
+ if (dataType == "timestamp without time zone" || dataType == "timestamp with time zone") return "timestamp";
141
+ if (dataType == "USER-DEFINED" && udtName) return udtName;
142
+ return dataType;
143
+ }
144
+ export {
145
+ PostgresConnection
146
+ };
147
+ //# sourceMappingURL=postgres-NF43BPZY.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../connections/postgres.ts"],
4
+ "sourcesContent": ["import pg, {type FieldDef, type PoolConfig, type QueryResult as PgQueryResult} from 'pg'\n\nimport {config} from '../../lang/config.ts'\nimport {type QueryConnection, type QueryParams, type QueryResult, type SchemaColumn} from './types.ts'\n\nexport interface PostgresOptions {\n connectionString?: string\n host?: string\n port?: number\n database?: string\n user?: string\n username?: string\n password?: string\n schema?: string\n ssl?: PoolConfig['ssl']\n max?: number\n idleTimeoutMillis?: number\n connectionTimeoutMillis?: number\n queryTimeout?: number\n statementTimeout?: number\n pool?: PostgresPool\n onClose?: () => Promise<void>\n}\n\ninterface PostgresPool {\n query(sql: string, params?: unknown[]): Promise<PgQueryResult>\n end(): Promise<void>\n}\n\nconst NUMERIC_OIDS = new Set([20, 21, 23, 26, 700, 701, 1700])\nconst DATE_OID = 1082\nconst TIMESTAMP_OIDS = new Set([1114, 1184])\nconst {Pool} = pg\n\nexport class PostgresConnection implements QueryConnection {\n private pool: PostgresPool\n private defaultSchema: string\n private onClose?: () => Promise<void>\n\n constructor(options: PostgresOptions = {}) {\n this.defaultSchema = options.schema || config.postgres?.schema || config.defaultNamespace || 'public'\n this.onClose = options.onClose\n this.pool =\n options.pool ||\n new Pool({\n connectionString: options.connectionString,\n host: options.host,\n port: options.port,\n database: options.database,\n user: options.user || options.username,\n password: options.password,\n ssl: options.ssl,\n max: options.max,\n idleTimeoutMillis: options.idleTimeoutMillis,\n connectionTimeoutMillis: options.connectionTimeoutMillis,\n query_timeout: options.queryTimeout,\n statement_timeout: options.statementTimeout,\n application_name: 'Graphene',\n })\n }\n\n async runQuery(sql: string, params?: QueryParams): Promise<QueryResult> {\n let [preparedSql, preparedParams] = preparePostgresParams(sql, params)\n let result = await this.pool.query(preparedSql, preparedParams)\n let rows = result.rows.map(row => normalizeRow(row, result.fields))\n return {rows, totalRows: result.rowCount ?? rows.length}\n }\n\n async listDatasets(): Promise<string[]> {\n let res = await this.runQuery(`\n select schema_name\n from information_schema.schemata\n where schema_name not in ('information_schema', 'pg_catalog')\n and schema_name not like 'pg_toast%'\n and schema_name not like 'pg_temp%'\n order by schema_name\n `)\n return res.rows.map(row => String(row['schema_name']).toLowerCase())\n }\n\n async listTables(schema = this.defaultSchema): Promise<string[]> {\n let sql = `\n select table_name\n from information_schema.tables\n where lower(table_schema) = lower($1)\n and table_type in ('BASE TABLE', 'VIEW')\n order by table_name\n `.trim()\n let res = await this.runQuery(sql, [schema])\n return res.rows.map(row => String(row['table_name']).toLowerCase())\n }\n\n async describeTable(target: string): Promise<SchemaColumn[]> {\n let parts = target.split('.').filter(Boolean)\n let table = parts.pop() || ''\n let schema = parts.join('.') || this.defaultSchema\n let sql = `\n select column_name, data_type, udt_name, ordinal_position\n from information_schema.columns\n where lower(table_schema) = lower($1)\n and lower(table_name) = lower($2)\n order by ordinal_position\n `.trim()\n let res = await this.runQuery(sql, [schema, table])\n return res.rows.map(row => ({name: String(row['column_name']).toLowerCase(), dataType: postgresDisplayType(row)}))\n }\n\n async close(): Promise<void> {\n try {\n await this.pool.end()\n } finally {\n await this.onClose?.()\n }\n }\n}\n\nfunction preparePostgresParams(sql: string, params?: QueryParams): [string, unknown[] | undefined] {\n if (!params) return [sql, undefined]\n if (Array.isArray(params)) return [sql, params]\n\n let values: unknown[] = []\n let indexes = new Map<string, number>()\n let inString = false\n let out = ''\n\n for (let i = 0; i < sql.length; i++) {\n let ch = sql[i]\n if (ch == \"'\") {\n out += ch\n if (inString && sql[i + 1] == \"'\") {\n out += sql[++i]\n continue\n }\n inString = !inString\n continue\n }\n\n let match = !inString && ch == '$' ? sql.slice(i).match(/^\\$([A-Za-z_][A-Za-z0-9_]*)/) : null\n if (!match) {\n out += ch\n continue\n }\n\n let name = match[1]\n if (!(name in params)) throw new Error(`Missing param $${name}`)\n if (!indexes.has(name)) {\n values.push(params[name])\n indexes.set(name, values.length)\n }\n out += `$${indexes.get(name)}`\n i += name.length\n }\n\n return [out, values]\n}\n\nfunction normalizeRow(row: Record<string, unknown>, fields: FieldDef[]): Record<string, unknown> {\n let out: Record<string, unknown> = {}\n for (let [key, value] of Object.entries(row)) {\n let field = fields.find(f => f.name == key)\n out[key] = normalizeValue(value, field?.dataTypeID)\n }\n return out\n}\n\nfunction normalizeValue(value: unknown, oid?: number): unknown {\n if (value === null) return null\n if (typeof value === 'bigint') return Number(value)\n if (typeof value === 'string' && oid && NUMERIC_OIDS.has(oid) && value !== '') return Number(value)\n if (value instanceof Date && oid == DATE_OID) return value.toISOString().slice(0, 10)\n if (value instanceof Date && oid && TIMESTAMP_OIDS.has(oid)) return value.toISOString()\n if (Array.isArray(value)) return value.map(item => normalizeValue(item))\n return value\n}\n\nfunction postgresDisplayType(row: Record<string, unknown>) {\n let dataType = String(row['data_type'])\n let udtName = String(row['udt_name'] || '')\n let udtAliases: Record<string, string> = {int2: 'smallint', int4: 'integer', int8: 'bigint', float4: 'real', float8: 'double precision', bool: 'boolean', varchar: 'character varying'}\n if (dataType == 'ARRAY' && udtName.startsWith('_')) return `${udtAliases[udtName.slice(1)] || udtName.slice(1)}[]`\n if (dataType == 'timestamp without time zone' || dataType == 'timestamp with time zone') return 'timestamp'\n if (dataType == 'USER-DEFINED' && udtName) return udtName\n return dataType\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -6,10 +6,10 @@ import {
6
6
  runQuery,
7
7
  runVitePlugin,
8
8
  toSql
9
- } from "./chunk-TZTTALAV.js";
9
+ } from "./chunk-KYTXXLSS.js";
10
10
  import {
11
11
  config
12
- } from "./chunk-56K2FF57.js";
12
+ } from "./chunk-KW66YQ62.js";
13
13
 
14
14
  // serve2.ts
15
15
  import { svelte, vitePreprocess } from "@sveltejs/vite-plugin-svelte";
@@ -408,6 +408,10 @@ var handleRequestPlugin = {
408
408
  if (!pathName || pathName == "/") pathName = "index";
409
409
  let relativeMdPath = pathName.replace(/^\//, "") + ".md";
410
410
  let mdPath = path2.join(config.root, relativeMdPath);
411
+ if (!mockFileMap[relativeMdPath] && !await fs2.exists(mdPath)) {
412
+ relativeMdPath = pathName.replace(/^\//, "") + "/index.md";
413
+ mdPath = path2.join(config.root, relativeMdPath);
414
+ }
411
415
  if (mockFileMap[relativeMdPath] || await fs2.exists(mdPath)) {
412
416
  await handlePage(s, res);
413
417
  } else {
@@ -445,4 +449,4 @@ export {
445
449
  serve2,
446
450
  svelteWarnings
447
451
  };
448
- //# sourceMappingURL=serve2-S2LL4D4D.js.map
452
+ //# sourceMappingURL=serve2-XALOUIFB.js.map