@graphenedata/cli 0.0.18 → 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 (34) hide show
  1. package/README.md +3 -1
  2. package/dist/cli/athena-WROJBSLV.js +136 -0
  3. package/dist/cli/athena-WROJBSLV.js.map +7 -0
  4. package/dist/cli/{bigQuery-YIWXZPY6.js → bigQuery-3A7HPXZS.js} +2 -2
  5. package/dist/cli/{chunk-SQVXTHE5.js → chunk-KW66YQ62.js} +3 -1
  6. package/dist/cli/chunk-KW66YQ62.js.map +7 -0
  7. package/dist/cli/{chunk-UTV3ERGI.js → chunk-KYTXXLSS.js} +5219 -4592
  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-V6PJEA7H.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-CGQSM7TD.js → serve2-XALOUIFB.js} +7 -3
  18. package/dist/cli/{serve2-CGQSM7TD.js.map → serve2-XALOUIFB.js.map} +2 -2
  19. package/dist/cli/{snowflake-HVSTYBLB.js → snowflake-GX4FSSWT.js} +2 -2
  20. package/dist/skills/graphene/SKILL.md +16 -9
  21. package/dist/skills/graphene/references/dropdown.md +12 -0
  22. package/dist/ui/component-utilities/enrich.ts +26 -22
  23. package/dist/ui/components/AreaChart.svelte +3 -2
  24. package/dist/ui/components/BarChart.svelte +4 -3
  25. package/dist/ui/components/LineChart.svelte +3 -2
  26. package/dist/ui/components/ScatterPlot.svelte +4 -3
  27. package/dist/ui/components/_Table.svelte +3 -1
  28. package/dist/ui/internal/LocalApp.svelte +5 -1
  29. package/package.json +13 -4
  30. package/dist/cli/chunk-SQVXTHE5.js.map +0 -7
  31. package/dist/cli/chunk-UTV3ERGI.js.map +0 -7
  32. /package/dist/cli/{bigQuery-YIWXZPY6.js.map → bigQuery-3A7HPXZS.js.map} +0 -0
  33. /package/dist/cli/{duckdb-V6PJEA7H.js.map → duckdb-YOIX6QOQ.js.map} +0 -0
  34. /package/dist/cli/{snowflake-HVSTYBLB.js.map → snowflake-GX4FSSWT.js.map} +0 -0
package/README.md CHANGED
@@ -74,7 +74,7 @@ GSQL is inspired by [Malloy](https://github.com/malloydata/malloy), from the cre
74
74
  - [Try the demo project](https://github.com/graphene-data/example-flights)
75
75
  - [Create a new Graphene project](/docs/setup.md)
76
76
 
77
- Graphene currently supports Snowflake, BigQuery, ClickHouse, and local data (via DuckDB) as data sources. It is easy for us to add more - just ask.
77
+ Graphene currently supports Snowflake, BigQuery, ClickHouse, Postgres, and local data (via DuckDB) as data sources. It is easy for us to add more - just ask.
78
78
 
79
79
  Once your project is set up, simply start the dev server via `npm exec graphene serve` (or `pnpm graphene serve`, etc. based on your package manager) and then prompt your coding agent to do analytics work: answer a data question, build a dashboard, edit the model, etc.
80
80
 
@@ -84,6 +84,8 @@ Graphene itself is a CLI which can be installed via npm (or pnpm, yarn, etc.). T
84
84
 
85
85
  A Graphene project can either be a standalone repo or a directory within a larger codebase (such as dbt). It is comprised of _semantic models_ via .gsql files and _pages_ via .md files.
86
86
 
87
+ <img alt="Architecture Diagram" src="./assets/marketecture.png"/>
88
+
87
89
  ### GSQL and Graphene markdown
88
90
 
89
91
  Semantic models are defined like so:
@@ -0,0 +1,136 @@
1
+ // connections/athena.ts
2
+ import {
3
+ AthenaClient,
4
+ GetQueryExecutionCommand,
5
+ GetQueryResultsCommand,
6
+ GetTableMetadataCommand,
7
+ ListDatabasesCommand,
8
+ ListTableMetadataCommand,
9
+ StartQueryExecutionCommand
10
+ } from "@aws-sdk/client-athena";
11
+ var AthenaConnection = class {
12
+ client;
13
+ catalog;
14
+ database;
15
+ workGroup;
16
+ outputLocation;
17
+ constructor(opts = {}) {
18
+ if (!opts.region) throw new Error("Athena requires a region in config or AWS_REGION");
19
+ let clientConfig = { region: opts.region };
20
+ if (opts.accessKeyId && opts.secretAccessKey) clientConfig.credentials = { accessKeyId: opts.accessKeyId, secretAccessKey: opts.secretAccessKey, sessionToken: opts.sessionToken };
21
+ this.client = new AthenaClient(clientConfig);
22
+ this.catalog = opts.catalog || "AwsDataCatalog";
23
+ this.database = opts.database;
24
+ this.workGroup = opts.workGroup;
25
+ this.outputLocation = opts.outputLocation;
26
+ }
27
+ async runQuery(sql, params) {
28
+ let queryExecutionId = await this.startQuery(sql, params);
29
+ await this.waitForQuery(queryExecutionId);
30
+ return await this.fetchResults(queryExecutionId);
31
+ }
32
+ async listDatasets() {
33
+ let databases = [];
34
+ let nextToken;
35
+ while (true) {
36
+ let res = await this.client.send(new ListDatabasesCommand({ CatalogName: this.catalog, NextToken: nextToken }));
37
+ databases.push(...(res.DatabaseList || []).map((db) => String(db.Name).toLowerCase()));
38
+ if (!res.NextToken) return databases;
39
+ nextToken = res.NextToken;
40
+ }
41
+ }
42
+ async listTables(database = this.database) {
43
+ if (!database) throw new Error("Athena requires a database");
44
+ let resolvedDatabase = await this.resolveDatabaseName(database);
45
+ let tables = [];
46
+ let nextToken;
47
+ while (true) {
48
+ let res = await this.client.send(new ListTableMetadataCommand({ CatalogName: this.catalog, DatabaseName: resolvedDatabase, NextToken: nextToken }));
49
+ let validTypes = /* @__PURE__ */ new Set(["EXTERNAL_TABLE", "VIRTUAL_VIEW"]);
50
+ tables.push(...(res.TableMetadataList || []).filter((t) => validTypes.has(String(t.TableType))).map((t) => `${resolvedDatabase}.${String(t.Name).toLowerCase()}`));
51
+ if (!res.NextToken) return tables;
52
+ nextToken = res.NextToken;
53
+ }
54
+ }
55
+ async describeTable(target) {
56
+ let parts = target.split(".").filter(Boolean);
57
+ let table = parts.pop() || "";
58
+ let database = parts.join(".") || this.database;
59
+ if (!database) throw new Error("No Athena database specified and no default namespace configured");
60
+ let resolvedDatabase = await this.resolveDatabaseName(database);
61
+ let res = await this.client.send(new GetTableMetadataCommand({ CatalogName: this.catalog, DatabaseName: resolvedDatabase, TableName: table }));
62
+ return (res.TableMetadata?.Columns || []).map((col) => ({ name: String(col.Name).toLowerCase(), dataType: String(col.Type) }));
63
+ }
64
+ close() {
65
+ this.client.destroy();
66
+ return Promise.resolve();
67
+ }
68
+ async startQuery(sql, params) {
69
+ if (params && !Array.isArray(params)) throw new Error("Athena only supports positional query parameters");
70
+ let res = await this.client.send(
71
+ new StartQueryExecutionCommand({
72
+ QueryString: sql,
73
+ QueryExecutionContext: { Catalog: this.catalog, Database: this.database },
74
+ WorkGroup: this.workGroup,
75
+ ResultConfiguration: this.outputLocation ? { OutputLocation: this.outputLocation } : void 0,
76
+ ExecutionParameters: params?.map(renderAthenaParameter)
77
+ })
78
+ );
79
+ if (!res.QueryExecutionId) throw new Error("Athena did not return a query execution id");
80
+ return res.QueryExecutionId;
81
+ }
82
+ async waitForQuery(queryExecutionId) {
83
+ let started = Date.now();
84
+ let timeoutMs = 5 * 60 * 1e3;
85
+ while (Date.now() - started < timeoutMs) {
86
+ let res = await this.client.send(new GetQueryExecutionCommand({ QueryExecutionId: queryExecutionId }));
87
+ let status = res.QueryExecution?.Status;
88
+ if (status?.State == "SUCCEEDED") return;
89
+ if (status?.State == "FAILED" || status?.State == "CANCELLED") throw new Error(`Athena query ${status.State.toLowerCase()}: ${status.StateChangeReason || "unknown reason"}`);
90
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
91
+ }
92
+ throw new Error(`Athena query timed out after ${Math.round(timeoutMs / 1e3)}s`);
93
+ }
94
+ async fetchResults(queryExecutionId) {
95
+ let rows = [];
96
+ let nextToken;
97
+ let firstPage = true;
98
+ while (true) {
99
+ let res = await this.client.send(new GetQueryResultsCommand({ QueryExecutionId: queryExecutionId, NextToken: nextToken, MaxResults: 1e3 }));
100
+ let columns = res.ResultSet?.ResultSetMetadata?.ColumnInfo || [];
101
+ let resultRows = firstPage ? (res.ResultSet?.Rows || []).slice(1) : res.ResultSet?.Rows || [];
102
+ for (let row of resultRows) {
103
+ let out = {};
104
+ columns.forEach((column, idx) => {
105
+ let value = row.Data?.[idx]?.VarCharValue;
106
+ out[String(column.Name).toLowerCase()] = parseAthenaValue(value, String(column.Type || ""));
107
+ });
108
+ rows.push(out);
109
+ }
110
+ firstPage = false;
111
+ if (!res.NextToken || rows.length >= 1e4) return { rows, totalRows: rows.length };
112
+ nextToken = res.NextToken;
113
+ }
114
+ }
115
+ async resolveDatabaseName(name) {
116
+ let databases = await this.listDatasets();
117
+ return databases.find((db) => db.toLowerCase() == name.toLowerCase()) || name;
118
+ }
119
+ };
120
+ function renderAthenaParameter(value) {
121
+ if (value === null || value === void 0) return "NULL";
122
+ if (typeof value == "number" || typeof value == "bigint") return String(value);
123
+ if (typeof value == "boolean") return value ? "true" : "false";
124
+ return `'${String(value).replace(/'/g, "''")}'`;
125
+ }
126
+ function parseAthenaValue(value, type) {
127
+ if (value === void 0) return null;
128
+ let normalizedType = type.toLowerCase();
129
+ if (normalizedType == "boolean") return value == "true";
130
+ if (/^(tinyint|smallint|integer|bigint|real|float|double|decimal)/.test(normalizedType)) return Number(value);
131
+ return value;
132
+ }
133
+ export {
134
+ AthenaConnection
135
+ };
136
+ //# sourceMappingURL=athena-WROJBSLV.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../connections/athena.ts"],
4
+ "sourcesContent": ["import {\n AthenaClient,\n GetQueryExecutionCommand,\n GetQueryResultsCommand,\n GetTableMetadataCommand,\n ListDatabasesCommand,\n ListTableMetadataCommand,\n StartQueryExecutionCommand,\n} from '@aws-sdk/client-athena'\n\nimport {type QueryConnection, type QueryParams, type QueryResult, type SchemaColumn} from './types.ts'\n\nexport interface AthenaOptions {\n region?: string\n catalog?: string\n database?: string\n workGroup?: string\n outputLocation?: string\n accessKeyId?: string\n secretAccessKey?: string\n sessionToken?: string\n}\n\n// Athena is serverless SQL over external data, usually S3 files registered in Glue.\n// Query execution is asynchronous: StartQueryExecution writes results to S3, then\n// GetQueryResults pages those materialized rows back through the Athena API.\nexport class AthenaConnection implements QueryConnection {\n private client: AthenaClient\n private catalog: string\n private database?: string\n private workGroup?: string\n private outputLocation?: string\n\n constructor(opts: AthenaOptions = {}) {\n if (!opts.region) throw new Error('Athena requires a region in config or AWS_REGION')\n\n let clientConfig: any = {region: opts.region}\n if (opts.accessKeyId && opts.secretAccessKey) clientConfig.credentials = {accessKeyId: opts.accessKeyId, secretAccessKey: opts.secretAccessKey, sessionToken: opts.sessionToken}\n\n this.client = new AthenaClient(clientConfig)\n this.catalog = opts.catalog || 'AwsDataCatalog'\n this.database = opts.database\n this.workGroup = opts.workGroup\n this.outputLocation = opts.outputLocation\n }\n\n async runQuery(sql: string, params?: QueryParams): Promise<QueryResult> {\n let queryExecutionId = await this.startQuery(sql, params)\n await this.waitForQuery(queryExecutionId)\n return await this.fetchResults(queryExecutionId)\n }\n\n async listDatasets(): Promise<string[]> {\n let databases: string[] = []\n let nextToken: string | undefined\n while (true) {\n let res = await this.client.send(new ListDatabasesCommand({CatalogName: this.catalog, NextToken: nextToken}))\n databases.push(...(res.DatabaseList || []).map(db => String(db.Name).toLowerCase()))\n if (!res.NextToken) return databases\n nextToken = res.NextToken\n }\n }\n\n async listTables(database = this.database): Promise<string[]> {\n if (!database) throw new Error('Athena requires a database')\n let resolvedDatabase = await this.resolveDatabaseName(database)\n let tables: string[] = []\n let nextToken: string | undefined\n while (true) {\n let res = await this.client.send(new ListTableMetadataCommand({CatalogName: this.catalog, DatabaseName: resolvedDatabase, NextToken: nextToken}))\n let validTypes = new Set(['EXTERNAL_TABLE', 'VIRTUAL_VIEW'])\n tables.push(...(res.TableMetadataList || []).filter(t => validTypes.has(String(t.TableType))).map(t => `${resolvedDatabase}.${String(t.Name).toLowerCase()}`))\n if (!res.NextToken) return tables\n nextToken = res.NextToken\n }\n }\n\n async describeTable(target: string): Promise<SchemaColumn[]> {\n let parts = target.split('.').filter(Boolean)\n let table = parts.pop() || ''\n let database = parts.join('.') || this.database\n if (!database) throw new Error('No Athena database specified and no default namespace configured')\n let resolvedDatabase = await this.resolveDatabaseName(database)\n let res = await this.client.send(new GetTableMetadataCommand({CatalogName: this.catalog, DatabaseName: resolvedDatabase, TableName: table}))\n return (res.TableMetadata?.Columns || []).map(col => ({name: String(col.Name).toLowerCase(), dataType: String(col.Type)}))\n }\n\n close(): Promise<void> {\n this.client.destroy()\n return Promise.resolve()\n }\n\n private async startQuery(sql: string, params?: QueryParams) {\n // Athena execution parameters are positional only and are rendered as SQL literals by the API.\n // Named params would be misleading, because Athena cannot bind them by name.\n if (params && !Array.isArray(params)) throw new Error('Athena only supports positional query parameters')\n let res = await this.client.send(\n new StartQueryExecutionCommand({\n QueryString: sql,\n QueryExecutionContext: {Catalog: this.catalog, Database: this.database},\n WorkGroup: this.workGroup,\n ResultConfiguration: this.outputLocation ? {OutputLocation: this.outputLocation} : undefined,\n ExecutionParameters: params?.map(renderAthenaParameter),\n }),\n )\n if (!res.QueryExecutionId) throw new Error('Athena did not return a query execution id')\n return res.QueryExecutionId\n }\n\n private async waitForQuery(queryExecutionId: string) {\n let started = Date.now()\n let timeoutMs = 5 * 60 * 1000\n while (Date.now() - started < timeoutMs) {\n let res = await this.client.send(new GetQueryExecutionCommand({QueryExecutionId: queryExecutionId}))\n let status = res.QueryExecution?.Status\n if (status?.State == 'SUCCEEDED') return\n if (status?.State == 'FAILED' || status?.State == 'CANCELLED') throw new Error(`Athena query ${status.State.toLowerCase()}: ${status.StateChangeReason || 'unknown reason'}`)\n await new Promise(resolve => setTimeout(resolve, 1000))\n }\n throw new Error(`Athena query timed out after ${Math.round(timeoutMs / 1000)}s`)\n }\n\n private async fetchResults(queryExecutionId: string): Promise<QueryResult> {\n let rows: Array<Record<string, unknown>> = []\n let nextToken: string | undefined\n let firstPage = true\n\n while (true) {\n let res = await this.client.send(new GetQueryResultsCommand({QueryExecutionId: queryExecutionId, NextToken: nextToken, MaxResults: 1000}))\n let columns = res.ResultSet?.ResultSetMetadata?.ColumnInfo || []\n let resultRows = firstPage ? (res.ResultSet?.Rows || []).slice(1) : res.ResultSet?.Rows || []\n\n for (let row of resultRows) {\n let out: Record<string, unknown> = {}\n columns.forEach((column, idx) => {\n let value = row.Data?.[idx]?.VarCharValue\n out[String(column.Name).toLowerCase()] = parseAthenaValue(value, String(column.Type || ''))\n })\n rows.push(out)\n }\n\n firstPage = false\n if (!res.NextToken || rows.length >= 10000) return {rows, totalRows: rows.length}\n nextToken = res.NextToken\n }\n }\n\n private async resolveDatabaseName(name: string): Promise<string> {\n let databases = await this.listDatasets()\n return databases.find(db => db.toLowerCase() == name.toLowerCase()) || name\n }\n}\n\nfunction renderAthenaParameter(value: unknown) {\n if (value === null || value === undefined) return 'NULL'\n if (typeof value == 'number' || typeof value == 'bigint') return String(value)\n if (typeof value == 'boolean') return value ? 'true' : 'false'\n return `'${String(value).replace(/'/g, \"''\")}'`\n}\n\nfunction parseAthenaValue(value: string | undefined, type: string) {\n if (value === undefined) return null\n let normalizedType = type.toLowerCase()\n if (normalizedType == 'boolean') return value == 'true'\n if (/^(tinyint|smallint|integer|bigint|real|float|double|decimal)/.test(normalizedType)) return Number(value)\n return value\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  config
3
- } from "./chunk-SQVXTHE5.js";
3
+ } from "./chunk-KW66YQ62.js";
4
4
 
5
5
  // connections/bigQuery.ts
6
6
  import { BigQuery, BigQueryDate, BigQueryTimestamp } from "@google-cloud/bigquery";
@@ -72,4 +72,4 @@ var BigQueryConnection = class {
72
72
  export {
73
73
  BigQueryConnection
74
74
  };
75
- //# sourceMappingURL=bigQuery-YIWXZPY6.js.map
75
+ //# sourceMappingURL=bigQuery-3A7HPXZS.js.map
@@ -14,6 +14,8 @@ function normalizeConfig(input, defaultRoot = process.cwd()) {
14
14
  if (cfg.bigquery) dialect = "bigquery";
15
15
  else if (cfg.snowflake) dialect = "snowflake";
16
16
  else if (cfg.clickhouse) dialect = "clickhouse";
17
+ else if (cfg.postgres) dialect = "postgres";
18
+ else if (cfg.athena) dialect = "athena";
17
19
  else if (cfg.duckdb) dialect = "duckdb";
18
20
  let envFile = [".env"];
19
21
  if (Array.isArray(cfg.envFile)) envFile = cfg.envFile;
@@ -50,4 +52,4 @@ export {
50
52
  setGlobalConfig,
51
53
  loadConfig
52
54
  };
53
- //# sourceMappingURL=chunk-SQVXTHE5.js.map
55
+ //# sourceMappingURL=chunk-KW66YQ62.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../lang/config.ts"],
4
+ "sourcesContent": ["import {existsSync} from 'node:fs'\nimport {readFile} from 'node:fs/promises'\nimport path from 'path'\n\nexport interface Config {\n root: string\n dialect: string\n defaultNamespace?: string\n ignoredFiles: string[]\n telemetry?: boolean\n updateNotifier?: boolean\n port?: number\n host?: string\n envFile: string[] // array of paths where we can look for the env file\n\n bigquery?: {\n projectId?: string\n keyPath?: string\n }\n\n snowflake?: {\n account: string\n username: string\n privateKeyPath: string\n schema?: string\n database?: string\n }\n\n clickhouse?: {\n url?: string\n username?: string\n database?: string\n requestTimeout?: number\n }\n\n postgres?: {\n connectionString?: string\n host?: string\n port?: number\n database?: string\n user?: string\n username?: string\n schema?: string\n inMemory?: boolean\n seedSql?: string\n ssl?: boolean | {rejectUnauthorized?: boolean}\n max?: number\n idleTimeoutMillis?: number\n connectionTimeoutMillis?: number\n queryTimeout?: number\n statementTimeout?: number\n }\n\n athena?: {\n region?: string\n catalog?: string\n database?: string\n workGroup?: string\n outputLocation?: string\n }\n\n duckdb?: {\n path?: string\n }\n}\n\nexport type ConfigInput = Omit<Config, 'root' | 'dialect' | 'ignoredFiles' | 'envFile'> & {\n root?: string\n dialect?: Config['dialect']\n ignoredFiles?: Config['ignoredFiles']\n envFile?: string | string[]\n namespace?: string\n}\n\nexport let config: Config = {dialect: 'duckdb', root: ''} as Config\n\nexport function setGlobalConfig(cfg: ConfigInput) {\n Object.keys(config).forEach(key => delete config[key])\n Object.assign(config, normalizeConfig(cfg))\n}\n\nexport function normalizeConfig(input: ConfigInput, defaultRoot = process.cwd()): Config {\n let cfg = {...input}\n if (cfg.namespace && !cfg.defaultNamespace) cfg.defaultNamespace = cfg.namespace\n\n let dialect = cfg.dialect || 'duckdb'\n if (cfg.bigquery) dialect = 'bigquery'\n else if (cfg.snowflake) dialect = 'snowflake'\n else if (cfg.clickhouse) dialect = 'clickhouse'\n else if (cfg.postgres) dialect = 'postgres'\n else if (cfg.athena) dialect = 'athena'\n else if (cfg.duckdb) dialect = 'duckdb'\n let envFile = ['.env']\n if (Array.isArray(cfg.envFile)) envFile = cfg.envFile\n else if (cfg.envFile) envFile = [cfg.envFile]\n\n return {\n ...cfg,\n dialect,\n root: path.resolve(cfg.root || defaultRoot),\n port: cfg.port || Number(process.env.GRAPHENE_PORT) || 4000,\n ignoredFiles: cfg.ignoredFiles || [],\n envFile,\n } as Config\n}\n\n// Read graphene config from the nearest parent package.json.\nexport async function loadConfig(dir: string, envLoader: (envFiles: string[]) => void): Promise<Config> {\n // seek upwards from dir looking for package.json\n let configDir = path.resolve(dir)\n while (!existsSync(path.join(configDir, 'package.json'))) {\n let parent = path.dirname(configDir)\n if (parent == configDir) throw new Error(`No package.json found in ${path.resolve(dir)} or its parents`)\n configDir = parent\n }\n\n let txt = await readFile(path.join(configDir, 'package.json'), 'utf8')\n let graphene = JSON.parse(txt).graphene\n if (!graphene || typeof graphene != 'object' || Array.isArray(graphene)) {\n throw new Error(`No graphene config found in ${path.join(configDir, 'package.json')}`)\n }\n\n // config can provide 1 or more env files that Graphene should load. Default to just `.env`\n let envFiles = Array.isArray(graphene.envFile) ? graphene.envFile : [graphene.envFile || '.env']\n envLoader(envFiles.map(file => path.resolve(configDir, file)))\n\n let cfg = normalizeConfig({...graphene, root: configDir}, configDir)\n return cfg\n}\n"],
5
+ "mappings": ";AAAA,SAAQ,kBAAiB;AACzB,SAAQ,gBAAe;AACvB,OAAO,UAAU;AAwEV,IAAI,SAAiB,EAAC,SAAS,UAAU,MAAM,GAAE;AAEjD,SAAS,gBAAgB,KAAkB;AAChD,SAAO,KAAK,MAAM,EAAE,QAAQ,SAAO,OAAO,OAAO,GAAG,CAAC;AACrD,SAAO,OAAO,QAAQ,gBAAgB,GAAG,CAAC;AAC5C;AAEO,SAAS,gBAAgB,OAAoB,cAAc,QAAQ,IAAI,GAAW;AACvF,MAAI,MAAM,EAAC,GAAG,MAAK;AACnB,MAAI,IAAI,aAAa,CAAC,IAAI,iBAAkB,KAAI,mBAAmB,IAAI;AAEvE,MAAI,UAAU,IAAI,WAAW;AAC7B,MAAI,IAAI,SAAU,WAAU;AAAA,WACnB,IAAI,UAAW,WAAU;AAAA,WACzB,IAAI,WAAY,WAAU;AAAA,WAC1B,IAAI,SAAU,WAAU;AAAA,WACxB,IAAI,OAAQ,WAAU;AAAA,WACtB,IAAI,OAAQ,WAAU;AAC/B,MAAI,UAAU,CAAC,MAAM;AACrB,MAAI,MAAM,QAAQ,IAAI,OAAO,EAAG,WAAU,IAAI;AAAA,WACrC,IAAI,QAAS,WAAU,CAAC,IAAI,OAAO;AAE5C,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA,MAAM,KAAK,QAAQ,IAAI,QAAQ,WAAW;AAAA,IAC1C,MAAM,IAAI,QAAQ,OAAO,QAAQ,IAAI,aAAa,KAAK;AAAA,IACvD,cAAc,IAAI,gBAAgB,CAAC;AAAA,IACnC;AAAA,EACF;AACF;AAGA,eAAsB,WAAW,KAAa,WAA0D;AAEtG,MAAI,YAAY,KAAK,QAAQ,GAAG;AAChC,SAAO,CAAC,WAAW,KAAK,KAAK,WAAW,cAAc,CAAC,GAAG;AACxD,QAAI,SAAS,KAAK,QAAQ,SAAS;AACnC,QAAI,UAAU,UAAW,OAAM,IAAI,MAAM,4BAA4B,KAAK,QAAQ,GAAG,CAAC,iBAAiB;AACvG,gBAAY;AAAA,EACd;AAEA,MAAI,MAAM,MAAM,SAAS,KAAK,KAAK,WAAW,cAAc,GAAG,MAAM;AACrE,MAAI,WAAW,KAAK,MAAM,GAAG,EAAE;AAC/B,MAAI,CAAC,YAAY,OAAO,YAAY,YAAY,MAAM,QAAQ,QAAQ,GAAG;AACvE,UAAM,IAAI,MAAM,+BAA+B,KAAK,KAAK,WAAW,cAAc,CAAC,EAAE;AAAA,EACvF;AAGA,MAAI,WAAW,MAAM,QAAQ,SAAS,OAAO,IAAI,SAAS,UAAU,CAAC,SAAS,WAAW,MAAM;AAC/F,YAAU,SAAS,IAAI,UAAQ,KAAK,QAAQ,WAAW,IAAI,CAAC,CAAC;AAE7D,MAAI,MAAM,gBAAgB,EAAC,GAAG,UAAU,MAAM,UAAS,GAAG,SAAS;AACnE,SAAO;AACT;",
6
+ "names": []
7
+ }