create-graphene 0.0.16 → 0.0.17
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/dist/cli.js +229 -70
- package/package.json +5 -2
package/dist/cli.js
CHANGED
|
@@ -6,14 +6,19 @@ import * as clack from "@clack/prompts";
|
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
7
|
import { access, mkdir, readFile, readlink, readdir, symlink, writeFile } from "node:fs/promises";
|
|
8
8
|
import path2 from "node:path";
|
|
9
|
+
import { styleText } from "node:util";
|
|
9
10
|
|
|
10
11
|
// ../cli/package.json
|
|
11
12
|
var package_default = {
|
|
12
13
|
name: "@graphenedata/cli",
|
|
13
|
-
version: "0.0.
|
|
14
|
+
version: "0.0.17",
|
|
14
15
|
private: true,
|
|
15
16
|
license: "Elastic-2.0",
|
|
16
17
|
author: "Graphene Systems Inc",
|
|
18
|
+
repository: {
|
|
19
|
+
type: "git",
|
|
20
|
+
url: "git+https://github.com/graphene-data/graphene.git"
|
|
21
|
+
},
|
|
17
22
|
bin: {
|
|
18
23
|
graphene: "./bin.js"
|
|
19
24
|
},
|
|
@@ -113,7 +118,7 @@ var CreateCancelled = class extends Error {
|
|
|
113
118
|
}
|
|
114
119
|
};
|
|
115
120
|
function parseArgs(argv) {
|
|
116
|
-
let options = { yes: false, install: true, name: void 0, targetDir: void 0, help: false };
|
|
121
|
+
let options = { yes: false, install: true, skipCredentialValidation: false, name: void 0, targetDir: void 0, help: false };
|
|
117
122
|
for (let i = 0; i < argv.length; i++) {
|
|
118
123
|
let arg = argv[i];
|
|
119
124
|
if (arg === "--yes" || arg === "-y") {
|
|
@@ -124,6 +129,10 @@ function parseArgs(argv) {
|
|
|
124
129
|
options.install = false;
|
|
125
130
|
continue;
|
|
126
131
|
}
|
|
132
|
+
if (arg === "--skip-credential-validation") {
|
|
133
|
+
options.skipCredentialValidation = true;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
127
136
|
if (arg === "--help" || arg === "-h") {
|
|
128
137
|
options.help = true;
|
|
129
138
|
continue;
|
|
@@ -167,8 +176,10 @@ function renderTemplate({ answers, cliVersion }) {
|
|
|
167
176
|
if (answers.duckdbPath) graphene.duckdb = { path: answers.duckdbPath };
|
|
168
177
|
} else if (answers.database === "snowflake") {
|
|
169
178
|
graphene.snowflake = { account: answers.snowflakeAccount || "", username: answers.snowflakeUsername || "" };
|
|
170
|
-
} else {
|
|
179
|
+
} else if (answers.database === "bigquery") {
|
|
171
180
|
graphene.bigquery = { projectId: answers.bigqueryProjectId || "" };
|
|
181
|
+
} else {
|
|
182
|
+
graphene.clickhouse = { url: answers.clickhouseUrl || "", username: answers.clickhouseUsername || "" };
|
|
172
183
|
}
|
|
173
184
|
let pkg = {
|
|
174
185
|
name: answers.projectName,
|
|
@@ -191,7 +202,7 @@ function renderTemplate({ answers, cliVersion }) {
|
|
|
191
202
|
let files = {
|
|
192
203
|
"package.json": JSON.stringify(pkg, null, 2) + "\n",
|
|
193
204
|
".gitignore": ["node_modules", ".env", "*.duckdb"].join("\n") + "\n",
|
|
194
|
-
|
|
205
|
+
[agentsFileName(answers.skillLinkTarget)]: renderAgents(answers),
|
|
195
206
|
"index.md": renderIndex(answers)
|
|
196
207
|
};
|
|
197
208
|
if (answers.packageManager?.name === "yarn") files[".yarnrc.yml"] = "nodeLinker: node-modules\n";
|
|
@@ -205,6 +216,10 @@ function grapheneCommand(packageManager, args) {
|
|
|
205
216
|
if (packageManager?.name === "bun") return `bun run graphene ${args}`;
|
|
206
217
|
return `npx graphene ${args}`;
|
|
207
218
|
}
|
|
219
|
+
function agentsFileName(skillLinkTarget) {
|
|
220
|
+
if (skillLinkTarget === ".claude") return "CLAUDE.md";
|
|
221
|
+
return "AGENTS.md";
|
|
222
|
+
}
|
|
208
223
|
function renderAgents(answers) {
|
|
209
224
|
return [
|
|
210
225
|
"## Graphene Reference",
|
|
@@ -221,6 +236,7 @@ function renderAgents(answers) {
|
|
|
221
236
|
function databaseLabel(database) {
|
|
222
237
|
if (database === "snowflake") return "Snowflake";
|
|
223
238
|
if (database === "bigquery") return "BigQuery";
|
|
239
|
+
if (database === "clickhouse") return "ClickHouse";
|
|
224
240
|
return "DuckDB";
|
|
225
241
|
}
|
|
226
242
|
function renderIndex(answers) {
|
|
@@ -233,6 +249,8 @@ function renderEnvFile(answers) {
|
|
|
233
249
|
if (answers.snowflakePassphrase) lines.push(`SNOWFLAKE_PRI_PASSPHRASE=${answers.snowflakePassphrase}`);
|
|
234
250
|
} else if (answers.database === "bigquery") {
|
|
235
251
|
lines.push(`GOOGLE_APPLICATION_CREDENTIALS=${answers.bigqueryKeyPath || ""}`);
|
|
252
|
+
} else if (answers.database === "clickhouse") {
|
|
253
|
+
lines.push(`CLICKHOUSE_PASSWORD=${answers.clickhousePassword || ""}`);
|
|
236
254
|
}
|
|
237
255
|
return lines.length ? lines.join("\n") + "\n" : null;
|
|
238
256
|
}
|
|
@@ -258,9 +276,10 @@ function printHelp(stdout) {
|
|
|
258
276
|
"Usage: npm create graphene [target-dir] [-- --yes] [--name <project-name>] [--no-install]",
|
|
259
277
|
"",
|
|
260
278
|
"Options:",
|
|
261
|
-
" -y, --yes
|
|
262
|
-
" --name <name>
|
|
263
|
-
" --no-install
|
|
279
|
+
" -y, --yes Skip prompts and accept defaults",
|
|
280
|
+
" --name <name> Set the generated package name",
|
|
281
|
+
" --no-install Skip dependency installation",
|
|
282
|
+
" --skip-credential-validation Skip warehouse credential validation"
|
|
264
283
|
].join("\n") + "\n"
|
|
265
284
|
);
|
|
266
285
|
}
|
|
@@ -280,11 +299,18 @@ function validateFileExtension(filePath, expectedExtension) {
|
|
|
280
299
|
if (typeof filePath !== "string" || !filePath.trim()) return `Path to ${expectedExtension} file is required`;
|
|
281
300
|
if (!filePath.endsWith(expectedExtension)) return `File must end with ${expectedExtension}`;
|
|
282
301
|
}
|
|
283
|
-
async function promptExistingFilePath({
|
|
302
|
+
async function promptExistingFilePath({
|
|
303
|
+
message,
|
|
304
|
+
expectedExtension,
|
|
305
|
+
initialValue,
|
|
306
|
+
input,
|
|
307
|
+
output
|
|
308
|
+
}) {
|
|
284
309
|
while (true) {
|
|
285
310
|
let filePath = unwrapPrompt(
|
|
286
311
|
await clack.path({
|
|
287
312
|
message,
|
|
313
|
+
initialValue,
|
|
288
314
|
validate: (value) => validateFileExtension(value, expectedExtension),
|
|
289
315
|
...promptOptions(input, output)
|
|
290
316
|
})
|
|
@@ -297,14 +323,10 @@ async function promptExistingFilePath({ message, expectedExtension, input, outpu
|
|
|
297
323
|
}
|
|
298
324
|
}
|
|
299
325
|
}
|
|
300
|
-
function namespacePlaceholder(database) {
|
|
301
|
-
if (database === "snowflake") return "MY_DB.ANALYTICS";
|
|
302
|
-
if (database === "bigquery") return "my-project.analytics";
|
|
303
|
-
return "analytics";
|
|
304
|
-
}
|
|
305
326
|
function getWarehouseClient(database) {
|
|
306
327
|
if (database === "snowflake") return "snowflake-sdk";
|
|
307
328
|
if (database === "bigquery") return "@google-cloud/bigquery";
|
|
329
|
+
if (database === "clickhouse") return "@clickhouse/client";
|
|
308
330
|
return "@duckdb/node-api";
|
|
309
331
|
}
|
|
310
332
|
function getWarehouseClientVersion(packageName) {
|
|
@@ -312,6 +334,175 @@ function getWarehouseClientVersion(packageName) {
|
|
|
312
334
|
if (!version) throw new Error(`Missing ${packageName} peerDependency in cli/package.json`);
|
|
313
335
|
return version;
|
|
314
336
|
}
|
|
337
|
+
async function promptWarehouseCredentials(answers, input, output) {
|
|
338
|
+
if (answers.database === "snowflake") {
|
|
339
|
+
answers.snowflakeAccount = unwrapPrompt(
|
|
340
|
+
await clack.text({
|
|
341
|
+
message: "Snowflake account ID",
|
|
342
|
+
placeholder: "myorg-myaccount",
|
|
343
|
+
initialValue: answers.snowflakeAccount,
|
|
344
|
+
validate: validateRequired("Snowflake account ID is required"),
|
|
345
|
+
...promptOptions(input, output)
|
|
346
|
+
})
|
|
347
|
+
);
|
|
348
|
+
answers.snowflakeUsername = unwrapPrompt(
|
|
349
|
+
await clack.text({
|
|
350
|
+
message: "Snowflake username",
|
|
351
|
+
placeholder: "graphene_user",
|
|
352
|
+
initialValue: answers.snowflakeUsername,
|
|
353
|
+
validate: validateRequired("Snowflake username is required"),
|
|
354
|
+
...promptOptions(input, output)
|
|
355
|
+
})
|
|
356
|
+
);
|
|
357
|
+
answers.snowflakeKeyPath = await promptExistingFilePath({ message: "Path to .p8 key file", expectedExtension: ".p8", initialValue: answers.snowflakeKeyPath, input, output });
|
|
358
|
+
answers.snowflakePassphrase = unwrapPrompt(await clack.password({ message: "Key passphrase", ...promptOptions(input, output) }));
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (answers.database === "bigquery") {
|
|
362
|
+
answers.bigqueryProjectId = unwrapPrompt(
|
|
363
|
+
await clack.text({
|
|
364
|
+
message: "GCP project ID",
|
|
365
|
+
placeholder: "my-project-123",
|
|
366
|
+
initialValue: answers.bigqueryProjectId,
|
|
367
|
+
validate: validateRequired("GCP project ID is required"),
|
|
368
|
+
...promptOptions(input, output)
|
|
369
|
+
})
|
|
370
|
+
);
|
|
371
|
+
answers.bigqueryKeyPath = await promptExistingFilePath({
|
|
372
|
+
message: "Path to service account .json key file",
|
|
373
|
+
expectedExtension: ".json",
|
|
374
|
+
initialValue: answers.bigqueryKeyPath,
|
|
375
|
+
input,
|
|
376
|
+
output
|
|
377
|
+
});
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
if (answers.database === "clickhouse") {
|
|
381
|
+
answers.clickhouseUrl = unwrapPrompt(
|
|
382
|
+
await clack.text({
|
|
383
|
+
message: "ClickHouse URL",
|
|
384
|
+
placeholder: "https://example.clickhouse.cloud:8443",
|
|
385
|
+
initialValue: answers.clickhouseUrl,
|
|
386
|
+
validate: validateRequired("ClickHouse URL is required"),
|
|
387
|
+
...promptOptions(input, output)
|
|
388
|
+
})
|
|
389
|
+
);
|
|
390
|
+
answers.clickhouseUsername = unwrapPrompt(
|
|
391
|
+
await clack.text({
|
|
392
|
+
message: "ClickHouse username",
|
|
393
|
+
placeholder: "default",
|
|
394
|
+
initialValue: answers.clickhouseUsername,
|
|
395
|
+
validate: validateRequired("ClickHouse username is required"),
|
|
396
|
+
...promptOptions(input, output)
|
|
397
|
+
})
|
|
398
|
+
);
|
|
399
|
+
answers.clickhousePassword = unwrapPrompt(
|
|
400
|
+
await clack.password({
|
|
401
|
+
message: "ClickHouse password",
|
|
402
|
+
validate: validateRequired("ClickHouse password is required"),
|
|
403
|
+
...promptOptions(input, output)
|
|
404
|
+
})
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
async function collectWarehouseCredentials(answers, options, input, output) {
|
|
409
|
+
while (true) {
|
|
410
|
+
await promptWarehouseCredentials(answers, input, output);
|
|
411
|
+
if (options.skipCredentialValidation) return;
|
|
412
|
+
let result = await testWarehouseCredentials(answers, output);
|
|
413
|
+
if (result.ok) return;
|
|
414
|
+
clack.log.error(`${databaseLabel(answers.database)} credential validation failed: ${result.error}`, { output });
|
|
415
|
+
let action = unwrapPrompt(
|
|
416
|
+
await clack.select({
|
|
417
|
+
message: "How would you like to continue?",
|
|
418
|
+
options: [
|
|
419
|
+
{ value: "edit", label: "Edit credentials" },
|
|
420
|
+
{ value: "continue", label: "Continue anyway" }
|
|
421
|
+
],
|
|
422
|
+
...promptOptions(input, output)
|
|
423
|
+
})
|
|
424
|
+
);
|
|
425
|
+
if (action === "continue") return;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
async function testWarehouseCredentials(answers, output) {
|
|
429
|
+
let task = clack.taskLog({ title: `Testing ${databaseLabel(answers.database)} credentials...`, retainLog: true, output });
|
|
430
|
+
try {
|
|
431
|
+
await withTimeout(runWarehouseCredentialTest(answers), 15e3, `${databaseLabel(answers.database)} credential validation timed out`);
|
|
432
|
+
task.success("Credentials validated");
|
|
433
|
+
return { ok: true };
|
|
434
|
+
} catch (err) {
|
|
435
|
+
task.error("Credential validation failed", { showLog: true });
|
|
436
|
+
return { ok: false, error: formatCredentialError(err) };
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
async function withTimeout(promise, ms, message) {
|
|
440
|
+
let timeout;
|
|
441
|
+
try {
|
|
442
|
+
return await Promise.race([
|
|
443
|
+
promise,
|
|
444
|
+
new Promise((_resolve, reject) => {
|
|
445
|
+
timeout = setTimeout(() => reject(new Error(message)), ms);
|
|
446
|
+
})
|
|
447
|
+
]);
|
|
448
|
+
} finally {
|
|
449
|
+
if (timeout) clearTimeout(timeout);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function runWarehouseCredentialTest(answers) {
|
|
453
|
+
if (answers.database === "snowflake") return testSnowflakeCredentials(answers);
|
|
454
|
+
if (answers.database === "bigquery") return testBigQueryCredentials(answers);
|
|
455
|
+
if (answers.database === "clickhouse") return testClickHouseCredentials(answers);
|
|
456
|
+
return Promise.resolve();
|
|
457
|
+
}
|
|
458
|
+
async function testSnowflakeCredentials(answers) {
|
|
459
|
+
let snowflake = (await import("snowflake-sdk")).default;
|
|
460
|
+
snowflake.configure({ logLevel: "WARN", logFilePath: "/dev/null" });
|
|
461
|
+
let connection = snowflake.createConnection({
|
|
462
|
+
account: answers.snowflakeAccount,
|
|
463
|
+
username: answers.snowflakeUsername,
|
|
464
|
+
privateKeyPath: answers.snowflakeKeyPath,
|
|
465
|
+
privateKeyPass: answers.snowflakePassphrase,
|
|
466
|
+
authenticator: "SNOWFLAKE_JWT",
|
|
467
|
+
application: "Graphene"
|
|
468
|
+
});
|
|
469
|
+
try {
|
|
470
|
+
await new Promise((resolve, reject) => {
|
|
471
|
+
connection.connect((err) => err ? reject(err) : resolve());
|
|
472
|
+
});
|
|
473
|
+
} finally {
|
|
474
|
+
await new Promise((resolve) => {
|
|
475
|
+
connection.destroy(() => resolve());
|
|
476
|
+
}).catch(() => {
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async function testBigQueryCredentials(answers) {
|
|
481
|
+
let { BigQuery } = await import("@google-cloud/bigquery");
|
|
482
|
+
let credentials = JSON.parse(await readFile(answers.bigqueryKeyPath || "", "utf8"));
|
|
483
|
+
let client = new BigQuery({ projectId: answers.bigqueryProjectId, credentials, userAgent: "Graphene" });
|
|
484
|
+
await client.createQueryJob({ query: "select 1", useLegacySql: false, dryRun: true });
|
|
485
|
+
}
|
|
486
|
+
async function testClickHouseCredentials(answers) {
|
|
487
|
+
let { createClient } = await import("@clickhouse/client");
|
|
488
|
+
let client = createClient({
|
|
489
|
+
url: answers.clickhouseUrl,
|
|
490
|
+
username: answers.clickhouseUsername,
|
|
491
|
+
password: answers.clickhousePassword,
|
|
492
|
+
database: answers.defaultNamespace || "default",
|
|
493
|
+
application: "Graphene"
|
|
494
|
+
});
|
|
495
|
+
try {
|
|
496
|
+
let result = await client.query({ query: "SELECT 1", format: "JSONEachRow" });
|
|
497
|
+
await result.json();
|
|
498
|
+
} finally {
|
|
499
|
+
await client.close();
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
function formatCredentialError(err) {
|
|
503
|
+
if (err instanceof Error && err.message) return err.message;
|
|
504
|
+
return String(err || "Unknown error");
|
|
505
|
+
}
|
|
315
506
|
async function collectAnswers({ options, packageManager, input, output }) {
|
|
316
507
|
if (options.yes) {
|
|
317
508
|
let targetDir2 = options.targetDir || "graphene-app";
|
|
@@ -340,74 +531,23 @@ async function collectAnswers({ options, packageManager, input, output }) {
|
|
|
340
531
|
await clack.select({
|
|
341
532
|
message: "Database",
|
|
342
533
|
options: [
|
|
343
|
-
{ value: "duckdb", label: "DuckDB (local file)" },
|
|
344
534
|
{ value: "snowflake", label: "Snowflake" },
|
|
345
|
-
{ value: "bigquery", label: "BigQuery" }
|
|
535
|
+
{ value: "bigquery", label: "BigQuery" },
|
|
536
|
+
{ value: "clickhouse", label: "ClickHouse" },
|
|
537
|
+
{ value: "duckdb", label: "DuckDB (local file)" }
|
|
346
538
|
],
|
|
347
539
|
...promptOptions(input, output)
|
|
348
540
|
})
|
|
349
541
|
);
|
|
350
|
-
let defaultNamespace = unwrapPrompt(
|
|
351
|
-
await clack.text({
|
|
352
|
-
message: "Default namespace (optional)",
|
|
353
|
-
placeholder: namespacePlaceholder(database),
|
|
354
|
-
...promptOptions(input, output)
|
|
355
|
-
})
|
|
356
|
-
).trim();
|
|
357
542
|
let answers = {
|
|
358
543
|
targetDir,
|
|
359
544
|
projectName,
|
|
360
545
|
packageManager,
|
|
361
546
|
database,
|
|
362
|
-
defaultNamespace: defaultNamespace || void 0,
|
|
363
547
|
skillLinkTarget: "none"
|
|
364
548
|
};
|
|
365
|
-
if (database
|
|
366
|
-
answers
|
|
367
|
-
await clack.text({
|
|
368
|
-
message: "Path to .duckdb file",
|
|
369
|
-
placeholder: "./data.duckdb",
|
|
370
|
-
validate(value) {
|
|
371
|
-
if (typeof value !== "string" || !value.trim()) return;
|
|
372
|
-
if (!value.endsWith(".duckdb")) return "DuckDB path must end with .duckdb";
|
|
373
|
-
},
|
|
374
|
-
...promptOptions(input, output)
|
|
375
|
-
})
|
|
376
|
-
).trim() || void 0;
|
|
377
|
-
} else if (database === "snowflake") {
|
|
378
|
-
answers.snowflakeAccount = unwrapPrompt(
|
|
379
|
-
await clack.text({
|
|
380
|
-
message: "Snowflake account ID",
|
|
381
|
-
placeholder: "myorg-myaccount",
|
|
382
|
-
validate: validateRequired("Snowflake account ID is required"),
|
|
383
|
-
...promptOptions(input, output)
|
|
384
|
-
})
|
|
385
|
-
);
|
|
386
|
-
answers.snowflakeUsername = unwrapPrompt(
|
|
387
|
-
await clack.text({
|
|
388
|
-
message: "Snowflake username",
|
|
389
|
-
placeholder: "graphene_user",
|
|
390
|
-
validate: validateRequired("Snowflake username is required"),
|
|
391
|
-
...promptOptions(input, output)
|
|
392
|
-
})
|
|
393
|
-
);
|
|
394
|
-
answers.snowflakeKeyPath = await promptExistingFilePath({ message: "Path to .p8 key file", expectedExtension: ".p8", input, output });
|
|
395
|
-
answers.snowflakePassphrase = unwrapPrompt(
|
|
396
|
-
await clack.password({
|
|
397
|
-
message: "Key passphrase",
|
|
398
|
-
...promptOptions(input, output)
|
|
399
|
-
})
|
|
400
|
-
);
|
|
401
|
-
} else {
|
|
402
|
-
answers.bigqueryProjectId = unwrapPrompt(
|
|
403
|
-
await clack.text({
|
|
404
|
-
message: "GCP project ID",
|
|
405
|
-
placeholder: "my-project-123",
|
|
406
|
-
validate: validateRequired("GCP project ID is required"),
|
|
407
|
-
...promptOptions(input, output)
|
|
408
|
-
})
|
|
409
|
-
);
|
|
410
|
-
answers.bigqueryKeyPath = await promptExistingFilePath({ message: "Path to service account .json key file", expectedExtension: ".json", input, output });
|
|
549
|
+
if (database !== "duckdb") {
|
|
550
|
+
await collectWarehouseCredentials(answers, options, input, output);
|
|
411
551
|
}
|
|
412
552
|
if (options.install) {
|
|
413
553
|
answers.skillLinkTarget = unwrapPrompt(
|
|
@@ -505,7 +645,7 @@ async function runCreate({ argv, cwd, env = {}, stdin, stdout }) {
|
|
|
505
645
|
if (install.code !== 0) throw new Error(install.stderr.trim() || `${packageManager.name} install failed with code ${install.code}`);
|
|
506
646
|
await symlinkGrapheneSkill(targetDir, answers.skillLinkTarget);
|
|
507
647
|
}
|
|
508
|
-
clack.outro(
|
|
648
|
+
clack.outro(completionMessage(answers), { output: stdout });
|
|
509
649
|
} catch (err) {
|
|
510
650
|
if (err instanceof CreateCancelled) {
|
|
511
651
|
clack.cancel("Operation cancelled.", { output: stdout });
|
|
@@ -514,6 +654,25 @@ async function runCreate({ argv, cwd, env = {}, stdin, stdout }) {
|
|
|
514
654
|
throw err;
|
|
515
655
|
}
|
|
516
656
|
}
|
|
657
|
+
function completionMessage(answers) {
|
|
658
|
+
if (answers.database !== "duckdb") return "Done!";
|
|
659
|
+
return [
|
|
660
|
+
"Done!",
|
|
661
|
+
"",
|
|
662
|
+
`For DuckDB, copy your ${color("cyan", ".duckdb")} file into the ${color("magenta", answers.projectName)} folder so Graphene can discover it.`,
|
|
663
|
+
"",
|
|
664
|
+
`If the duckdb file lives elsewhere, set the path in ${color("magenta", "package.json")}:`,
|
|
665
|
+
"",
|
|
666
|
+
color("gray", '"graphene": {'),
|
|
667
|
+
color("gray", ' "duckdb": {'),
|
|
668
|
+
color("gray", ' "path": "/path/to/example.duckdb"'),
|
|
669
|
+
color("gray", " }"),
|
|
670
|
+
color("gray", "}")
|
|
671
|
+
].join("\n");
|
|
672
|
+
}
|
|
673
|
+
function color(style, text2) {
|
|
674
|
+
return styleText(style, text2, { validateStream: false });
|
|
675
|
+
}
|
|
517
676
|
|
|
518
677
|
// cli.ts
|
|
519
678
|
await runCreate({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-graphene",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"author": "Graphene Systems Inc",
|
|
6
6
|
"repository": {
|
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
"prepack": "pnpm run build"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@clack/prompts": "^1.2.0"
|
|
28
|
+
"@clack/prompts": "^1.2.0",
|
|
29
|
+
"@clickhouse/client": "^1.18.2",
|
|
30
|
+
"@google-cloud/bigquery": "^8.2.0",
|
|
31
|
+
"snowflake-sdk": "2.4.0"
|
|
29
32
|
},
|
|
30
33
|
"devDependencies": {
|
|
31
34
|
"esbuild": "^0.27.2"
|