@hypequery/serve 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +138 -879
  2. package/dist/adapters/node.d.ts.map +1 -1
  3. package/dist/adapters/node.js +3 -5
  4. package/dist/adapters/standalone.d.ts +41 -0
  5. package/dist/adapters/standalone.d.ts.map +1 -0
  6. package/dist/adapters/standalone.js +46 -0
  7. package/dist/auth.d.ts +59 -83
  8. package/dist/auth.d.ts.map +1 -1
  9. package/dist/auth.js +136 -102
  10. package/dist/client-config.d.ts +3 -2
  11. package/dist/client-config.d.ts.map +1 -1
  12. package/dist/client-config.js +4 -2
  13. package/dist/errors.js +3 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/openapi.js +1 -2
  18. package/dist/pipeline.d.ts.map +1 -1
  19. package/dist/pipeline.js +10 -22
  20. package/dist/query-logger.js +1 -3
  21. package/dist/rate-limit.js +4 -3
  22. package/dist/router.js +2 -1
  23. package/dist/semantic/datasets/dataset-endpoint.d.ts +85 -0
  24. package/dist/semantic/datasets/dataset-endpoint.d.ts.map +1 -0
  25. package/dist/semantic/datasets/dataset-endpoint.js +121 -0
  26. package/dist/semantic/datasets/index.d.ts +6 -0
  27. package/dist/semantic/datasets/index.d.ts.map +1 -0
  28. package/dist/semantic/datasets/index.js +5 -0
  29. package/dist/semantic/datasets/metric-endpoint.d.ts +82 -0
  30. package/dist/semantic/datasets/metric-endpoint.d.ts.map +1 -0
  31. package/dist/semantic/datasets/metric-endpoint.js +159 -0
  32. package/dist/semantic/datasets/utils/dataset-entry.d.ts +24 -0
  33. package/dist/semantic/datasets/utils/dataset-entry.d.ts.map +1 -0
  34. package/dist/semantic/datasets/utils/dataset-entry.js +15 -0
  35. package/dist/semantic/datasets/utils/dataset-query-metadata.d.ts +3 -0
  36. package/dist/semantic/datasets/utils/dataset-query-metadata.d.ts.map +1 -0
  37. package/dist/semantic/datasets/utils/dataset-query-metadata.js +12 -0
  38. package/dist/semantic/datasets/utils/semantic-input-schema.d.ts +107 -0
  39. package/dist/semantic/datasets/utils/semantic-input-schema.d.ts.map +1 -0
  40. package/dist/semantic/datasets/utils/semantic-input-schema.js +87 -0
  41. package/dist/semantic/index.d.ts +2 -0
  42. package/dist/semantic/index.d.ts.map +1 -0
  43. package/dist/semantic/index.js +1 -0
  44. package/dist/semantic/query-builder-context.d.ts +20 -0
  45. package/dist/semantic/query-builder-context.d.ts.map +1 -0
  46. package/dist/semantic/query-builder-context.js +66 -0
  47. package/dist/semantic/utils/tenant-runtime.d.ts +11 -0
  48. package/dist/semantic/utils/tenant-runtime.d.ts.map +1 -0
  49. package/dist/semantic/utils/tenant-runtime.js +48 -0
  50. package/dist/serve.d.ts +2 -2
  51. package/dist/serve.d.ts.map +1 -1
  52. package/dist/server/api-builder.d.ts +5 -0
  53. package/dist/server/api-builder.d.ts.map +1 -0
  54. package/dist/server/api-builder.js +76 -0
  55. package/dist/server/builder.d.ts.map +1 -1
  56. package/dist/server/builder.js +11 -1
  57. package/dist/server/create-api.d.ts +32 -0
  58. package/dist/server/create-api.d.ts.map +1 -0
  59. package/dist/server/create-api.js +211 -0
  60. package/dist/server/define-serve.d.ts +21 -2
  61. package/dist/server/define-serve.d.ts.map +1 -1
  62. package/dist/server/define-serve.js +53 -84
  63. package/dist/server/index.d.ts +2 -0
  64. package/dist/server/index.d.ts.map +1 -1
  65. package/dist/server/index.js +2 -0
  66. package/dist/server/init-serve.d.ts +1 -1
  67. package/dist/server/init-serve.d.ts.map +1 -1
  68. package/dist/server/init-serve.js +7 -2
  69. package/dist/type-tests/builder.test-d.d.ts +4 -0
  70. package/dist/type-tests/builder.test-d.d.ts.map +1 -1
  71. package/dist/type-tests/builder.test-d.js +16 -1
  72. package/dist/type-tests/semantic.test-d.d.ts +2 -0
  73. package/dist/type-tests/semantic.test-d.d.ts.map +1 -0
  74. package/dist/type-tests/semantic.test-d.js +59 -0
  75. package/dist/types.d.ts +227 -6
  76. package/dist/types.d.ts.map +1 -1
  77. package/package.json +6 -3
@@ -25,6 +25,7 @@ export function extractClientConfig(api) {
25
25
  for (const [key, routeConfig] of Object.entries(api._routeConfig)) {
26
26
  config[key] = {
27
27
  method: routeConfig.method,
28
+ path: api.queries[key]?.metadata?.path,
28
29
  };
29
30
  }
30
31
  }
@@ -33,6 +34,7 @@ export function extractClientConfig(api) {
33
34
  for (const [key, endpoint] of Object.entries(api.queries)) {
34
35
  config[key] = {
35
36
  method: endpoint.method,
37
+ path: endpoint.metadata?.path,
36
38
  };
37
39
  }
38
40
  }
@@ -44,8 +46,8 @@ export function extractClientConfig(api) {
44
46
  *
45
47
  * @example
46
48
  * const config = defineClientConfig({
47
- * hello: { method: 'GET' },
48
- * createUser: { method: 'POST' },
49
+ * hello: { method: 'GET', path: '/api/analytics/queries/hello' },
50
+ * createUser: { method: 'POST', path: '/api/analytics/queries/createUser' },
49
51
  * });
50
52
  */
51
53
  export function defineClientConfig(config) {
package/dist/errors.js CHANGED
@@ -12,6 +12,9 @@
12
12
  * ```
13
13
  */
14
14
  export class ServeHttpError extends Error {
15
+ status;
16
+ payload;
17
+ headers;
15
18
  constructor(status, type, message, headers) {
16
19
  super(message);
17
20
  this.name = 'ServeHttpError';
package/dist/index.d.ts CHANGED
@@ -14,6 +14,8 @@ export * from "./utils.js";
14
14
  export * from "./adapters/node.js";
15
15
  export * from "./adapters/fetch.js";
16
16
  export * from "./adapters/vercel.js";
17
+ export { startServer, toNodeHandler, toFetchHandler } from "./adapters/standalone.js";
17
18
  export * from "./dev.js";
18
19
  export * from "./serve.js";
20
+ export * from "./semantic/index.js";
19
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AACtF,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -14,5 +14,7 @@ export * from "./utils.js";
14
14
  export * from "./adapters/node.js";
15
15
  export * from "./adapters/fetch.js";
16
16
  export * from "./adapters/vercel.js";
17
+ export { startServer, toNodeHandler, toFetchHandler } from "./adapters/standalone.js";
17
18
  export * from "./dev.js";
18
19
  export * from "./serve.js";
20
+ export * from "./semantic/index.js";
package/dist/openapi.js CHANGED
@@ -168,7 +168,6 @@ const normalizeInfo = (options) => {
168
168
  };
169
169
  };
170
170
  export const buildOpenApiDocument = (endpoints, options) => {
171
- var _a;
172
171
  const document = {
173
172
  openapi: "3.1.0",
174
173
  info: normalizeInfo(options),
@@ -182,7 +181,7 @@ export const buildOpenApiDocument = (endpoints, options) => {
182
181
  }
183
182
  const path = endpoint.metadata.path || "/";
184
183
  const method = endpoint.method.toLowerCase();
185
- const pathItem = ((_a = document.paths)[path] ?? (_a[path] = {}));
184
+ const pathItem = (document.paths[path] ??= {});
186
185
  const operation = toOperation(endpoint, "Response");
187
186
  if (endpoint.metadata.requiresAuth) {
188
187
  needsSecurityScheme = true;
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAmB,MAAM,KAAK,CAAC;AAEzC,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EAKX,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,YAAY,EAGb,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAOrD,OAAO,EAAE,KAAK,kBAAkB,EAAqB,MAAM,WAAW,CAAC;AA4MvE,MAAM,WAAW,sBAAsB,CACrC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,KAAK,SAAS,WAAW;IAEzB,QAAQ,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACnD,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;IACtC,cAAc,CAAC,EAAE,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtD,iBAAiB,EAAE,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;IAChE,YAAY,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,eAAe,GAC1B,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,KAAK,SAAS,WAAW,EAEzB,SAAS,sBAAsB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAC/C,OAAO,CAAC,aAAa,CAqTvB,CAAC;AAEF,UAAU,cAAc,CACtB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,KAAK,SAAS,WAAW;IAEzB,MAAM,EAAE,OAAO,aAAa,EAAE,WAAW,CAAC;IAC1C,iBAAiB,EAAE,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;IAChE,cAAc,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;IACtC,YAAY,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,cAAc,CAAC,EAAE,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtD,KAAK,CAAC,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,KAAK,SAAS,WAAW,EACzB,iIAUC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAG,YA0CpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,MAAM,MAAM,EACZ,cAAc,MAAM,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,EACvD,UAAU,cAAc;;;;;;;;;;;;;;;;;;;;;CA8BzB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,MAAM,MAAM,EACZ,aAAa,MAAM,EACnB,UAAU,WAAW;;;;;;;;;;;;;;;;;;;;;;;;CAyBmD,CAAC"}
package/dist/pipeline.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { createTenantScope, warnTenantMisconfiguration } from './tenant.js';
2
+ import { warnTenantMisconfiguration } from './tenant.js';
3
+ import { applySemanticTenantRuntime } from './semantic/utils/tenant-runtime.js';
3
4
  import { generateRequestId } from './utils.js';
4
5
  import { buildOpenApiDocument } from './openapi.js';
5
6
  import { buildDocsHtml } from './docs-ui.js';
@@ -259,7 +260,7 @@ export const executeEndpoint = async (options) => {
259
260
  durationMs: Date.now() - startedAt,
260
261
  error: new Error(errorMessage),
261
262
  });
262
- return createErrorResponse(403, 'UNAUTHORIZED', errorMessage, {
263
+ return createErrorResponse(403, 'FORBIDDEN', errorMessage, {
263
264
  reason: 'missing_tenant_context',
264
265
  tenant_required: true,
265
266
  }, { 'x-request-id': requestId });
@@ -268,26 +269,13 @@ export const executeEndpoint = async (options) => {
268
269
  context.tenantId = tenantId;
269
270
  const mode = activeTenantConfig.mode ?? 'manual';
270
271
  const column = activeTenantConfig.column;
271
- if (mode === 'auto-inject' && column) {
272
- const contextValues = context;
273
- for (const key of Object.keys(contextValues)) {
274
- const value = contextValues[key];
275
- if (value && typeof value === 'object' && 'table' in value && typeof value.table === 'function') {
276
- contextValues[key] = createTenantScope(value, {
277
- tenantId,
278
- column,
279
- });
280
- }
281
- }
282
- }
283
- else if (mode === 'manual') {
284
- warnTenantMisconfiguration({
285
- queryKey: endpoint.key,
286
- hasTenantConfig: true,
287
- hasTenantId: true,
288
- mode: 'manual',
289
- });
290
- }
272
+ applySemanticTenantRuntime(context, {
273
+ queryKey: endpoint.key,
274
+ metadata: metadataWithAuth,
275
+ tenantId,
276
+ mode,
277
+ column,
278
+ });
291
279
  }
292
280
  else if (!tenantRequired) {
293
281
  warnTenantMisconfiguration({
@@ -12,9 +12,7 @@
12
12
  * logging, and analytics work with any query backend.
13
13
  */
14
14
  export class ServeQueryLogger {
15
- constructor() {
16
- this.listeners = new Set();
17
- }
15
+ listeners = new Set();
18
16
  /**
19
17
  * Subscribe to query events.
20
18
  * @returns Unsubscribe function.
@@ -1,6 +1,7 @@
1
1
  export class MemoryRateLimitStore {
2
- constructor(cleanupIntervalMs = 60000) {
3
- this.entries = new Map();
2
+ entries = new Map();
3
+ cleanupTimer;
4
+ constructor(cleanupIntervalMs = 60_000) {
4
5
  // Periodic cleanup of expired entries to prevent memory leaks
5
6
  this.cleanupTimer = setInterval(() => {
6
7
  const now = Date.now();
@@ -72,7 +73,7 @@ const defaultKeyExtractor = (ctx) => {
72
73
  * ```
73
74
  */
74
75
  export const rateLimit = (config = {}) => {
75
- const windowMs = config.windowMs ?? 60000;
76
+ const windowMs = config.windowMs ?? 60_000;
76
77
  const max = config.max ?? 100;
77
78
  const keyBy = config.keyBy ?? defaultKeyExtractor;
78
79
  const store = config.store ?? new MemoryRateLimitStore();
package/dist/router.js CHANGED
@@ -11,9 +11,10 @@ export const applyBasePath = (basePath, path) => {
11
11
  return combined.replace(/\/+/g, "/").replace(/\/$/, combined === "/" ? "/" : "");
12
12
  };
13
13
  export class ServeRouter {
14
+ basePath;
15
+ routes = [];
14
16
  constructor(basePath = "") {
15
17
  this.basePath = basePath;
16
- this.routes = [];
17
18
  }
18
19
  list() {
19
20
  return [...this.routes];
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Converts a DatasetInstance into a standard ServeEndpoint for semantic queries.
3
+ *
4
+ * The generated endpoint is a POST handler that:
5
+ * - Accepts dimensions, measures, filters, orderBy, limit, offset, by
6
+ * - Validates requested dimensions/measures/filters against the dataset contract
7
+ * - Executes via QueryBuilderFactoryLike
8
+ * - Applies Serve-managed tenant filtering when configured
9
+ * - Returns { data } or { data, meta } based on headers
10
+ */
11
+ import { z } from 'zod';
12
+ import type { AuthContext, ServeEndpoint } from '../../types.js';
13
+ import type { QueryBuilderFactoryLike } from '@hypequery/datasets';
14
+ import { type DatasetEntry } from './utils/dataset-entry.js';
15
+ export type { DatasetEntry } from './utils/dataset-entry.js';
16
+ declare const datasetResultSchema: z.ZodObject<{
17
+ data: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">;
18
+ meta: z.ZodOptional<z.ZodObject<{
19
+ timingMs: z.ZodOptional<z.ZodNumber>;
20
+ sql: z.ZodOptional<z.ZodString>;
21
+ tenant: z.ZodOptional<z.ZodString>;
22
+ rowCount: z.ZodOptional<z.ZodNumber>;
23
+ pagination: z.ZodOptional<z.ZodObject<{
24
+ limit: z.ZodNumber;
25
+ offset: z.ZodNumber;
26
+ hasMore: z.ZodBoolean;
27
+ }, "strip", z.ZodTypeAny, {
28
+ limit: number;
29
+ offset: number;
30
+ hasMore: boolean;
31
+ }, {
32
+ limit: number;
33
+ offset: number;
34
+ hasMore: boolean;
35
+ }>>;
36
+ }, "strip", z.ZodTypeAny, {
37
+ tenant?: string | undefined;
38
+ timingMs?: number | undefined;
39
+ sql?: string | undefined;
40
+ rowCount?: number | undefined;
41
+ pagination?: {
42
+ limit: number;
43
+ offset: number;
44
+ hasMore: boolean;
45
+ } | undefined;
46
+ }, {
47
+ tenant?: string | undefined;
48
+ timingMs?: number | undefined;
49
+ sql?: string | undefined;
50
+ rowCount?: number | undefined;
51
+ pagination?: {
52
+ limit: number;
53
+ offset: number;
54
+ hasMore: boolean;
55
+ } | undefined;
56
+ }>>;
57
+ }, "strip", z.ZodTypeAny, {
58
+ data: Record<string, unknown>[];
59
+ meta?: {
60
+ tenant?: string | undefined;
61
+ timingMs?: number | undefined;
62
+ sql?: string | undefined;
63
+ rowCount?: number | undefined;
64
+ pagination?: {
65
+ limit: number;
66
+ offset: number;
67
+ hasMore: boolean;
68
+ } | undefined;
69
+ } | undefined;
70
+ }, {
71
+ data: Record<string, unknown>[];
72
+ meta?: {
73
+ tenant?: string | undefined;
74
+ timingMs?: number | undefined;
75
+ sql?: string | undefined;
76
+ rowCount?: number | undefined;
77
+ pagination?: {
78
+ limit: number;
79
+ offset: number;
80
+ hasMore: boolean;
81
+ } | undefined;
82
+ } | undefined;
83
+ }>;
84
+ export declare function createDatasetEndpoint<TAuth extends AuthContext>(name: string, entry: DatasetEntry<TAuth>, builderFactory: QueryBuilderFactoryLike): ServeEndpoint<z.ZodTypeAny, typeof datasetResultSchema, any, TAuth, any>;
85
+ //# sourceMappingURL=dataset-endpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset-endpoint.d.ts","sourceRoot":"","sources":["../../../src/semantic/datasets/dataset-endpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EACV,WAAW,EAGX,aAAa,EAEd,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EACV,uBAAuB,EACxB,MAAM,qBAAqB,CAAC;AAY7B,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlF,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAkB7D,QAAA,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGvB,CAAC;AAMH,wBAAgB,qBAAqB,CAAC,KAAK,SAAS,WAAW,EAC7D,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAC1B,cAAc,EAAE,uBAAuB,GACtC,aAAa,CAAC,CAAC,CAAC,UAAU,EAAE,OAAO,mBAAmB,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,CAoG1E"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Converts a DatasetInstance into a standard ServeEndpoint for semantic queries.
3
+ *
4
+ * The generated endpoint is a POST handler that:
5
+ * - Accepts dimensions, measures, filters, orderBy, limit, offset, by
6
+ * - Validates requested dimensions/measures/filters against the dataset contract
7
+ * - Executes via QueryBuilderFactoryLike
8
+ * - Applies Serve-managed tenant filtering when configured
9
+ * - Returns { data } or { data, meta } based on headers
10
+ */
11
+ import { z } from 'zod';
12
+ import { runDatasetQuery, validateDatasetQuery, } from '@hypequery/datasets/internal';
13
+ import { ServeHttpError } from '../../errors.js';
14
+ import { resolveSemanticExecutionRuntime, resolveSemanticQueryBuilder, } from '../query-builder-context.js';
15
+ import { buildDatasetQueryDescription } from './utils/dataset-query-metadata.js';
16
+ import { resolveDatasetEntry } from './utils/dataset-entry.js';
17
+ import { buildDatasetInputSchema } from './utils/semantic-input-schema.js';
18
+ // ---------------------------------------------------------------------------
19
+ // Zod schemas for dataset query input / output
20
+ // ---------------------------------------------------------------------------
21
+ const datasetResultMetaSchema = z.object({
22
+ timingMs: z.number().optional(),
23
+ sql: z.string().optional(),
24
+ tenant: z.string().optional(),
25
+ rowCount: z.number().optional(),
26
+ pagination: z.object({
27
+ limit: z.number(),
28
+ offset: z.number(),
29
+ hasMore: z.boolean(),
30
+ }).optional(),
31
+ }).optional();
32
+ const datasetResultSchema = z.object({
33
+ data: z.array(z.record(z.unknown())),
34
+ meta: datasetResultMetaSchema,
35
+ });
36
+ // ---------------------------------------------------------------------------
37
+ // Factory
38
+ // ---------------------------------------------------------------------------
39
+ export function createDatasetEndpoint(name, entry, builderFactory) {
40
+ const resolved = resolveDatasetEntry(entry);
41
+ const ds = resolved.dataset;
42
+ const effectiveMaxLimit = resolved.maxLimit ?? ds.limits?.maxResultSize ?? 1000;
43
+ // Build a schema whose dimension/measure/filter fields are enumerated from
44
+ // this dataset's contract, so OpenAPI/docs and clients see the valid fields.
45
+ const datasetQueryInputSchema = buildDatasetInputSchema(ds);
46
+ const metadata = {
47
+ path: '', // filled by router.register
48
+ method: 'POST',
49
+ name: name,
50
+ summary: `Query the "${name}" semantic dataset`,
51
+ description: buildDatasetQueryDescription(ds, effectiveMaxLimit),
52
+ tags: ['datasets'],
53
+ requiresAuth: resolved.auth !== null ? undefined : false,
54
+ requiredRoles: resolved.requiredRoles,
55
+ requiredScopes: resolved.requiredScopes,
56
+ cacheTtlMs: resolved.cache,
57
+ visibility: 'public',
58
+ custom: {
59
+ usesServeTenantRuntime: true,
60
+ },
61
+ };
62
+ const handler = async (ctx) => {
63
+ const semanticContext = ctx;
64
+ const input = ctx.input ?? {};
65
+ const start = Date.now();
66
+ const runtime = resolveSemanticExecutionRuntime(semanticContext);
67
+ // Validate
68
+ const query = {
69
+ dimensions: input.dimensions,
70
+ measures: input.measures,
71
+ filters: input.filters,
72
+ orderBy: input.orderBy,
73
+ limit: Math.min(input.limit ?? effectiveMaxLimit, effectiveMaxLimit),
74
+ offset: input.offset,
75
+ by: input.by,
76
+ };
77
+ const executionContext = runtime ? { runtime } : undefined;
78
+ const validation = validateDatasetQuery(ds, query, executionContext);
79
+ if (!validation.valid) {
80
+ throw new ServeHttpError(400, 'VALIDATION_ERROR', validation.errors.join('; '));
81
+ }
82
+ // Build query
83
+ const runtimeBuilderFactory = resolveSemanticQueryBuilder(semanticContext, builderFactory);
84
+ if (ctx.tenantId) {
85
+ if (!runtime?.tenant || !ds.tenantKey) {
86
+ throw new ServeHttpError(500, 'INTERNAL_SERVER_ERROR', `Dataset endpoint "${name}" requires dataset tenantKey and serve tenant runtime when tenant isolation is enabled.`);
87
+ }
88
+ }
89
+ const result = await runDatasetQuery(ds, query, {
90
+ builderFactory: runtimeBuilderFactory,
91
+ context: executionContext,
92
+ });
93
+ const timingMs = Date.now() - start;
94
+ // Meta — opt in via the `includeMeta` input field or the x-include-meta header.
95
+ const includeMeta = input.includeMeta === true
96
+ || ctx.request?.headers?.['x-include-meta'] === 'true';
97
+ return {
98
+ data: result.data,
99
+ meta: includeMeta ? {
100
+ ...(result.meta ?? {}),
101
+ timingMs,
102
+ } : undefined,
103
+ };
104
+ };
105
+ return {
106
+ key: name,
107
+ method: 'POST',
108
+ inputSchema: datasetQueryInputSchema,
109
+ outputSchema: datasetResultSchema,
110
+ handler,
111
+ query: undefined,
112
+ middlewares: (resolved.middlewares ?? []),
113
+ auth: resolved.auth ?? null,
114
+ tenant: resolved.tenant,
115
+ metadata,
116
+ cacheTtlMs: resolved.cache ?? null,
117
+ defaultHeaders: undefined,
118
+ requiredRoles: resolved.requiredRoles,
119
+ requiredScopes: resolved.requiredScopes,
120
+ };
121
+ }
@@ -0,0 +1,6 @@
1
+ export { dataset, dimension, measure, belongsTo, hasMany, hasOne, sum, count, countDistinct, avg, min, max, divide, multiply, subtract, add, nullIfZero, coalesce, round, floor, ceil, eq, neq, gt, gte, lt, lte, inList, notInList, between, like, asc, desc, filter, order, createDatasetRegistry, } from '@hypequery/datasets';
2
+ export type { FieldType, DimensionType, DimensionOptions, DimensionDefinition, MeasureOptions, MeasureDefinition, InferDimensionType, RelationshipKind, RelationshipDefinition, AggregationType, MeasureAggregation, AggregationSpec, FormulaExpr, DerivedMetricSpec, TimeGrain, MetricRef, BaseMetricRef, DerivedMetricRef, GrainedMetricRef, MetricContract, MetricFilter, MetricOrderBy, MetricQuery, DatasetQuery, MetricResultMeta, MetricResult, DatasetQueryResult, MetricHandle, ExecutionContext, SemanticExecutionRuntime, SemanticTenantRuntime, SemanticFilterDefinition, SemanticFiltersDefinition, DatasetConfig, DatasetLimits, DatasetInstance, BaseMetricConfig, DerivedMetricConfig, DatasetRegistryInstance, DatasetFieldNames, } from '@hypequery/datasets';
3
+ export { createMetricEndpoint } from './metric-endpoint.js';
4
+ export { createDatasetEndpoint } from './dataset-endpoint.js';
5
+ export type { DatasetEntry } from './dataset-endpoint.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/semantic/datasets/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,OAAO,EACP,SAAS,EACT,OAAO,EACP,SAAS,EACT,OAAO,EACP,MAAM,EACN,GAAG,EACH,KAAK,EACL,aAAa,EACb,GAAG,EACH,GAAG,EACH,GAAG,EACH,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,GAAG,EACH,UAAU,EACV,QAAQ,EACR,KAAK,EACL,KAAK,EACL,IAAI,EACJ,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,MAAM,EACN,SAAS,EACT,OAAO,EACP,IAAI,EACJ,GAAG,EACH,IAAI,EACJ,MAAM,EACN,KAAK,EACL,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACV,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,5 @@
1
+ // Re-export public datasets APIs for convenience
2
+ export { dataset, dimension, measure, belongsTo, hasMany, hasOne, sum, count, countDistinct, avg, min, max, divide, multiply, subtract, add, nullIfZero, coalesce, round, floor, ceil, eq, neq, gt, gte, lt, lte, inList, notInList, between, like, asc, desc, filter, order, createDatasetRegistry, } from '@hypequery/datasets';
3
+ // Serve-specific endpoint integration
4
+ export { createMetricEndpoint } from './metric-endpoint.js';
5
+ export { createDatasetEndpoint } from './dataset-endpoint.js';
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Converts a MetricRef into a standard ServeEndpoint.
3
+ *
4
+ * The generated endpoint is a POST handler that:
5
+ * - Validates dimensions/filters against the metric's contract
6
+ * - Calls DatasetClient.execute() with the parsed query + tenant context
7
+ * - Returns { data } or { data, meta } based on headers
8
+ */
9
+ import { z } from 'zod';
10
+ import type { AuthContext, MetricEntry, ServeEndpoint } from '../../types.js';
11
+ import type { DatasetClient, QueryBuilderFactoryLike } from '@hypequery/datasets';
12
+ declare const metricResultSchema: z.ZodObject<{
13
+ data: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>, "many">;
14
+ meta: z.ZodOptional<z.ZodObject<{
15
+ timingMs: z.ZodOptional<z.ZodNumber>;
16
+ sql: z.ZodOptional<z.ZodString>;
17
+ tenant: z.ZodOptional<z.ZodString>;
18
+ rowCount: z.ZodOptional<z.ZodNumber>;
19
+ pagination: z.ZodOptional<z.ZodObject<{
20
+ limit: z.ZodNumber;
21
+ offset: z.ZodNumber;
22
+ hasMore: z.ZodBoolean;
23
+ }, "strip", z.ZodTypeAny, {
24
+ limit: number;
25
+ offset: number;
26
+ hasMore: boolean;
27
+ }, {
28
+ limit: number;
29
+ offset: number;
30
+ hasMore: boolean;
31
+ }>>;
32
+ }, "strip", z.ZodTypeAny, {
33
+ tenant?: string | undefined;
34
+ timingMs?: number | undefined;
35
+ sql?: string | undefined;
36
+ rowCount?: number | undefined;
37
+ pagination?: {
38
+ limit: number;
39
+ offset: number;
40
+ hasMore: boolean;
41
+ } | undefined;
42
+ }, {
43
+ tenant?: string | undefined;
44
+ timingMs?: number | undefined;
45
+ sql?: string | undefined;
46
+ rowCount?: number | undefined;
47
+ pagination?: {
48
+ limit: number;
49
+ offset: number;
50
+ hasMore: boolean;
51
+ } | undefined;
52
+ }>>;
53
+ }, "strip", z.ZodTypeAny, {
54
+ data: Record<string, unknown>[];
55
+ meta?: {
56
+ tenant?: string | undefined;
57
+ timingMs?: number | undefined;
58
+ sql?: string | undefined;
59
+ rowCount?: number | undefined;
60
+ pagination?: {
61
+ limit: number;
62
+ offset: number;
63
+ hasMore: boolean;
64
+ } | undefined;
65
+ } | undefined;
66
+ }, {
67
+ data: Record<string, unknown>[];
68
+ meta?: {
69
+ tenant?: string | undefined;
70
+ timingMs?: number | undefined;
71
+ sql?: string | undefined;
72
+ rowCount?: number | undefined;
73
+ pagination?: {
74
+ limit: number;
75
+ offset: number;
76
+ hasMore: boolean;
77
+ } | undefined;
78
+ } | undefined;
79
+ }>;
80
+ export declare function createMetricEndpoint<TAuth extends AuthContext>(name: string, entry: MetricEntry<TAuth>, analytics: DatasetClient, defaultBuilderFactory: QueryBuilderFactoryLike): ServeEndpoint<z.ZodTypeAny, typeof metricResultSchema, any, TAuth, any>;
81
+ export {};
82
+ //# sourceMappingURL=metric-endpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric-endpoint.d.ts","sourceRoot":"","sources":["../../../src/semantic/datasets/metric-endpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EACV,WAAW,EAIX,WAAW,EACX,aAAa,EAGd,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAsB,aAAa,EAAgC,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAwBpI,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGtB,CAAC;AAoDH,wBAAgB,oBAAoB,CAAC,KAAK,SAAS,WAAW,EAC5D,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EACzB,SAAS,EAAE,aAAa,EACxB,qBAAqB,EAAE,uBAAuB,GAC7C,aAAa,CAAC,CAAC,CAAC,UAAU,EAAE,OAAO,kBAAkB,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,CA4GzE"}