@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.
- package/README.md +138 -879
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js +3 -5
- package/dist/adapters/standalone.d.ts +41 -0
- package/dist/adapters/standalone.d.ts.map +1 -0
- package/dist/adapters/standalone.js +46 -0
- package/dist/auth.d.ts +59 -83
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +136 -102
- package/dist/client-config.d.ts +3 -2
- package/dist/client-config.d.ts.map +1 -1
- package/dist/client-config.js +4 -2
- package/dist/errors.js +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/openapi.js +1 -2
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +10 -22
- package/dist/query-logger.js +1 -3
- package/dist/rate-limit.js +4 -3
- package/dist/router.js +2 -1
- package/dist/semantic/datasets/dataset-endpoint.d.ts +85 -0
- package/dist/semantic/datasets/dataset-endpoint.d.ts.map +1 -0
- package/dist/semantic/datasets/dataset-endpoint.js +121 -0
- package/dist/semantic/datasets/index.d.ts +6 -0
- package/dist/semantic/datasets/index.d.ts.map +1 -0
- package/dist/semantic/datasets/index.js +5 -0
- package/dist/semantic/datasets/metric-endpoint.d.ts +82 -0
- package/dist/semantic/datasets/metric-endpoint.d.ts.map +1 -0
- package/dist/semantic/datasets/metric-endpoint.js +159 -0
- package/dist/semantic/datasets/utils/dataset-entry.d.ts +24 -0
- package/dist/semantic/datasets/utils/dataset-entry.d.ts.map +1 -0
- package/dist/semantic/datasets/utils/dataset-entry.js +15 -0
- package/dist/semantic/datasets/utils/dataset-query-metadata.d.ts +3 -0
- package/dist/semantic/datasets/utils/dataset-query-metadata.d.ts.map +1 -0
- package/dist/semantic/datasets/utils/dataset-query-metadata.js +12 -0
- package/dist/semantic/datasets/utils/semantic-input-schema.d.ts +107 -0
- package/dist/semantic/datasets/utils/semantic-input-schema.d.ts.map +1 -0
- package/dist/semantic/datasets/utils/semantic-input-schema.js +87 -0
- package/dist/semantic/index.d.ts +2 -0
- package/dist/semantic/index.d.ts.map +1 -0
- package/dist/semantic/index.js +1 -0
- package/dist/semantic/query-builder-context.d.ts +20 -0
- package/dist/semantic/query-builder-context.d.ts.map +1 -0
- package/dist/semantic/query-builder-context.js +66 -0
- package/dist/semantic/utils/tenant-runtime.d.ts +11 -0
- package/dist/semantic/utils/tenant-runtime.d.ts.map +1 -0
- package/dist/semantic/utils/tenant-runtime.js +48 -0
- package/dist/serve.d.ts +2 -2
- package/dist/serve.d.ts.map +1 -1
- package/dist/server/api-builder.d.ts +5 -0
- package/dist/server/api-builder.d.ts.map +1 -0
- package/dist/server/api-builder.js +76 -0
- package/dist/server/builder.d.ts.map +1 -1
- package/dist/server/builder.js +11 -1
- package/dist/server/create-api.d.ts +32 -0
- package/dist/server/create-api.d.ts.map +1 -0
- package/dist/server/create-api.js +211 -0
- package/dist/server/define-serve.d.ts +21 -2
- package/dist/server/define-serve.d.ts.map +1 -1
- package/dist/server/define-serve.js +53 -84
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/init-serve.d.ts +1 -1
- package/dist/server/init-serve.d.ts.map +1 -1
- package/dist/server/init-serve.js +7 -2
- package/dist/type-tests/builder.test-d.d.ts +4 -0
- package/dist/type-tests/builder.test-d.d.ts.map +1 -1
- package/dist/type-tests/builder.test-d.js +16 -1
- package/dist/type-tests/semantic.test-d.d.ts +2 -0
- package/dist/type-tests/semantic.test-d.d.ts.map +1 -0
- package/dist/type-tests/semantic.test-d.js +59 -0
- package/dist/types.d.ts +227 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -3
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { mergeTags } from "../utils.js";
|
|
2
|
+
import { applyBasePath, normalizeRoutePath } from "../router.js";
|
|
3
|
+
import { mapEndpointToToolkit } from "./mapper.js";
|
|
4
|
+
export const createAPImethods = (queryEntries, queryLogger, router, authStrategies, globalMiddlewares, executeQuery, handler, basePath) => {
|
|
5
|
+
const api = {
|
|
6
|
+
queries: queryEntries,
|
|
7
|
+
queryLogger,
|
|
8
|
+
manifest: () => {
|
|
9
|
+
const manifest = {};
|
|
10
|
+
for (const [key, endpoint] of Object.entries(queryEntries)) {
|
|
11
|
+
manifest[key] = {
|
|
12
|
+
method: endpoint.method,
|
|
13
|
+
// queryEntries store the pre-basePath route; re-apply so the manifest
|
|
14
|
+
// carries the full request path clients should call.
|
|
15
|
+
path: applyBasePath(basePath, endpoint.metadata.path),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return manifest;
|
|
19
|
+
},
|
|
20
|
+
route: (path, endpoint, options = {}) => {
|
|
21
|
+
if (!endpoint) {
|
|
22
|
+
throw new Error("Endpoint definition is required when registering a route");
|
|
23
|
+
}
|
|
24
|
+
const method = options?.method ?? endpoint.method;
|
|
25
|
+
const normalizedPath = normalizeRoutePath(path);
|
|
26
|
+
const fallbackRequiresAuth = endpoint.auth
|
|
27
|
+
? true
|
|
28
|
+
: authStrategies.length > 0
|
|
29
|
+
? true
|
|
30
|
+
: undefined;
|
|
31
|
+
const requiresAuth = options?.requiresAuth ?? endpoint.metadata.requiresAuth ?? fallbackRequiresAuth;
|
|
32
|
+
const visibility = options?.visibility ?? endpoint.metadata.visibility ?? "public";
|
|
33
|
+
const metadata = {
|
|
34
|
+
...endpoint.metadata,
|
|
35
|
+
path: normalizedPath,
|
|
36
|
+
method,
|
|
37
|
+
name: options?.name ?? endpoint.metadata.name ?? endpoint.key,
|
|
38
|
+
summary: options?.summary ?? endpoint.metadata.summary,
|
|
39
|
+
description: options?.description ?? endpoint.metadata.description,
|
|
40
|
+
tags: mergeTags(endpoint.metadata.tags, options?.tags),
|
|
41
|
+
requiresAuth,
|
|
42
|
+
visibility,
|
|
43
|
+
};
|
|
44
|
+
const middlewares = [...endpoint.middlewares, ...(options?.middlewares ?? [])];
|
|
45
|
+
const registeredEndpoint = {
|
|
46
|
+
...endpoint,
|
|
47
|
+
method,
|
|
48
|
+
metadata,
|
|
49
|
+
middlewares,
|
|
50
|
+
};
|
|
51
|
+
router.register(registeredEndpoint);
|
|
52
|
+
return api;
|
|
53
|
+
},
|
|
54
|
+
use: (middleware) => {
|
|
55
|
+
globalMiddlewares.push(middleware);
|
|
56
|
+
return api;
|
|
57
|
+
},
|
|
58
|
+
useAuth: (strategy) => {
|
|
59
|
+
authStrategies.push(strategy);
|
|
60
|
+
router.markRoutesRequireAuth();
|
|
61
|
+
return api;
|
|
62
|
+
},
|
|
63
|
+
execute: executeQuery,
|
|
64
|
+
client: executeQuery,
|
|
65
|
+
run: executeQuery,
|
|
66
|
+
describe: () => {
|
|
67
|
+
const description = {
|
|
68
|
+
basePath: basePath || undefined,
|
|
69
|
+
queries: router.list().map(mapEndpointToToolkit),
|
|
70
|
+
};
|
|
71
|
+
return description;
|
|
72
|
+
},
|
|
73
|
+
handler,
|
|
74
|
+
};
|
|
75
|
+
return api;
|
|
76
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/server/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,UAAU,
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/server/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,UAAU,EAEV,YAAY,EAEZ,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,YAAY,EACZ,oBAAoB,EAGrB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAYtD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,EACjD,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,KAAK,SAAS,WAAW,EAEzB,cAAc,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EACzD,aAAa,gBAAgB,EAC7B,aAAa,MAAM,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC,EACnD,QAAQ,WAAW,EACnB,gBAAgB,YAAY,CAAC,KAAK,CAAC,EAAE,EACrC,mBAAmB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,EAC/D,cAAc,oBAAoB,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,QAAQ,CAAC,EACzF,SAAS,YAAY,EACrB,UAAU,MAAM,KACf,YAAY,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,CAoG3E,CAAC"}
|
package/dist/server/builder.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mergeTags } from "../utils.js";
|
|
2
|
-
import { normalizeRoutePath } from "../router.js";
|
|
2
|
+
import { applyBasePath, normalizeRoutePath } from "../router.js";
|
|
3
3
|
import { mapEndpointToToolkit } from "./mapper.js";
|
|
4
4
|
const loadNodeAdapter = async () => {
|
|
5
5
|
if (typeof require !== "undefined") {
|
|
@@ -13,6 +13,16 @@ export const createBuilderMethods = (queryEntries, queryLogger, routeConfig, rou
|
|
|
13
13
|
basePath: basePath || undefined,
|
|
14
14
|
queryLogger,
|
|
15
15
|
_routeConfig: routeConfig,
|
|
16
|
+
manifest: () => {
|
|
17
|
+
const manifest = {};
|
|
18
|
+
for (const [key, endpoint] of Object.entries(queryEntries)) {
|
|
19
|
+
manifest[key] = {
|
|
20
|
+
method: routeConfig[key]?.method ?? endpoint.method,
|
|
21
|
+
path: applyBasePath(basePath, endpoint.metadata.path),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return manifest;
|
|
25
|
+
},
|
|
16
26
|
route: (path, endpoint, options = {}) => {
|
|
17
27
|
if (!endpoint) {
|
|
18
28
|
throw new Error("Endpoint definition is required when registering a route");
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AuthContext, HypeQueryAPI, ServeEndpointMap, ServeQueriesMap, ServeConfig, MetricsConfig, DatasetsConfig, ServeSemanticEndpointMap } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a transport-agnostic API definition.
|
|
4
|
+
*
|
|
5
|
+
* `createAPI` sets up queries, auth, tenancy, caching, and middleware —
|
|
6
|
+
* without binding to any HTTP server or runtime. Use standalone transport
|
|
7
|
+
* functions to serve the API:
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { createAPI } from '@hypequery/serve';
|
|
12
|
+
* import { startServer, toFetchHandler, toNodeHandler } from '@hypequery/serve';
|
|
13
|
+
*
|
|
14
|
+
* const api = createAPI({
|
|
15
|
+
* auth: jwtStrategy,
|
|
16
|
+
* queries: {
|
|
17
|
+
* revenue: { query: async () => db.table('orders').sum('amount').execute() },
|
|
18
|
+
* },
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Standalone server
|
|
22
|
+
* startServer(api, { port: 3000 });
|
|
23
|
+
*
|
|
24
|
+
* // Express / Node.js middleware
|
|
25
|
+
* app.use('/analytics', toNodeHandler(api));
|
|
26
|
+
*
|
|
27
|
+
* // Serverless (Vercel, Cloudflare, etc.)
|
|
28
|
+
* export default toFetchHandler(api);
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare const createAPI: <TContext extends Record<string, unknown> = Record<string, unknown>, TAuth extends AuthContext = AuthContext, TQueries extends ServeQueriesMap<TContext, TAuth> = Record<never, never>, TMetrics extends MetricsConfig<TAuth> = Record<never, never>, TDatasets extends DatasetsConfig<TAuth> = Record<never, never>>(config: ServeConfig<TContext, TAuth, TQueries, TMetrics, TDatasets>) => HypeQueryAPI<ServeEndpointMap<TQueries, TContext, TAuth> & ServeSemanticEndpointMap<TMetrics, TDatasets, TContext, TAuth>, TContext, TAuth>;
|
|
32
|
+
//# sourceMappingURL=create-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-api.d.ts","sourceRoot":"","sources":["../../src/server/create-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAEX,YAAY,EAGZ,gBAAgB,EAIhB,eAAe,EACf,WAAW,EACX,aAAa,EACb,cAAc,EACd,wBAAwB,EACzB,MAAM,aAAa,CAAC;AA2BrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,SAAS,GACpB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,KAAK,SAAS,WAAW,GAAG,WAAW,EACvC,QAAQ,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EACxE,QAAQ,SAAS,aAAa,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC5D,SAAS,SAAS,cAAc,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAE9D,QAAQ,WAAW,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,KAClE,YAAY,CACb,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,GACvC,wBAAwB,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,EAClE,QAAQ,EACR,KAAK,CA8ON,CAAC"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { createEndpoint } from "../endpoint.js";
|
|
2
|
+
import { ServeRouter, applyBasePath, normalizeRoutePath } from "../router.js";
|
|
3
|
+
import { ensureArray } from "../utils.js";
|
|
4
|
+
import { ServeQueryLogger, formatQueryEvent, formatQueryEventJSON } from "../query-logger.js";
|
|
5
|
+
import { createServeHandler } from "../pipeline.js";
|
|
6
|
+
import { createDocsEndpoint, createOpenApiEndpoint } from "../pipeline.js";
|
|
7
|
+
import { resolveCorsConfig } from "../cors.js";
|
|
8
|
+
import { createExecuteQuery } from "./execute-query.js";
|
|
9
|
+
import { createAPImethods } from "./api-builder.js";
|
|
10
|
+
import { createDatasetClient } from "@hypequery/datasets";
|
|
11
|
+
import { createMetricEndpoint, createDatasetEndpoint } from "../semantic/datasets/index.js";
|
|
12
|
+
import { attachSemanticQueryBuilder, extractQueryBuilderFromContext } from "../semantic/query-builder-context.js";
|
|
13
|
+
const assertSemanticKeyAvailable = (queryEntries, key, kind) => {
|
|
14
|
+
if (key in queryEntries) {
|
|
15
|
+
throw new Error(`createAPI: ${kind} "${key}" collides with an existing query key. ` +
|
|
16
|
+
`Rename the ${kind} or the query to keep api.queries and api.execute() unambiguous.`);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Create a transport-agnostic API definition.
|
|
21
|
+
*
|
|
22
|
+
* `createAPI` sets up queries, auth, tenancy, caching, and middleware —
|
|
23
|
+
* without binding to any HTTP server or runtime. Use standalone transport
|
|
24
|
+
* functions to serve the API:
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { createAPI } from '@hypequery/serve';
|
|
29
|
+
* import { startServer, toFetchHandler, toNodeHandler } from '@hypequery/serve';
|
|
30
|
+
*
|
|
31
|
+
* const api = createAPI({
|
|
32
|
+
* auth: jwtStrategy,
|
|
33
|
+
* queries: {
|
|
34
|
+
* revenue: { query: async () => db.table('orders').sum('amount').execute() },
|
|
35
|
+
* },
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* // Standalone server
|
|
39
|
+
* startServer(api, { port: 3000 });
|
|
40
|
+
*
|
|
41
|
+
* // Express / Node.js middleware
|
|
42
|
+
* app.use('/analytics', toNodeHandler(api));
|
|
43
|
+
*
|
|
44
|
+
* // Serverless (Vercel, Cloudflare, etc.)
|
|
45
|
+
* export default toFetchHandler(api);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export const createAPI = (config) => {
|
|
49
|
+
const basePath = config.basePath ?? "/api/analytics";
|
|
50
|
+
const router = new ServeRouter(basePath);
|
|
51
|
+
const globalMiddlewares = [
|
|
52
|
+
...(config.middlewares ?? []),
|
|
53
|
+
];
|
|
54
|
+
const authStrategies = ensureArray(config.auth);
|
|
55
|
+
const globalTenantConfig = config.tenant;
|
|
56
|
+
const baseContextFactory = config.context;
|
|
57
|
+
// Extract queryBuilder from context.db if not provided in config
|
|
58
|
+
let resolvedQueryBuilder = config.queryBuilder;
|
|
59
|
+
let extractedFromContext = false;
|
|
60
|
+
if (!resolvedQueryBuilder && baseContextFactory && (config.metrics || config.datasets)) {
|
|
61
|
+
// If context is a static object (not a function), we can extract queryBuilder synchronously
|
|
62
|
+
if (typeof baseContextFactory !== "function") {
|
|
63
|
+
resolvedQueryBuilder = extractQueryBuilderFromContext(baseContextFactory);
|
|
64
|
+
if (resolvedQueryBuilder) {
|
|
65
|
+
extractedFromContext = true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const contextFactory = baseContextFactory || resolvedQueryBuilder
|
|
70
|
+
? async ({ request, auth }) => {
|
|
71
|
+
const baseContext = baseContextFactory
|
|
72
|
+
? typeof baseContextFactory === "function"
|
|
73
|
+
? await baseContextFactory({ request, auth })
|
|
74
|
+
: baseContextFactory
|
|
75
|
+
: {};
|
|
76
|
+
// If queryBuilder was explicitly passed in config (not extracted from context),
|
|
77
|
+
// attach it to context for backward compatibility
|
|
78
|
+
if (config.queryBuilder) {
|
|
79
|
+
return attachSemanticQueryBuilder({ ...baseContext }, config.queryBuilder);
|
|
80
|
+
}
|
|
81
|
+
// If context.db is a queryBuilder but we haven't extracted it yet,
|
|
82
|
+
// also check and attach it to the semantic runtime for consistency
|
|
83
|
+
if (!extractedFromContext && typeof baseContextFactory === "function") {
|
|
84
|
+
const maybeQueryBuilder = extractQueryBuilderFromContext(baseContext);
|
|
85
|
+
if (maybeQueryBuilder) {
|
|
86
|
+
return attachSemanticQueryBuilder({ ...baseContext }, maybeQueryBuilder);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return baseContext;
|
|
90
|
+
}
|
|
91
|
+
: undefined;
|
|
92
|
+
const hooks = (config.hooks ?? {});
|
|
93
|
+
const queryLogger = new ServeQueryLogger();
|
|
94
|
+
// Wire up production query logging if configured
|
|
95
|
+
if (config.queryLogging) {
|
|
96
|
+
if (typeof config.queryLogging === 'function') {
|
|
97
|
+
queryLogger.on(config.queryLogging);
|
|
98
|
+
}
|
|
99
|
+
else if (config.queryLogging === 'json') {
|
|
100
|
+
queryLogger.on((event) => {
|
|
101
|
+
const line = formatQueryEventJSON(event);
|
|
102
|
+
if (line)
|
|
103
|
+
console.log(line);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
queryLogger.on((event) => {
|
|
108
|
+
const line = formatQueryEvent(event);
|
|
109
|
+
if (line)
|
|
110
|
+
console.log(line);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Slow query warning
|
|
115
|
+
if (config.slowQueryThreshold != null) {
|
|
116
|
+
queryLogger.on((event) => {
|
|
117
|
+
if (event.status === 'completed' && event.durationMs && event.durationMs > config.slowQueryThreshold) {
|
|
118
|
+
console.warn(`[hypequery/slow-query] ${event.method} ${event.path} took ${event.durationMs}ms (threshold: ${config.slowQueryThreshold}ms)`);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
const openapiConfig = {
|
|
123
|
+
enabled: config.openapi?.enabled ?? true,
|
|
124
|
+
path: config.openapi?.path ?? "/openapi.json",
|
|
125
|
+
};
|
|
126
|
+
const docsConfig = {
|
|
127
|
+
enabled: config.docs?.enabled ?? true,
|
|
128
|
+
path: config.docs?.path ?? "/docs",
|
|
129
|
+
};
|
|
130
|
+
const openapiPublicPath = applyBasePath(basePath, openapiConfig.path);
|
|
131
|
+
const configuredQueries = config.queries ?? {};
|
|
132
|
+
const queryEntries = {};
|
|
133
|
+
for (const key of Object.keys(configuredQueries)) {
|
|
134
|
+
const endpoint = createEndpoint(String(key), configuredQueries[key]);
|
|
135
|
+
const routePath = normalizeRoutePath(`/queries/${String(key)}`);
|
|
136
|
+
const registeredEndpoint = {
|
|
137
|
+
...endpoint,
|
|
138
|
+
metadata: { ...endpoint.metadata, path: routePath },
|
|
139
|
+
};
|
|
140
|
+
queryEntries[key] = registeredEndpoint;
|
|
141
|
+
router.register(registeredEndpoint);
|
|
142
|
+
}
|
|
143
|
+
// Process metrics — auto-generate POST endpoints
|
|
144
|
+
if (config.metrics) {
|
|
145
|
+
const metricsEntries = config.metrics;
|
|
146
|
+
const builderFactory = resolvedQueryBuilder;
|
|
147
|
+
if (!builderFactory) {
|
|
148
|
+
throw new Error('createAPI: `queryBuilder` is required when `metrics` is provided. ' +
|
|
149
|
+
'Pass the createQueryBuilder(config) return value as `queryBuilder`, ' +
|
|
150
|
+
'or provide it via context as `context: () => ({ db: queryBuilder })`.');
|
|
151
|
+
}
|
|
152
|
+
const analytics = createDatasetClient({ queryBuilder: builderFactory });
|
|
153
|
+
for (const [name, entry] of Object.entries(metricsEntries)) {
|
|
154
|
+
assertSemanticKeyAvailable(queryEntries, name, "metric");
|
|
155
|
+
const metricEndpoint = createMetricEndpoint(name, entry, analytics, builderFactory);
|
|
156
|
+
const metricsPath = config.semanticPaths?.metrics ?? '/metrics';
|
|
157
|
+
const routePath = normalizeRoutePath(`${metricsPath}/${name}`);
|
|
158
|
+
const registeredEndpoint = {
|
|
159
|
+
...metricEndpoint,
|
|
160
|
+
metadata: { ...metricEndpoint.metadata, path: routePath },
|
|
161
|
+
};
|
|
162
|
+
queryEntries[name] = registeredEndpoint;
|
|
163
|
+
router.register(registeredEndpoint);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Process datasets — auto-generate POST endpoints for semantic dataset queries
|
|
167
|
+
if (config.datasets) {
|
|
168
|
+
const datasetEntries = config.datasets;
|
|
169
|
+
const builderFactory = resolvedQueryBuilder;
|
|
170
|
+
if (!builderFactory) {
|
|
171
|
+
throw new Error('createAPI: `queryBuilder` is required when `datasets` is provided. ' +
|
|
172
|
+
'Pass the createQueryBuilder(config) return value as `queryBuilder`, ' +
|
|
173
|
+
'or provide it via context as `context: () => ({ db: queryBuilder })`.');
|
|
174
|
+
}
|
|
175
|
+
for (const [name, entry] of Object.entries(datasetEntries)) {
|
|
176
|
+
assertSemanticKeyAvailable(queryEntries, `dataset:${name}`, "dataset");
|
|
177
|
+
const datasetEndpoint = createDatasetEndpoint(name, entry, builderFactory);
|
|
178
|
+
const datasetsPath = config.semanticPaths?.datasets ?? '/datasets';
|
|
179
|
+
const routePath = normalizeRoutePath(`${datasetsPath}/${name}/query`);
|
|
180
|
+
const registeredEndpoint = {
|
|
181
|
+
...datasetEndpoint,
|
|
182
|
+
metadata: { ...datasetEndpoint.metadata, path: routePath },
|
|
183
|
+
};
|
|
184
|
+
queryEntries[`dataset:${name}`] = registeredEndpoint;
|
|
185
|
+
router.register(registeredEndpoint);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const corsConfig = resolveCorsConfig(config.cors);
|
|
189
|
+
const handler = createServeHandler({
|
|
190
|
+
router,
|
|
191
|
+
globalMiddlewares,
|
|
192
|
+
authStrategies,
|
|
193
|
+
tenantConfig: globalTenantConfig,
|
|
194
|
+
contextFactory,
|
|
195
|
+
hooks,
|
|
196
|
+
queryLogger,
|
|
197
|
+
verboseAuthErrors: config.security?.verboseAuthErrors ?? false,
|
|
198
|
+
corsConfig,
|
|
199
|
+
});
|
|
200
|
+
const executeQuery = createExecuteQuery(queryEntries, authStrategies, contextFactory, globalMiddlewares, globalTenantConfig, hooks, queryLogger, config.security?.verboseAuthErrors ?? false);
|
|
201
|
+
const api = createAPImethods(queryEntries, queryLogger, router, authStrategies, globalMiddlewares, executeQuery, handler, basePath);
|
|
202
|
+
if (openapiConfig.enabled) {
|
|
203
|
+
const openapiEndpoint = createOpenApiEndpoint(openapiConfig.path, () => router.list(), config.openapi);
|
|
204
|
+
router.register(openapiEndpoint);
|
|
205
|
+
}
|
|
206
|
+
if (docsConfig.enabled) {
|
|
207
|
+
const docsEndpoint = createDocsEndpoint(docsConfig.path, openapiPublicPath, config.docs);
|
|
208
|
+
router.register(docsEndpoint);
|
|
209
|
+
}
|
|
210
|
+
return api;
|
|
211
|
+
};
|
|
@@ -1,3 +1,22 @@
|
|
|
1
|
-
import type { AuthContext, ServeBuilder, ServeConfig, ServeEndpointMap, ServeQueriesMap } from "../types.js";
|
|
2
|
-
|
|
1
|
+
import type { AuthContext, ServeBuilder, ServeConfig, ServeEndpointMap, ServeSemanticEndpointMap, ServeQueriesMap, MetricsConfig, DatasetsConfig } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Define and configure a serve API with embedded transport.
|
|
4
|
+
*
|
|
5
|
+
* @deprecated Prefer `createAPI()` with standalone transport functions for
|
|
6
|
+
* better separation of concerns. `defineServe()` couples API definition
|
|
7
|
+
* with the Node.js HTTP server via `.start()`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // Before (defineServe)
|
|
12
|
+
* const api = defineServe({ queries: { ... } });
|
|
13
|
+
* api.start({ port: 3000 });
|
|
14
|
+
*
|
|
15
|
+
* // After (createAPI + serve)
|
|
16
|
+
* import { createAPI, startServer } from '@hypequery/serve';
|
|
17
|
+
* const api = createAPI({ queries: { ... } });
|
|
18
|
+
* startServer(api, { port: 3000 });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare const defineServe: <TContext extends Record<string, unknown> = Record<string, unknown>, TAuth extends AuthContext = AuthContext, TQueries extends ServeQueriesMap<TContext, TAuth> = Record<never, never>, TMetrics extends MetricsConfig<TAuth> = Record<never, never>, TDatasets extends DatasetsConfig<TAuth> = Record<never, never>>(config: ServeConfig<TContext, TAuth, TQueries, TMetrics, TDatasets>) => ServeBuilder<ServeEndpointMap<TQueries, TContext, TAuth> & ServeSemanticEndpointMap<TMetrics, TDatasets, TContext, TAuth>, TContext, TAuth>;
|
|
3
22
|
//# sourceMappingURL=define-serve.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-serve.d.ts","sourceRoot":"","sources":["../../src/server/define-serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,
|
|
1
|
+
{"version":3,"file":"define-serve.d.ts","sourceRoot":"","sources":["../../src/server/define-serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,wBAAwB,EACxB,eAAe,EAEf,aAAa,EACb,cAAc,EACf,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,KAAK,SAAS,WAAW,GAAG,WAAW,EACvC,QAAQ,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EACxE,QAAQ,SAAS,aAAa,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC5D,SAAS,SAAS,cAAc,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAE9D,QAAQ,WAAW,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,KAClE,YAAY,CACb,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,GACvC,wBAAwB,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,EAClE,QAAQ,EACR,KAAK,CAqDN,CAAC"}
|
|
@@ -1,91 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { createAPI } from "./create-api.js";
|
|
2
|
+
/**
|
|
3
|
+
* Define and configure a serve API with embedded transport.
|
|
4
|
+
*
|
|
5
|
+
* @deprecated Prefer `createAPI()` with standalone transport functions for
|
|
6
|
+
* better separation of concerns. `defineServe()` couples API definition
|
|
7
|
+
* with the Node.js HTTP server via `.start()`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // Before (defineServe)
|
|
12
|
+
* const api = defineServe({ queries: { ... } });
|
|
13
|
+
* api.start({ port: 3000 });
|
|
14
|
+
*
|
|
15
|
+
* // After (createAPI + serve)
|
|
16
|
+
* import { createAPI, startServer } from '@hypequery/serve';
|
|
17
|
+
* const api = createAPI({ queries: { ... } });
|
|
18
|
+
* startServer(api, { port: 3000 });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
10
21
|
export const defineServe = (config) => {
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
];
|
|
16
|
-
const authStrategies = ensureArray(config.auth);
|
|
17
|
-
const globalTenantConfig = config.tenant;
|
|
18
|
-
const contextFactory = config.context;
|
|
19
|
-
const hooks = (config.hooks ?? {});
|
|
20
|
-
const queryLogger = new ServeQueryLogger();
|
|
21
|
-
// Wire up production query logging if configured
|
|
22
|
-
if (config.queryLogging) {
|
|
23
|
-
if (typeof config.queryLogging === 'function') {
|
|
24
|
-
queryLogger.on(config.queryLogging);
|
|
22
|
+
const api = createAPI(config);
|
|
23
|
+
const loadNodeAdapter = async () => {
|
|
24
|
+
if (typeof require !== "undefined") {
|
|
25
|
+
return require("../adapters/node.js");
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
queryLogger.on((event) => {
|
|
28
|
-
const line = formatQueryEventJSON(event);
|
|
29
|
-
if (line)
|
|
30
|
-
console.log(line);
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
queryLogger.on((event) => {
|
|
35
|
-
const line = formatQueryEvent(event);
|
|
36
|
-
if (line)
|
|
37
|
-
console.log(line);
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
// Slow query warning
|
|
42
|
-
if (config.slowQueryThreshold != null) {
|
|
43
|
-
queryLogger.on((event) => {
|
|
44
|
-
if (event.status === 'completed' && event.durationMs && event.durationMs > config.slowQueryThreshold) {
|
|
45
|
-
console.warn(`[hypequery/slow-query] ${event.method} ${event.path} took ${event.durationMs}ms (threshold: ${config.slowQueryThreshold}ms)`);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
const openapiConfig = {
|
|
50
|
-
enabled: config.openapi?.enabled ?? true,
|
|
51
|
-
path: config.openapi?.path ?? "/openapi.json",
|
|
27
|
+
return import("../adapters/node.js");
|
|
52
28
|
};
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
path: config.docs?.path ?? "/docs",
|
|
56
|
-
};
|
|
57
|
-
const openapiPublicPath = applyBasePath(basePath, openapiConfig.path);
|
|
58
|
-
const configuredQueries = config.queries ?? {};
|
|
59
|
-
const queryEntries = {};
|
|
60
|
-
const registerQuery = (key, definition) => {
|
|
61
|
-
queryEntries[key] = createEndpoint(String(key), definition);
|
|
62
|
-
};
|
|
63
|
-
for (const key of Object.keys(configuredQueries)) {
|
|
64
|
-
registerQuery(key, configuredQueries[key]);
|
|
65
|
-
}
|
|
66
|
-
const corsConfig = resolveCorsConfig(config.cors);
|
|
67
|
-
const handler = createServeHandler({
|
|
68
|
-
router,
|
|
69
|
-
globalMiddlewares,
|
|
70
|
-
authStrategies,
|
|
71
|
-
tenantConfig: globalTenantConfig,
|
|
72
|
-
contextFactory,
|
|
73
|
-
hooks,
|
|
74
|
-
queryLogger,
|
|
75
|
-
verboseAuthErrors: config.security?.verboseAuthErrors ?? false,
|
|
76
|
-
corsConfig,
|
|
77
|
-
});
|
|
78
|
-
// Track route configuration for client config extraction
|
|
29
|
+
// Extend the API with backwards-compatible ServeBuilder methods
|
|
30
|
+
const builder = api;
|
|
79
31
|
const routeConfig = {};
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (openapiConfig.enabled) {
|
|
83
|
-
const openapiEndpoint = createOpenApiEndpoint(openapiConfig.path, () => router.list(), config.openapi);
|
|
84
|
-
router.register(openapiEndpoint);
|
|
85
|
-
}
|
|
86
|
-
if (docsConfig.enabled) {
|
|
87
|
-
const docsEndpoint = createDocsEndpoint(docsConfig.path, openapiPublicPath, config.docs);
|
|
88
|
-
router.register(docsEndpoint);
|
|
32
|
+
for (const [key, endpoint] of Object.entries(api.queries)) {
|
|
33
|
+
routeConfig[key] = { method: endpoint.method };
|
|
89
34
|
}
|
|
35
|
+
Object.defineProperty(builder, "basePath", {
|
|
36
|
+
value: config.basePath ?? "/api/analytics",
|
|
37
|
+
enumerable: true,
|
|
38
|
+
configurable: true,
|
|
39
|
+
});
|
|
40
|
+
Object.defineProperty(builder, "_routeConfig", {
|
|
41
|
+
value: routeConfig,
|
|
42
|
+
enumerable: true,
|
|
43
|
+
configurable: true,
|
|
44
|
+
});
|
|
45
|
+
const originalRoute = builder.route.bind(builder);
|
|
46
|
+
builder.route = (path, endpoint, options = {}) => {
|
|
47
|
+
const result = originalRoute(path, endpoint, options);
|
|
48
|
+
const queryKey = Object.entries(api.queries).find(([_, entry]) => entry === endpoint)?.[0];
|
|
49
|
+
if (queryKey) {
|
|
50
|
+
routeConfig[queryKey] = { method: options?.method ?? endpoint.method };
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
// Add transport method that ServeBuilder expects
|
|
55
|
+
builder.start = async (options = {}) => {
|
|
56
|
+
const { startNodeServer } = await loadNodeAdapter();
|
|
57
|
+
return startNodeServer(api.handler, options);
|
|
58
|
+
};
|
|
90
59
|
return builder;
|
|
91
60
|
};
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
export { createAPI } from "./create-api.js";
|
|
1
2
|
export { defineServe } from "./define-serve.js";
|
|
2
3
|
export { initServe } from "./init-serve.js";
|
|
3
4
|
export { createExecuteQuery } from "./execute-query.js";
|
|
4
5
|
export { createBuilderMethods } from "./builder.js";
|
|
6
|
+
export { createAPImethods } from "./api-builder.js";
|
|
5
7
|
export { mapEndpointToToolkit } from "./mapper.js";
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
export { createAPI } from "./create-api.js";
|
|
1
2
|
export { defineServe } from "./define-serve.js";
|
|
2
3
|
export { initServe } from "./init-serve.js";
|
|
3
4
|
export { createExecuteQuery } from "./execute-query.js";
|
|
4
5
|
export { createBuilderMethods } from "./builder.js";
|
|
6
|
+
export { createAPImethods } from "./api-builder.js";
|
|
5
7
|
export { mapEndpointToToolkit } from "./mapper.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AuthContext, ServeContextFactory, ServeInitializer, ServeQueriesMap, ServeConfig } from "../types.js";
|
|
2
2
|
type InferInitializerContext<TFactory, TAuth extends AuthContext> = TFactory extends ServeContextFactory<infer TContext, TAuth> ? TContext : never;
|
|
3
|
-
type ServeInitializerOptions<TFactory extends ServeContextFactory<any, TAuth>, TAuth extends AuthContext> = Omit<ServeConfig<InferInitializerContext<TFactory, TAuth>, TAuth, ServeQueriesMap<InferInitializerContext<TFactory, TAuth>, TAuth>>, "queries" | "context"> & {
|
|
3
|
+
type ServeInitializerOptions<TFactory extends ServeContextFactory<any, TAuth>, TAuth extends AuthContext> = Omit<ServeConfig<InferInitializerContext<TFactory, TAuth>, TAuth, ServeQueriesMap<InferInitializerContext<TFactory, TAuth>, TAuth>, Record<never, never>, Record<never, never>>, "queries" | "context"> & {
|
|
4
4
|
context: TFactory;
|
|
5
5
|
};
|
|
6
6
|
export declare const initServe: <TFactory extends ServeContextFactory<any, TAuth>, TAuth extends AuthContext = AuthContext>(options: ServeInitializerOptions<TFactory, TAuth>) => ServeInitializer<InferInitializerContext<TFactory, TAuth>, TAuth>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-serve.d.ts","sourceRoot":"","sources":["../../src/server/init-serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAEX,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,WAAW,
|
|
1
|
+
{"version":3,"file":"init-serve.d.ts","sourceRoot":"","sources":["../../src/server/init-serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAEX,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,WAAW,EAGZ,MAAM,aAAa,CAAC;AAKrB,KAAK,uBAAuB,CAC1B,QAAQ,EACR,KAAK,SAAS,WAAW,IACvB,QAAQ,SAAS,mBAAmB,CAAC,MAAM,QAAQ,EAAE,KAAK,CAAC,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEnF,KAAK,uBAAuB,CAC1B,QAAQ,SAAS,mBAAmB,CAAC,GAAG,EAAE,KAAK,CAAC,EAChD,KAAK,SAAS,WAAW,IACvB,IAAI,CACN,WAAW,CACT,uBAAuB,CAAC,QAAQ,EAAE,KAAK,CAAC,EACxC,KAAK,EACL,eAAe,CAAC,uBAAuB,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,EAChE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EACpB,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CACrB,EACD,SAAS,GAAG,SAAS,CACtB,GAAG;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;AAU1B,eAAO,MAAM,SAAS,GACpB,QAAQ,SAAS,mBAAmB,CAAC,GAAG,EAAE,KAAK,CAAC,EAChD,KAAK,SAAS,WAAW,GAAG,WAAW,EACvC,SAAS,uBAAuB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAG,gBAAgB,CACpE,uBAAuB,CAAC,QAAQ,EAAE,KAAK,CAAC,EACxC,KAAK,CAkDN,CAAC"}
|
|
@@ -5,11 +5,16 @@ export const initServe = (options) => {
|
|
|
5
5
|
const { context, ...staticOptions } = options;
|
|
6
6
|
const procedure = createProcedureBuilder();
|
|
7
7
|
const define = (config) => {
|
|
8
|
-
|
|
8
|
+
// Auto-extract queryBuilder from context.db if metrics/datasets are used
|
|
9
|
+
// This is handled in createAPI since it needs to support both sync and async contexts
|
|
10
|
+
const finalConfig = {
|
|
9
11
|
...staticOptions,
|
|
10
12
|
...config,
|
|
11
13
|
context: (context ?? {}),
|
|
12
|
-
}
|
|
14
|
+
};
|
|
15
|
+
// Note: defineServe is deprecated for public use, but initServe uses it internally
|
|
16
|
+
// to provide the .start() method on the returned builder. This is intentional.
|
|
17
|
+
return defineServe(finalConfig);
|
|
13
18
|
};
|
|
14
19
|
const queryFactory = createQueryFactory((context ?? {}));
|
|
15
20
|
const query = new Proxy(queryFactory, {
|
|
@@ -13,6 +13,10 @@ export declare const api: import("../types.js").ServeBuilder<import("../types.js
|
|
|
13
13
|
}[]>;
|
|
14
14
|
}, {
|
|
15
15
|
db: {};
|
|
16
|
+
}, import("../types.js").AuthContext> & import("../types.js").SemanticMetricEndpointMap<Record<never, never>, {
|
|
17
|
+
db: {};
|
|
18
|
+
}, import("../types.js").AuthContext> & import("../types.js").SemanticDatasetEndpointMap<Record<never, never>, {
|
|
19
|
+
db: {};
|
|
16
20
|
}, import("../types.js").AuthContext>, {
|
|
17
21
|
db: {};
|
|
18
22
|
}, import("../types.js").AuthContext>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.test-d.d.ts","sourceRoot":"","sources":["../../src/type-tests/builder.test-d.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,GAAG
|
|
1
|
+
{"version":3,"file":"builder.test-d.d.ts","sourceRoot":"","sources":["../../src/type-tests/builder.test-d.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;qCAUd,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { initServe } from '../index.js';
|
|
1
|
+
import { createAnalyticsTokenIssuer, createJwtStrategy, initServe } from '../index.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
const serve = initServe({
|
|
4
4
|
context: () => ({
|
|
@@ -34,3 +34,18 @@ const executableResultPromise = executableQuery.execute({
|
|
|
34
34
|
const _executableResultIsTyped = { total: 10 };
|
|
35
35
|
// @ts-expect-error total must be number
|
|
36
36
|
const _executableResultRejectsString = { total: '10' };
|
|
37
|
+
createJwtStrategy({ secret: 'secret' });
|
|
38
|
+
createJwtStrategy({ jwksUri: 'https://issuer.example.com/.well-known/jwks.json' });
|
|
39
|
+
// @ts-expect-error exactly one key source is allowed
|
|
40
|
+
createJwtStrategy({ secret: 'secret', jwksUri: 'https://issuer.example.com/.well-known/jwks.json' });
|
|
41
|
+
// @ts-expect-error custom auth types require a mapper that proves required fields exist
|
|
42
|
+
createJwtStrategy({ secret: 'secret' });
|
|
43
|
+
createJwtStrategy({
|
|
44
|
+
secret: 'secret',
|
|
45
|
+
mapClaims: (payload) => ({
|
|
46
|
+
userId: String(payload.sub),
|
|
47
|
+
tenantId: String(payload.org_id),
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
50
|
+
// @ts-expect-error token issuer supports symmetric HMAC JWT algorithms only
|
|
51
|
+
createAnalyticsTokenIssuer({ secret: 'secret', algorithm: 'RS256' });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.test-d.d.ts","sourceRoot":"","sources":["../../src/type-tests/semantic.test-d.ts"],"names":[],"mappings":""}
|