@hypequery/cli 1.0.0 → 1.1.1

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/README.md CHANGED
@@ -4,7 +4,14 @@ Command-line interface for Hypequery - the type-safe analytics layer for ClickHo
4
4
 
5
5
  ## Quick Start
6
6
 
7
- **No installation required!** Use `npx` to run commands directly:
7
+ The CLI scaffolds and runs the main hypequery path:
8
+
9
+ 1. Generate schema types from ClickHouse
10
+ 2. Build queries with the typed query builder
11
+ 3. Wrap reusable queries with `query({ ... })`
12
+ 4. Add `serve({ queries })` when you want HTTP routes and docs
13
+
14
+ Use `npx` to run commands directly:
8
15
 
9
16
  ```bash
10
17
  # Initialize a new project
@@ -68,7 +75,7 @@ npx hypequery init
68
75
  **What it does:**
69
76
  - Connects to your ClickHouse database
70
77
  - Generates TypeScript types from your schema
71
- - Creates client, queries, and config files
78
+ - Creates the client, query, and serve files for the main path
72
79
  - Sets up `.env` with connection details
73
80
  - Updates `.gitignore` to protect secrets
74
81
 
@@ -192,7 +199,12 @@ npm run db:dev
192
199
 
193
200
  ## Documentation
194
201
 
195
- Visit [hypequery.com/docs](https://hypequery.com/docs) for full documentation.
202
+ Visit the main docs flow:
203
+
204
+ - [Quick Start](https://hypequery.com/docs/quick-start)
205
+ - [Core Concepts](https://hypequery.com/docs/core-concepts)
206
+ - [Query Building](https://hypequery.com/docs/query-building/basics)
207
+ - [Serve Runtime Reference](https://hypequery.com/docs/reference/runtime)
196
208
 
197
209
  ## License
198
210
 
@@ -3,5 +3,7 @@ export interface ClickHouseGeneratorOptions {
3
3
  includeTables?: string[];
4
4
  excludeTables?: string[];
5
5
  }
6
+ declare const clickhouseToTsType: (type: string) => string;
7
+ export { clickhouseToTsType };
6
8
  export declare function generateClickHouseTypes(options: ClickHouseGeneratorOptions): Promise<void>;
7
9
  //# sourceMappingURL=clickhouse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clickhouse.d.ts","sourceRoot":"","sources":["../../src/generators/clickhouse.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AA4HD,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,0BAA0B,iBA0ChF"}
1
+ {"version":3,"file":"clickhouse.d.ts","sourceRoot":"","sources":["../../src/generators/clickhouse.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAmGD,QAAA,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAsC1C,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAgC9B,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,0BAA0B,iBA0ChF"}
@@ -39,57 +39,53 @@ import path from 'node:path';
39
39
  import { getClickHouseClient } from '../utils/clickhouse-client.js';
40
40
  var DEFAULT_WARNING = 'Warning: No tables match the filter criteria. Check your include/exclude options.';
41
41
  var capitalizeFirstLetter = function (value) { return value.charAt(0).toUpperCase() + value.slice(1); };
42
- var clickhouseToTsType = function (type) {
43
- if (type.startsWith('Array(')) {
44
- var innerType = type.slice(6, -1);
45
- return "Array<".concat(clickhouseToTsType(innerType), ">");
46
- }
47
- if (type.startsWith('Nullable(')) {
48
- var innerType = type.slice(9, -1);
49
- return "".concat(clickhouseToTsType(innerType), " | null");
50
- }
51
- if (type.startsWith('Map(')) {
52
- var mapContent = type.slice(4, -1);
53
- var commaIndex = mapContent.lastIndexOf(',');
54
- if (commaIndex !== -1) {
55
- var keyType = mapContent.substring(0, commaIndex).trim();
56
- var valueType = mapContent.substring(commaIndex + 1).trim();
57
- var keyTsType = 'string';
58
- if (keyType === 'LowCardinality(String)') {
59
- keyTsType = 'string';
60
- }
61
- else if (keyType.includes('Int') || keyType.includes('UInt')) {
62
- keyTsType = 'number';
63
- }
64
- var valueTsType = 'unknown';
65
- if (valueType.startsWith('Array(')) {
66
- var innerType = valueType.slice(6, -1);
67
- valueTsType = "Array<".concat(clickhouseToTsType(innerType), ">");
68
- }
69
- else if (valueType.startsWith('Nullable(')) {
70
- var innerType = valueType.slice(9, -1);
71
- valueTsType = "".concat(clickhouseToTsType(innerType), " | null");
72
- }
73
- else {
74
- valueTsType = clickhouseToTsType(valueType);
75
- }
76
- return "Record<".concat(keyTsType, ", ").concat(valueTsType, ">");
42
+ function splitTopLevelArgs(value) {
43
+ var parts = [];
44
+ var current = '';
45
+ var depth = 0;
46
+ for (var _i = 0, value_1 = value; _i < value_1.length; _i++) {
47
+ var char = value_1[_i];
48
+ if (char === '(') {
49
+ depth += 1;
50
+ current += char;
51
+ continue;
77
52
  }
78
- return 'Record<string, unknown>';
53
+ if (char === ')') {
54
+ depth -= 1;
55
+ current += char;
56
+ continue;
57
+ }
58
+ if (char === ',' && depth === 0) {
59
+ parts.push(current.trim());
60
+ current = '';
61
+ continue;
62
+ }
63
+ current += char;
79
64
  }
80
- switch (type.toLowerCase()) {
65
+ if (current.trim()) {
66
+ parts.push(current.trim());
67
+ }
68
+ return parts;
69
+ }
70
+ function unwrapType(type, wrapperName) {
71
+ var prefix = "".concat(wrapperName, "(");
72
+ return type.startsWith(prefix) && type.endsWith(')') ? type.slice(prefix.length, -1) : null;
73
+ }
74
+ function getPrimitiveTsType(type) {
75
+ var lowerType = type.toLowerCase();
76
+ switch (lowerType) {
81
77
  case 'string':
82
- case 'fixedstring':
78
+ case 'uuid':
83
79
  return 'string';
84
80
  case 'int8':
85
81
  case 'int16':
86
82
  case 'int32':
87
83
  case 'uint8':
88
- case 'int64':
89
84
  case 'uint16':
90
85
  case 'uint32':
91
- case 'uint64':
92
86
  return 'number';
87
+ case 'int64':
88
+ case 'uint64':
93
89
  case 'uint128':
94
90
  case 'uint256':
95
91
  case 'int128':
@@ -108,9 +104,56 @@ var clickhouseToTsType = function (type) {
108
104
  case 'boolean':
109
105
  return 'boolean';
110
106
  default:
111
- return 'string';
107
+ if (type.startsWith('FixedString('))
108
+ return 'string';
109
+ if (type.startsWith('Decimal('))
110
+ return 'number';
111
+ if (type.startsWith('DateTime64('))
112
+ return 'string';
113
+ if (type.startsWith('DateTime('))
114
+ return 'string';
115
+ if (type.startsWith('Enum8('))
116
+ return 'string';
117
+ if (type.startsWith('Enum16('))
118
+ return 'string';
119
+ return null;
120
+ }
121
+ }
122
+ var clickhouseToTsType = function (type) {
123
+ var wrappedArrayType = unwrapType(type, 'Array');
124
+ if (wrappedArrayType) {
125
+ return "Array<".concat(clickhouseToTsType(wrappedArrayType), ">");
126
+ }
127
+ var wrappedNullableType = unwrapType(type, 'Nullable');
128
+ if (wrappedNullableType) {
129
+ return "".concat(clickhouseToTsType(wrappedNullableType), " | null");
130
+ }
131
+ var wrappedLowCardinalityType = unwrapType(type, 'LowCardinality');
132
+ if (wrappedLowCardinalityType) {
133
+ return clickhouseToTsType(wrappedLowCardinalityType);
134
+ }
135
+ var wrappedTupleType = unwrapType(type, 'Tuple');
136
+ if (wrappedTupleType) {
137
+ var tupleParts = splitTopLevelArgs(wrappedTupleType);
138
+ return "[".concat(tupleParts.map(clickhouseToTsType).join(', '), "]");
139
+ }
140
+ var wrappedMapType = unwrapType(type, 'Map');
141
+ if (wrappedMapType) {
142
+ var mapParts = splitTopLevelArgs(wrappedMapType);
143
+ if (mapParts.length === 2) {
144
+ var valueType = mapParts[1];
145
+ // JSON object keys are strings even when ClickHouse map keys are numeric.
146
+ return "Record<string, ".concat(clickhouseToTsType(valueType), ">");
147
+ }
148
+ return 'Record<string, unknown>';
112
149
  }
150
+ var primitiveType = getPrimitiveTsType(type);
151
+ if (primitiveType)
152
+ return primitiveType;
153
+ // Unsupported or more complex ClickHouse types currently preserve the historical fallback.
154
+ return 'string';
113
155
  };
156
+ export { clickhouseToTsType };
114
157
  function fetchTables(includeTables, excludeTables) {
115
158
  return __awaiter(this, void 0, void 0, function () {
116
159
  var client, tablesQuery, tables;
@@ -1 +1 @@
1
- {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/templates/queries.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CA6DT"}
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/templates/queries.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CA+DT"}
@@ -5,14 +5,14 @@ export function generateQueriesTemplate(options) {
5
5
  var hasExample = options.hasExample, tableName = options.tableName;
6
6
  var metricKey = hasExample && tableName ? "".concat(camelCase(tableName), "Query") : 'exampleMetric';
7
7
  var typeAlias = "".concat(pascalCase(metricKey), "Result");
8
- var template = "import { initServe } from '@hypequery/serve';\nimport type { InferApiType } from '@hypequery/serve';\nimport { z } from 'zod';\nimport { db } from './client';\n\nconst serve = initServe({\n context: () => ({ db }),\n});\nconst { query } = serve;\n\nexport const api = serve.define({\n queries: serve.queries({";
8
+ var template = "import { initServe } from '@hypequery/serve';\nimport type { InferApiType } from '@hypequery/serve';\nimport { z } from 'zod';\nimport { db } from './client';\n\nconst { query, serve } = initServe({\n context: () => ({ db }),\n});\n\n";
9
9
  if (hasExample && tableName) {
10
- template += "\n ".concat(camelCase(tableName), "Query: query\n .describe('Example query using the ").concat(tableName, " table')\n .query(async ({ ctx }) =>\n ctx.db\n .table('").concat(tableName, "')\n .select('*')\n .limit(10)\n .execute()\n ),");
10
+ template += "\nconst ".concat(camelCase(tableName), "Query = query({\n description: 'Example query using the ").concat(tableName, " table',\n query: async ({ ctx }) =>\n ctx.db\n .table('").concat(tableName, "')\n .select('*')\n .limit(10)\n .execute(),\n});");
11
11
  }
12
12
  else {
13
- template += "\n exampleMetric: query\n .describe('Example metric that returns a simple value')\n .output(z.object({ ok: z.boolean() }))\n .query(async () => ({ ok: true })),";
13
+ template += "\nconst exampleMetric = query({\n description: 'Example metric that returns a simple value',\n output: z.object({ ok: z.boolean() }),\n query: async () => ({ ok: true }),\n});";
14
14
  }
15
- template += "\n }),\n});\n\nexport type ApiDefinition = InferApiType<typeof api>;\n\n/**\n * Inline usage example:\n *\n * const result = await api.execute('".concat(metricKey, "');\n * console.log(result);\n *\n * // import type { InferQueryResult } from '@hypequery/serve';\n * type ").concat(typeAlias, " = InferQueryResult<typeof api, '").concat(metricKey, "'>;\n *\n * // Register HTTP route:\n * api.route('/metrics/").concat(metricKey, "', api.queries.").concat(metricKey, ");\n *\n * Dev server:\n * npx hypequery dev\n */\n");
15
+ template += "\nexport const api = serve({\n queries: {\n ".concat(metricKey, ",\n },\n});\n\nexport type ApiDefinition = InferApiType<typeof api>;\n\n/**\n * Inline usage example:\n *\n * const result = await api.execute('").concat(metricKey, "');\n * console.log(result);\n *\n * // import type { InferQueryResult } from '@hypequery/serve';\n * type ").concat(typeAlias, " = InferQueryResult<typeof api, '").concat(metricKey, "'>;\n *\n * // Register HTTP route:\n * api.route('/metrics/").concat(metricKey, "', api.queries.").concat(metricKey, ");\n *\n * Dev server:\n * npx hypequery dev analytics/queries.ts\n */\n");
16
16
  return template;
17
17
  }
18
18
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC;;GAEG;AACH,wBAAgB,iBAAiB;;;;;;;;;EAWhC;AAED;;GAEG;AACH,wBAAgB,uBAAuB;;;;EAMtC;AAED;;GAEG;AACH,wBAAgB,mBAAmB;;;;;EAOlC;AAED;;GAEG;AACH,wBAAgB,gBAAgB;;;;;;;;;;;;EAc/B;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;;GAQhC;AAED;;GAEG;AACH,wBAAgB,YAAY;;;;;EAO3B;AAED;;GAEG;AACH,wBAAgB,cAAc;;;;EAuB7B;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACtB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIhC;AAED,wBAAgB,eAAe;;;EAe9B"}
1
+ {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC;;GAEG;AACH,wBAAgB,iBAAiB;;;;;;;;;EAWhC;AAED;;GAEG;AACH,wBAAgB,uBAAuB;;;;EAMtC;AAED;;GAEG;AACH,wBAAgB,mBAAmB;;;;;EAOlC;AAED;;GAEG;AACH,wBAAgB,gBAAgB;;;;;;;;;;;;EAc/B;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;;GAQhC;AAED;;GAEG;AACH,wBAAgB,YAAY;;;;;EAO3B;AAED;;GAEG;AACH,wBAAgB,cAAc;;;;EAuB7B;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACtB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIhC;AAED,wBAAgB,eAAe;;;EAc9B"}
@@ -142,7 +142,6 @@ export function mockProcessExit() {
142
142
  var exitMock = vi.fn(function (code) {
143
143
  throw new ProcessExitError(code !== null && code !== void 0 ? code : 0);
144
144
  });
145
- // @ts-ignore
146
145
  process.exit = exitMock;
147
146
  return {
148
147
  exitMock: exitMock,
@@ -1,2 +1,3 @@
1
1
  export declare function loadApiModule(modulePath: string): Promise<any>;
2
+ export declare function loadModule(modulePath: string): Promise<any>;
2
3
  //# sourceMappingURL=load-api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"load-api.d.ts","sourceRoot":"","sources":["../../src/utils/load-api.ts"],"names":[],"mappings":"AAaA,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,gBAuErD"}
1
+ {"version":3,"file":"load-api.d.ts","sourceRoot":"","sources":["../../src/utils/load-api.ts"],"names":[],"mappings":"AAaA,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,gBAkDrD;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,gBAkClD"}
@@ -36,7 +36,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
36
36
  };
37
37
  var _a, _b, _c, _d;
38
38
  import { pathToFileURL } from 'node:url';
39
- import { access, mkdtemp, writeFile, rm, mkdir } from 'node:fs/promises';
39
+ import { access, mkdtemp, rm, mkdir, writeFile } from 'node:fs/promises';
40
40
  import os from 'node:os';
41
41
  import path from 'node:path';
42
42
  import { build } from 'esbuild';
@@ -47,8 +47,62 @@ var TYPESCRIPT_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts']);
47
47
  var tsconfigCache = new Map();
48
48
  export function loadApiModule(modulePath) {
49
49
  return __awaiter(this, void 0, void 0, function () {
50
- var resolved, _a, relativePath, extension, isTypeScript, moduleUrl, _b, mod, error_1, relativePath, api, relativePath, availableExports;
51
- var _c;
50
+ var resolved, mod, error_1, relativePath, api, relativePath, availableExports;
51
+ var _a;
52
+ return __generator(this, function (_b) {
53
+ switch (_b.label) {
54
+ case 0:
55
+ resolved = path.resolve(process.cwd(), modulePath);
56
+ _b.label = 1;
57
+ case 1:
58
+ _b.trys.push([1, 3, , 4]);
59
+ return [4 /*yield*/, loadModule(modulePath)];
60
+ case 2:
61
+ mod = _b.sent();
62
+ return [3 /*break*/, 4];
63
+ case 3:
64
+ error_1 = _b.sent();
65
+ if (error_1 instanceof Error && error_1.message.startsWith('File not found:')) {
66
+ relativePath = path.relative(process.cwd(), resolved);
67
+ throw new Error("File not found: ".concat(relativePath, "\n\n") +
68
+ "Make sure the file exists and the path is correct.\n" +
69
+ "You can specify a different file with:\n" +
70
+ " hypequery dev path/to/your/queries.ts");
71
+ }
72
+ throw error_1;
73
+ case 4:
74
+ api = (_a = mod.api) !== null && _a !== void 0 ? _a : mod.default;
75
+ if (!api || typeof api.handler !== 'function') {
76
+ relativePath = path.relative(process.cwd(), resolved);
77
+ availableExports = Object.keys(mod).filter(function (key) { return key !== '__esModule'; });
78
+ throw new Error("Invalid API module: ".concat(relativePath, "\n\n") +
79
+ "The module must export a 'defineServe' result as 'api'.\n\n" +
80
+ (availableExports.length > 0
81
+ ? "Found exports: ".concat(availableExports.join(', '), "\n\n")
82
+ : "No exports found in the module.\n\n") +
83
+ "Expected format:\n\n" +
84
+ " import { initServe } from '@hypequery/serve';\n" +
85
+ " \n" +
86
+ " const { define, queries, query } = initServe({\n" +
87
+ " context: () => ({ db }),\n" +
88
+ " });\n" +
89
+ " \n" +
90
+ " export const api = define({\n" +
91
+ " queries: queries({\n" +
92
+ " myQuery: query.query(async ({ ctx }) => {\n" +
93
+ " // ...\n" +
94
+ " }),\n" +
95
+ " }),\n" +
96
+ " });\n");
97
+ }
98
+ return [2 /*return*/, api];
99
+ }
100
+ });
101
+ });
102
+ }
103
+ export function loadModule(modulePath) {
104
+ return __awaiter(this, void 0, void 0, function () {
105
+ var resolved, _a, relativePath, extension, isTypeScript, moduleUrl, _b, importOverride, _c, error_2, relativePath;
52
106
  return __generator(this, function (_d) {
53
107
  switch (_d.label) {
54
108
  case 0:
@@ -63,10 +117,7 @@ export function loadApiModule(modulePath) {
63
117
  case 3:
64
118
  _a = _d.sent();
65
119
  relativePath = path.relative(process.cwd(), resolved);
66
- throw new Error("File not found: ".concat(relativePath, "\n\n") +
67
- "Make sure the file exists and the path is correct.\n" +
68
- "You can specify a different file with:\n" +
69
- " hypequery dev path/to/your/queries.ts");
120
+ throw new Error("File not found: ".concat(relativePath));
70
121
  case 4:
71
122
  extension = path.extname(resolved).toLowerCase();
72
123
  isTypeScript = TYPESCRIPT_EXTENSIONS.has(extension);
@@ -82,48 +133,30 @@ export function loadApiModule(modulePath) {
82
133
  moduleUrl = _b;
83
134
  _d.label = 8;
84
135
  case 8:
85
- _d.trys.push([8, 10, , 11]);
86
- return [4 /*yield*/, import(moduleUrl)];
136
+ _d.trys.push([8, 13, , 14]);
137
+ importOverride = globalState.__hypequeryCliImportOverride;
138
+ if (!importOverride) return [3 /*break*/, 10];
139
+ return [4 /*yield*/, importOverride(moduleUrl)];
87
140
  case 9:
88
- mod = _d.sent();
89
- return [3 /*break*/, 11];
90
- case 10:
91
- error_1 = _d.sent();
141
+ _c = _d.sent();
142
+ return [3 /*break*/, 12];
143
+ case 10: return [4 /*yield*/, import(/* @vite-ignore */ moduleUrl)];
144
+ case 11:
145
+ _c = _d.sent();
146
+ _d.label = 12;
147
+ case 12: return [2 /*return*/, _c];
148
+ case 13:
149
+ error_2 = _d.sent();
92
150
  relativePath = path.relative(process.cwd(), resolved);
93
151
  throw new Error("Failed to load module: ".concat(relativePath, "\n\n") +
94
- "Error: ".concat(error_1.message, "\n\n") +
95
- (error_1.code === 'ERR_MODULE_NOT_FOUND'
152
+ "Error: ".concat(error_2.message, "\n\n") +
153
+ (error_2.code === 'ERR_MODULE_NOT_FOUND'
96
154
  ? "This usually means:\n" +
97
155
  " \u2022 A dependency is missing (run 'npm install')\n" +
98
156
  " \u2022 An import path is incorrect\n"
99
157
  : "") +
100
- (error_1.stack ? "\nStack trace:\n".concat(error_1.stack, "\n") : ''));
101
- case 11:
102
- api = (_c = mod.api) !== null && _c !== void 0 ? _c : mod.default;
103
- if (!api || typeof api.handler !== 'function') {
104
- relativePath = path.relative(process.cwd(), resolved);
105
- availableExports = Object.keys(mod).filter(function (key) { return key !== '__esModule'; });
106
- throw new Error("Invalid API module: ".concat(relativePath, "\n\n") +
107
- "The module must export a 'defineServe' result as 'api'.\n\n" +
108
- (availableExports.length > 0
109
- ? "Found exports: ".concat(availableExports.join(', '), "\n\n")
110
- : "No exports found in the module.\n\n") +
111
- "Expected format:\n\n" +
112
- " import { initServe } from '@hypequery/serve';\n" +
113
- " \n" +
114
- " const { define, queries, query } = initServe({\n" +
115
- " context: () => ({ db }),\n" +
116
- " });\n" +
117
- " \n" +
118
- " export const api = define({\n" +
119
- " queries: queries({\n" +
120
- " myQuery: query.query(async ({ ctx }) => {\n" +
121
- " // ...\n" +
122
- " }),\n" +
123
- " }),\n" +
124
- " });\n");
125
- }
126
- return [2 /*return*/, api];
158
+ (error_2.stack ? "\nStack trace:\n".concat(error_2.stack, "\n") : ''));
159
+ case 14: return [2 /*return*/];
127
160
  }
128
161
  });
129
162
  });
@@ -285,7 +318,7 @@ function installCleanupHooks() {
285
318
  }
286
319
  function bundleTypeScriptModule(entryPath) {
287
320
  return __awaiter(this, void 0, void 0, function () {
288
- var relativePath, tsconfigPath, result, output, contents, tempDir, tempFile, error_2;
321
+ var relativePath, tsconfigPath, result, output, tempDir, timestamp, tempFile, contents, error_3;
289
322
  var _a, _b, _c, _d;
290
323
  return __generator(this, function (_e) {
291
324
  switch (_e.label) {
@@ -322,20 +355,23 @@ function bundleTypeScriptModule(entryPath) {
322
355
  if (!output) {
323
356
  throw new Error('esbuild produced no output');
324
357
  }
325
- contents = "".concat(output.text, "\n//# sourceURL=").concat(pathToFileURL(entryPath).href);
326
358
  return [4 /*yield*/, ensureTempDir()];
327
359
  case 4:
328
360
  tempDir = _e.sent();
329
- tempFile = path.join(tempDir, "".concat(path.basename(entryPath).replace(/[^a-zA-Z0-9_-]/g, '_'), "-").concat(Date.now(), "-").concat(Math.random().toString(36).slice(2), ".mjs"));
361
+ timestamp = Date.now();
362
+ tempFile = path.join(tempDir, "".concat(path.basename(entryPath, path.extname(entryPath)), "-").concat(timestamp, ".mjs"));
363
+ contents = "".concat(output.text, "\n") +
364
+ "//# sourceURL=".concat(pathToFileURL(entryPath).href, "\n") +
365
+ "//# hypequery-ts-bundle=".concat(timestamp);
330
366
  return [4 /*yield*/, writeFile(tempFile, contents, 'utf8')];
331
367
  case 5:
332
368
  _e.sent();
333
369
  tempFiles.add(tempFile);
334
- return [2 /*return*/, "".concat(pathToFileURL(tempFile).href, "?t=").concat(Date.now())];
370
+ return [2 /*return*/, "".concat(pathToFileURL(tempFile).href, "?t=").concat(timestamp)];
335
371
  case 6:
336
- error_2 = _e.sent();
372
+ error_3 = _e.sent();
337
373
  throw new Error("Failed to compile ".concat(relativePath, " with esbuild.\n") +
338
- "Original error: ".concat((_d = error_2 === null || error_2 === void 0 ? void 0 : error_2.message) !== null && _d !== void 0 ? _d : error_2));
374
+ "Original error: ".concat((_d = error_3 === null || error_3 === void 0 ? void 0 : error_3.message) !== null && _d !== void 0 ? _d : error_3));
339
375
  case 7: return [2 /*return*/];
340
376
  }
341
377
  });
@@ -386,14 +422,14 @@ function findNearestTsconfig(filePath) {
386
422
  };
387
423
  _b.label = 1;
388
424
  case 1:
389
- if (!true) return [3 /*break*/, 3];
425
+ if (!dir) return [3 /*break*/, 3];
390
426
  return [5 /*yield**/, _loop_1()];
391
427
  case 2:
392
428
  state_1 = _b.sent();
393
429
  if (typeof state_1 === "object")
394
430
  return [2 /*return*/, state_1.value];
395
431
  return [3 /*break*/, 1];
396
- case 3: return [2 /*return*/];
432
+ case 3: return [2 /*return*/, null];
397
433
  }
398
434
  });
399
435
  });
@@ -0,0 +1,7 @@
1
+ import type { ResolvedHypequeryClickHouseConfig } from '@hypequery/clickhouse';
2
+ export declare const DEFAULT_HYPEQUERY_CONFIG_PATH = "hypequery.config.ts";
3
+ export declare const DEFAULT_MIGRATIONS_OUT_DIR = "./migrations";
4
+ export declare const DEFAULT_MIGRATIONS_TABLE = "_hypequery_migrations";
5
+ export declare const DEFAULT_MIGRATIONS_PREFIX: "timestamp";
6
+ export declare function loadHypequeryConfig(configPath?: string): Promise<ResolvedHypequeryClickHouseConfig>;
7
+ //# sourceMappingURL=load-hypequery-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-hypequery-config.d.ts","sourceRoot":"","sources":["../../src/utils/load-hypequery-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,iCAAiC,EAClC,MAAM,uBAAuB,CAAC;AAG/B,eAAO,MAAM,6BAA6B,wBAAwB,CAAC;AACnE,eAAO,MAAM,0BAA0B,iBAAiB,CAAC;AACzD,eAAO,MAAM,wBAAwB,0BAA0B,CAAC;AAChE,eAAO,MAAM,yBAAyB,EAAG,WAAoB,CAAC;AAE9D,wBAAsB,mBAAmB,CACvC,UAAU,SAAgC,GACzC,OAAO,CAAC,iCAAiC,CAAC,CA0C5C"}
@@ -0,0 +1,89 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
21
+ var __generator = (this && this.__generator) || function (thisArg, body) {
22
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
23
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24
+ function verb(n) { return function (v) { return step([n, v]); }; }
25
+ function step(op) {
26
+ if (f) throw new TypeError("Generator is already executing.");
27
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
28
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
29
+ if (y = 0, t) op = [op[0] & 2, t.value];
30
+ switch (op[0]) {
31
+ case 0: case 1: t = op; break;
32
+ case 4: _.label++; return { value: op[1], done: false };
33
+ case 5: _.label++; y = op[1]; op = [0]; continue;
34
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
35
+ default:
36
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40
+ if (t[2]) _.ops.pop();
41
+ _.trys.pop(); continue;
42
+ }
43
+ op = body.call(thisArg, _);
44
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
+ }
47
+ };
48
+ import { loadModule } from './load-api.js';
49
+ export var DEFAULT_HYPEQUERY_CONFIG_PATH = 'hypequery.config.ts';
50
+ export var DEFAULT_MIGRATIONS_OUT_DIR = './migrations';
51
+ export var DEFAULT_MIGRATIONS_TABLE = '_hypequery_migrations';
52
+ export var DEFAULT_MIGRATIONS_PREFIX = 'timestamp';
53
+ export function loadHypequeryConfig() {
54
+ return __awaiter(this, arguments, void 0, function (configPath) {
55
+ var mod, candidate, config;
56
+ var _a, _b, _c, _d, _e, _f, _g;
57
+ if (configPath === void 0) { configPath = DEFAULT_HYPEQUERY_CONFIG_PATH; }
58
+ return __generator(this, function (_h) {
59
+ switch (_h.label) {
60
+ case 0: return [4 /*yield*/, loadModule(configPath)];
61
+ case 1:
62
+ mod = _h.sent();
63
+ candidate = (_a = mod.default) !== null && _a !== void 0 ? _a : mod.config;
64
+ if (!candidate || typeof candidate !== 'object') {
65
+ throw new Error("Invalid hypequery config: ".concat(configPath, "\n\n") +
66
+ "The config module must export a ClickHouse config as the default export.");
67
+ }
68
+ config = candidate;
69
+ if (config.dialect !== 'clickhouse') {
70
+ throw new Error("Invalid hypequery config: ".concat(configPath, "\n\n") +
71
+ "Expected \"dialect\" to be \"clickhouse\".");
72
+ }
73
+ if (typeof config.schema !== 'string' || config.schema.length === 0) {
74
+ throw new Error("Invalid hypequery config: ".concat(configPath, "\n\n") +
75
+ "Expected \"schema\" to be a non-empty string.");
76
+ }
77
+ if (!config.dbCredentials || typeof config.dbCredentials !== 'object') {
78
+ throw new Error("Invalid hypequery config: ".concat(configPath, "\n\n") +
79
+ "Expected \"dbCredentials\" to be defined.");
80
+ }
81
+ return [2 /*return*/, __assign(__assign({}, config), { migrations: {
82
+ out: (_c = (_b = config.migrations) === null || _b === void 0 ? void 0 : _b.out) !== null && _c !== void 0 ? _c : DEFAULT_MIGRATIONS_OUT_DIR,
83
+ table: (_e = (_d = config.migrations) === null || _d === void 0 ? void 0 : _d.table) !== null && _e !== void 0 ? _e : DEFAULT_MIGRATIONS_TABLE,
84
+ prefix: (_g = (_f = config.migrations) === null || _f === void 0 ? void 0 : _f.prefix) !== null && _g !== void 0 ? _g : DEFAULT_MIGRATIONS_PREFIX,
85
+ } })];
86
+ }
87
+ });
88
+ });
89
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMzD;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAavE;AAED;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAAC,CAkCR;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CA6B7D;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAS9D;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BnF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CASxE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASnE;AAED;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC,CAShE"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAQzD;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAavE;AAED;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAAC,CAkCR;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CA6B7D;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAS9D;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BnF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CASxE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASnE;AAED;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC,CAShE"}
@@ -45,8 +45,9 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
45
45
  };
46
46
  import prompts from 'prompts';
47
47
  import { logger } from './logger.js';
48
+ var noop = function () { return undefined; };
48
49
  // Configure prompts to not exit on cancel
49
- prompts.override({ onCancel: function () { } });
50
+ prompts.override({ onCancel: noop });
50
51
  /**
51
52
  * Prompt for database type selection
52
53
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypequery/cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Command-line interface for hypequery",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -15,7 +15,7 @@
15
15
  "chalk": "^5.3.0",
16
16
  "commander": "^12.0.0",
17
17
  "dotenv": "^16.4.7",
18
- "esbuild": "^0.24.0",
18
+ "esbuild": "^0.25.0",
19
19
  "open": "^10.0.0",
20
20
  "ora": "^8.0.1",
21
21
  "prompts": "^2.4.2"
@@ -35,8 +35,16 @@
35
35
  "@vitest/coverage-v8": "^2.1.6",
36
36
  "typescript": "^5.7.3",
37
37
  "vitest": "^2.1.6",
38
- "@hypequery/serve": "0.1.1",
39
- "@hypequery/clickhouse": "1.6.0"
38
+ "@hypequery/clickhouse": "1.6.2",
39
+ "@hypequery/serve": "0.2.0"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/hypequery/hypequery.git"
44
+ },
45
+ "homepage": "https://www.hypequery.com",
46
+ "bugs": {
47
+ "url": "https://github.com/hypequery/hypequery/issues"
40
48
  },
41
49
  "publishConfig": {
42
50
  "access": "public"