@hypequery/serve 0.2.1 → 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 -1
- 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 +5 -2
|
@@ -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":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { dataset, dimension, measure, divide, nullIfZero, belongsTo } from '../semantic/index.js';
|
|
2
|
+
import { createAPI } from '../index.js';
|
|
3
|
+
const Customers = dataset('customers', {
|
|
4
|
+
source: 'customers',
|
|
5
|
+
dimensions: {
|
|
6
|
+
id: dimension.string(),
|
|
7
|
+
name: dimension.string(),
|
|
8
|
+
country: dimension.string(),
|
|
9
|
+
},
|
|
10
|
+
measures: {
|
|
11
|
+
customerCount: measure.count('id'),
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
const Orders = dataset('orders', {
|
|
15
|
+
source: 'orders',
|
|
16
|
+
tenantKey: 'tenant_id',
|
|
17
|
+
timeKey: 'created_at',
|
|
18
|
+
dimensions: {
|
|
19
|
+
id: dimension.string(),
|
|
20
|
+
customerId: dimension.string({ column: 'customer_id' }),
|
|
21
|
+
status: dimension.string(),
|
|
22
|
+
createdAt: dimension.timestamp({ column: 'created_at' }),
|
|
23
|
+
},
|
|
24
|
+
measures: {
|
|
25
|
+
revenue: measure.sum('amount'),
|
|
26
|
+
orderCount: measure.count('id'),
|
|
27
|
+
},
|
|
28
|
+
relationships: {
|
|
29
|
+
customer: belongsTo(() => Customers, { from: 'customerId', to: 'id' }),
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const totalRevenue = Orders.metric('totalRevenue', { measure: 'revenue' });
|
|
33
|
+
const orderCountMetric = Orders.metric('orderCountMetric', { measure: 'orderCount' });
|
|
34
|
+
const avgOrderValue = Orders.metric('avgOrderValue', {
|
|
35
|
+
uses: { revenue: totalRevenue, orders: orderCountMetric },
|
|
36
|
+
formula: ({ revenue, orders }) => divide(revenue, nullIfZero(orders)),
|
|
37
|
+
});
|
|
38
|
+
const monthlyRevenue = totalRevenue.by('month');
|
|
39
|
+
monthlyRevenue.contract();
|
|
40
|
+
avgOrderValue.contract();
|
|
41
|
+
const queryBuilder = {
|
|
42
|
+
table: (() => {
|
|
43
|
+
throw new Error('type-only query builder');
|
|
44
|
+
}),
|
|
45
|
+
rawQuery: async () => [],
|
|
46
|
+
};
|
|
47
|
+
const semanticApi = createAPI({
|
|
48
|
+
metrics: { totalRevenue },
|
|
49
|
+
datasets: { orders: Orders },
|
|
50
|
+
queryBuilder,
|
|
51
|
+
});
|
|
52
|
+
void semanticApi.execute('totalRevenue', {
|
|
53
|
+
input: { dimensions: ['status'] },
|
|
54
|
+
});
|
|
55
|
+
void semanticApi.execute('dataset:orders', {
|
|
56
|
+
input: { dimensions: ['status'], measures: ['revenue'] },
|
|
57
|
+
});
|
|
58
|
+
// @ts-expect-error only configured semantic keys are executable
|
|
59
|
+
void semanticApi.execute('dataset:customers', { input: {} });
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { ZodTypeAny } from "zod";
|
|
1
|
+
import type { ZodType, ZodTypeAny } from "zod";
|
|
2
2
|
import type { ServeQueryLogger, ServeQueryEventCallback } from "./query-logger.js";
|
|
3
|
+
import type { QueryBuilderFactoryLike } from "@hypequery/datasets";
|
|
3
4
|
/** Supported HTTP verbs for serve-managed endpoints. */
|
|
4
5
|
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS";
|
|
5
6
|
export type HeaderMap = Record<string, string | undefined>;
|
|
@@ -328,8 +329,118 @@ export interface OpenApiDocument {
|
|
|
328
329
|
securitySchemes?: Record<string, unknown>;
|
|
329
330
|
};
|
|
330
331
|
}
|
|
331
|
-
|
|
332
|
-
|
|
332
|
+
/** Per-metric entry: shorthand (just the ref) or with overrides. */
|
|
333
|
+
export type MetricEntry<TAuth extends AuthContext = AuthContext> = MetricHandle<any, any> | {
|
|
334
|
+
metric: MetricHandle<any, any>;
|
|
335
|
+
auth?: AuthStrategy<TAuth> | null;
|
|
336
|
+
tenant?: TenantConfigOverride<TAuth>;
|
|
337
|
+
cache?: number | null;
|
|
338
|
+
requiredRoles?: string[];
|
|
339
|
+
requiredScopes?: string[];
|
|
340
|
+
/** Middleware applied to this metric endpoint. */
|
|
341
|
+
middlewares?: ServeMiddleware<any, any, any, TAuth>[];
|
|
342
|
+
/**
|
|
343
|
+
* Caps the page size for this metric. Requests above it are clamped (not
|
|
344
|
+
* rejected). Defaults to the dataset's `limits.maxResultSize`, else 1000.
|
|
345
|
+
*/
|
|
346
|
+
maxLimit?: number;
|
|
347
|
+
};
|
|
348
|
+
/** Map of metric names to entries. */
|
|
349
|
+
export type MetricsConfig<TAuth extends AuthContext = AuthContext> = Record<string, MetricEntry<TAuth>>;
|
|
350
|
+
import type { DatasetInstance, DatasetQueryFor, DatasetQueryResultFor, MetricHandle, MetricQueryFor, MetricResultFor } from "@hypequery/datasets";
|
|
351
|
+
import type { DatasetEntry } from "./semantic/datasets/dataset-endpoint.js";
|
|
352
|
+
export type { DatasetEntry } from "./semantic/datasets/dataset-endpoint.js";
|
|
353
|
+
/** Map of dataset names to entries. */
|
|
354
|
+
export type DatasetsConfig<TAuth extends AuthContext = AuthContext> = Record<string, DatasetEntry<TAuth>>;
|
|
355
|
+
/** The dataset instance behind a `DatasetEntry` (bare instance or `{ dataset }`). */
|
|
356
|
+
type DatasetInstanceOfEntry<TEntry> = TEntry extends {
|
|
357
|
+
__type: 'dataset';
|
|
358
|
+
} ? TEntry : TEntry extends {
|
|
359
|
+
dataset: infer TDataset;
|
|
360
|
+
} ? (TDataset extends DatasetInstance<any, any, any, any> ? TDataset : never) : never;
|
|
361
|
+
/** The `MetricHandle` behind a `MetricEntry` (bare handle or `{ metric }`). */
|
|
362
|
+
type MetricHandleOfEntry<TEntry> = TEntry extends {
|
|
363
|
+
__type: 'metric_ref' | 'grained_metric_ref';
|
|
364
|
+
} ? TEntry : TEntry extends {
|
|
365
|
+
metric: infer THandle;
|
|
366
|
+
} ? THandle : never;
|
|
367
|
+
/** Unwrap a grained metric ref to its underlying base ref. */
|
|
368
|
+
type BaseMetricRefOf<THandle> = THandle extends {
|
|
369
|
+
__type: 'grained_metric_ref';
|
|
370
|
+
metric: infer TRef;
|
|
371
|
+
} ? TRef : THandle;
|
|
372
|
+
/** The concrete dataset instance a metric is defined on. */
|
|
373
|
+
type MetricDatasetOfEntry<TEntry> = BaseMetricRefOf<MetricHandleOfEntry<TEntry>> extends {
|
|
374
|
+
dataset: infer TDataset;
|
|
375
|
+
} ? (TDataset extends DatasetInstance<any, any, any, any> ? TDataset : never) : never;
|
|
376
|
+
/** The metric's output column name (used for typed rows and orderBy). */
|
|
377
|
+
type MetricNameOfEntry<TEntry> = BaseMetricRefOf<MetricHandleOfEntry<TEntry>> extends {
|
|
378
|
+
name: infer TName;
|
|
379
|
+
} ? (TName extends string ? TName : string) : string;
|
|
380
|
+
export type SemanticMetricEndpointMap<TMetrics extends MetricsConfig<TAuth>, TContext extends Record<string, unknown>, TAuth extends AuthContext> = {
|
|
381
|
+
[TKey in keyof TMetrics & string]: ServeEndpoint<ZodType<MetricQueryFor<MetricDatasetOfEntry<TMetrics[TKey]>, MetricNameOfEntry<TMetrics[TKey]>>>, ZodType<MetricResultFor<MetricDatasetOfEntry<TMetrics[TKey]>, MetricNameOfEntry<TMetrics[TKey]>>>, TContext, TAuth, MetricResultFor<MetricDatasetOfEntry<TMetrics[TKey]>, MetricNameOfEntry<TMetrics[TKey]>>>;
|
|
382
|
+
};
|
|
383
|
+
export type SemanticDatasetEndpointMap<TDatasets extends DatasetsConfig<TAuth>, TContext extends Record<string, unknown>, TAuth extends AuthContext> = {
|
|
384
|
+
[TKey in keyof TDatasets & string as `dataset:${TKey}`]: ServeEndpoint<ZodType<DatasetQueryFor<DatasetInstanceOfEntry<TDatasets[TKey]>>>, ZodType<DatasetQueryResultFor<DatasetInstanceOfEntry<TDatasets[TKey]>>>, TContext, TAuth, DatasetQueryResultFor<DatasetInstanceOfEntry<TDatasets[TKey]>>>;
|
|
385
|
+
};
|
|
386
|
+
export type ServeSemanticEndpointMap<TMetrics extends MetricsConfig<TAuth>, TDatasets extends DatasetsConfig<TAuth>, TContext extends Record<string, unknown>, TAuth extends AuthContext> = SemanticMetricEndpointMap<TMetrics, TContext, TAuth> & SemanticDatasetEndpointMap<TDatasets, TContext, TAuth>;
|
|
387
|
+
export interface ServeConfig<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>> {
|
|
388
|
+
queries?: TQueries;
|
|
389
|
+
/**
|
|
390
|
+
* Metrics: auto-generated POST endpoints for each metric.
|
|
391
|
+
* Each metric gets a `POST /api/analytics/metrics/:name` endpoint
|
|
392
|
+
* that validates dimensions/filters against the metric's contract.
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```ts
|
|
396
|
+
* const api = createAPI({
|
|
397
|
+
* metrics: {
|
|
398
|
+
* totalRevenue, // shorthand
|
|
399
|
+
* profitMargin: { // with overrides
|
|
400
|
+
* metric: profitMargin,
|
|
401
|
+
* auth: requireRole('finance'),
|
|
402
|
+
* cache: 300_000,
|
|
403
|
+
* },
|
|
404
|
+
* },
|
|
405
|
+
* });
|
|
406
|
+
* ```
|
|
407
|
+
*/
|
|
408
|
+
metrics?: TMetrics;
|
|
409
|
+
/**
|
|
410
|
+
* Semantic dataset endpoints — auto-generated POST endpoints for each dataset.
|
|
411
|
+
* Each dataset gets a `POST /api/analytics/datasets/:name/query` endpoint
|
|
412
|
+
* that validates dimensions/measures/filters against the dataset definition.
|
|
413
|
+
*
|
|
414
|
+
* When Serve tenant isolation is enabled for semantic endpoints, set
|
|
415
|
+
* `tenant.column` in the Serve config or per-entry override so the runtime
|
|
416
|
+
* knows which column to enforce.
|
|
417
|
+
*
|
|
418
|
+
* Accepts an inline map of dataset instances.
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```ts
|
|
422
|
+
* const api = createAPI({
|
|
423
|
+
* datasets: { orders, customers },
|
|
424
|
+
* queryBuilder: qb,
|
|
425
|
+
* });
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
datasets?: TDatasets;
|
|
429
|
+
/**
|
|
430
|
+
* Query builder instance for metric/dataset execution.
|
|
431
|
+
* Required when `metrics` or `datasets` are provided.
|
|
432
|
+
* Pass the return value of `createQueryBuilder(config)` directly.
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* ```ts
|
|
436
|
+
* const qb = createQueryBuilder<Schema>(config);
|
|
437
|
+
* const api = createAPI({
|
|
438
|
+
* metrics: { totalRevenue },
|
|
439
|
+
* queryBuilder: qb,
|
|
440
|
+
* });
|
|
441
|
+
* ```
|
|
442
|
+
*/
|
|
443
|
+
queryBuilder?: QueryBuilderFactoryLike;
|
|
333
444
|
basePath?: string;
|
|
334
445
|
middlewares?: ServeMiddleware<any, any, TContext, TAuth>[];
|
|
335
446
|
auth?: AuthStrategy<TAuth> | AuthStrategy<TAuth>[];
|
|
@@ -383,6 +494,31 @@ export interface ServeConfig<TContext extends Record<string, unknown> = Record<s
|
|
|
383
494
|
security?: {
|
|
384
495
|
verboseAuthErrors?: boolean;
|
|
385
496
|
};
|
|
497
|
+
/**
|
|
498
|
+
* Customize path prefixes for auto-generated semantic layer endpoints.
|
|
499
|
+
* Useful for avoiding route collisions or organizing API structure.
|
|
500
|
+
*
|
|
501
|
+
* @default { metrics: '/metrics', datasets: '/datasets' }
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* ```ts
|
|
505
|
+
* const api = createAPI({
|
|
506
|
+
* metrics: { totalRevenue },
|
|
507
|
+
* datasets: { orders: Orders },
|
|
508
|
+
* semanticPaths: {
|
|
509
|
+
* metrics: '/api/metrics',
|
|
510
|
+
* datasets: '/api/data',
|
|
511
|
+
* },
|
|
512
|
+
* });
|
|
513
|
+
* // Generates:
|
|
514
|
+
* // POST /api/metrics/totalRevenue
|
|
515
|
+
* // POST /api/data/orders/query
|
|
516
|
+
* ```
|
|
517
|
+
*/
|
|
518
|
+
semanticPaths?: {
|
|
519
|
+
metrics?: string;
|
|
520
|
+
datasets?: string;
|
|
521
|
+
};
|
|
386
522
|
}
|
|
387
523
|
export interface RouteRegistrationOptions<TContext extends Record<string, unknown> = Record<string, unknown>, TAuth extends AuthContext = AuthContext> {
|
|
388
524
|
method?: HttpMethod;
|
|
@@ -471,6 +607,87 @@ export type ExecuteQueryFunction<TQueries extends Record<string, ServeEndpoint<a
|
|
|
471
607
|
context?: Partial<TContext>;
|
|
472
608
|
request?: Partial<ServeRequest>;
|
|
473
609
|
}) => Promise<ServeEndpointResult<TQueries[TKey]>>;
|
|
610
|
+
/**
|
|
611
|
+
* A transport-agnostic API definition. Contains queries, auth, tenancy,
|
|
612
|
+
* and a handler — but no HTTP server. Pass to standalone transport functions:
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* ```ts
|
|
616
|
+
* const api = createAPI({ queries: { ... }, auth: jwtStrategy });
|
|
617
|
+
*
|
|
618
|
+
* // Use with any transport:
|
|
619
|
+
* startServer(api, { port: 3000 });
|
|
620
|
+
* app.use('/analytics', toNodeHandler(api));
|
|
621
|
+
* export default toFetchHandler(api);
|
|
622
|
+
* ```
|
|
623
|
+
*/
|
|
624
|
+
/** A single route in a {@link RouteManifest}. */
|
|
625
|
+
export interface RouteManifestEntry {
|
|
626
|
+
method: HttpMethod;
|
|
627
|
+
/** Full request path including the API base path. */
|
|
628
|
+
path: string;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Serializable map of query/metric/dataset keys to their HTTP method and full
|
|
632
|
+
* path. Keys match {@link HypeQueryAPI.queries} (including `dataset:<name>`
|
|
633
|
+
* keys for datasets), so it can be paired with `InferAPIType` and handed to
|
|
634
|
+
* `@hypequery/react`'s `createHooks({ manifest })` to resolve client routes
|
|
635
|
+
* without importing server code into the browser bundle.
|
|
636
|
+
*/
|
|
637
|
+
export type RouteManifest = Record<string, RouteManifestEntry>;
|
|
638
|
+
export interface HypeQueryAPI<TQueries extends Record<string, ServeEndpoint<any, any, any, any>> = Record<string, ServeEndpoint<any, any, any, any>>, TContext extends Record<string, unknown> = Record<string, unknown>, TAuth extends AuthContext = AuthContext> {
|
|
639
|
+
readonly queries: TQueries;
|
|
640
|
+
/** Serve-layer query logger for subscribing to endpoint execution events */
|
|
641
|
+
readonly queryLogger: ServeQueryLogger;
|
|
642
|
+
/** The underlying request handler. Can be passed directly to transport adapters. */
|
|
643
|
+
readonly handler: ServeHandler;
|
|
644
|
+
/**
|
|
645
|
+
* Build a serializable {@link RouteManifest} of every query/metric/dataset
|
|
646
|
+
* route (method + full path). Safe to JSON-serialize and ship to the client.
|
|
647
|
+
*/
|
|
648
|
+
manifest(): RouteManifest;
|
|
649
|
+
route<Path extends string, TKey extends keyof TQueries>(path: Path, endpoint: TQueries[TKey], options?: Partial<RouteRegistrationOptions<TContext, TAuth>>): this;
|
|
650
|
+
use(middleware: ServeMiddleware<any, any, TContext, TAuth>): this;
|
|
651
|
+
useAuth(strategy: AuthStrategy<TAuth>): this;
|
|
652
|
+
execute<TKey extends keyof TQueries>(key: TKey, options?: {
|
|
653
|
+
input?: SchemaInput<TQueries[TKey]["inputSchema"]>;
|
|
654
|
+
context?: Partial<TContext>;
|
|
655
|
+
request?: Partial<ServeRequest>;
|
|
656
|
+
}): Promise<ServeEndpointResult<TQueries[TKey]>>;
|
|
657
|
+
/** Alias of execute() for in-process execution. */
|
|
658
|
+
client<TKey extends keyof TQueries>(key: TKey, options?: {
|
|
659
|
+
input?: SchemaInput<TQueries[TKey]["inputSchema"]>;
|
|
660
|
+
context?: Partial<TContext>;
|
|
661
|
+
request?: Partial<ServeRequest>;
|
|
662
|
+
}): Promise<ServeEndpointResult<TQueries[TKey]>>;
|
|
663
|
+
/** Alias of execute() for in-process execution. */
|
|
664
|
+
run<TKey extends keyof TQueries>(key: TKey, options?: {
|
|
665
|
+
input?: SchemaInput<TQueries[TKey]["inputSchema"]>;
|
|
666
|
+
context?: Partial<TContext>;
|
|
667
|
+
request?: Partial<ServeRequest>;
|
|
668
|
+
}): Promise<ServeEndpointResult<TQueries[TKey]>>;
|
|
669
|
+
describe(): ToolkitDescription;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Infer the API type from a HypeQueryAPI for use with @hypequery/react.
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* ```ts
|
|
676
|
+
* const api = createAPI({ queries: { hello: ... } });
|
|
677
|
+
* type Api = InferAPIType<typeof api>;
|
|
678
|
+
* createHooks<Api>({ baseUrl: '/api' });
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
681
|
+
export type InferAPIType<TTarget> = TTarget extends HypeQueryAPI<infer TQueries, any, any> ? {
|
|
682
|
+
[K in keyof TQueries]: TQueries[K] extends ServeEndpoint<infer TInputSchema, infer TOutputSchema, any, any, any> ? {
|
|
683
|
+
input: SchemaInput<TInputSchema>;
|
|
684
|
+
output: SchemaOutput<TOutputSchema>;
|
|
685
|
+
} : never;
|
|
686
|
+
} : never;
|
|
687
|
+
/**
|
|
688
|
+
* @deprecated Use `HypeQueryAPI` and `createAPI()` instead. `ServeBuilder` adds
|
|
689
|
+
* transport concerns (`start()`) that should be handled separately.
|
|
690
|
+
*/
|
|
474
691
|
export interface ServeBuilder<TQueries extends Record<string, ServeEndpoint<any, any, any, any>> = Record<string, ServeEndpoint<any, any, any, any>>, TContext extends Record<string, unknown> = Record<string, unknown>, TAuth extends AuthContext = AuthContext> {
|
|
475
692
|
readonly queries: TQueries;
|
|
476
693
|
/** Base path applied to all registered routes, docs, and OpenAPI endpoints */
|
|
@@ -481,6 +698,11 @@ export interface ServeBuilder<TQueries extends Record<string, ServeEndpoint<any,
|
|
|
481
698
|
readonly _routeConfig?: Record<string, {
|
|
482
699
|
method: HttpMethod;
|
|
483
700
|
}>;
|
|
701
|
+
/**
|
|
702
|
+
* Build a serializable {@link RouteManifest} of every query/metric/dataset
|
|
703
|
+
* route (method + full path). Safe to JSON-serialize and ship to the client.
|
|
704
|
+
*/
|
|
705
|
+
manifest(): RouteManifest;
|
|
484
706
|
route<Path extends string, TKey extends keyof TQueries>(path: Path, endpoint: TQueries[TKey], options?: Partial<RouteRegistrationOptions<TContext, TAuth>>): this;
|
|
485
707
|
use(middleware: ServeMiddleware<any, any, TContext, TAuth>): this;
|
|
486
708
|
useAuth(strategy: AuthStrategy<TAuth>): this;
|
|
@@ -508,8 +730,8 @@ export interface ServeInitializer<TContext extends Record<string, unknown> = Rec
|
|
|
508
730
|
readonly procedure: QueryProcedureBuilder<TContext, TAuth>;
|
|
509
731
|
readonly query: QueryFactory<TContext, TAuth>;
|
|
510
732
|
queries<TQueries extends ServeQueriesMap<TContext, TAuth>>(queries: TQueries): TQueries;
|
|
511
|
-
serve<TQueries extends ServeQueriesMap<TContext, TAuth>>(config: Omit<ServeConfig<TContext, TAuth, TQueries>, "context">): ServeBuilder<ServeEndpointMap<TQueries, TContext, TAuth>, TContext, TAuth>;
|
|
512
|
-
define<TQueries extends ServeQueriesMap<TContext, TAuth>>(config: Omit<ServeConfig<TContext, TAuth, TQueries>, "context">): ServeBuilder<ServeEndpointMap<TQueries, TContext, TAuth>, TContext, TAuth>;
|
|
733
|
+
serve<TQueries extends ServeQueriesMap<TContext, TAuth>, TMetrics extends MetricsConfig<TAuth> = Record<never, never>, TDatasets extends DatasetsConfig<TAuth> = Record<never, never>>(config: Omit<ServeConfig<TContext, TAuth, TQueries, TMetrics, TDatasets>, "context">): ServeBuilder<ServeEndpointMap<TQueries, TContext, TAuth> & ServeSemanticEndpointMap<TMetrics, TDatasets, TContext, TAuth>, TContext, TAuth>;
|
|
734
|
+
define<TQueries extends ServeQueriesMap<TContext, TAuth>, TMetrics extends MetricsConfig<TAuth> = Record<never, never>, TDatasets extends DatasetsConfig<TAuth> = Record<never, never>>(config: Omit<ServeConfig<TContext, TAuth, TQueries, TMetrics, TDatasets>, "context">): ServeBuilder<ServeEndpointMap<TQueries, TContext, TAuth> & ServeSemanticEndpointMap<TMetrics, TDatasets, TContext, TAuth>, TContext, TAuth>;
|
|
513
735
|
}
|
|
514
736
|
export type QueryFactory<TContext extends Record<string, unknown>, TAuth extends AuthContext> = QueryProcedureBuilder<TContext, TAuth> & {
|
|
515
737
|
<TInputSchema extends ZodTypeAny | undefined = undefined, TOutputSchema extends ZodTypeAny | undefined = undefined, TResult = TOutputSchema extends ZodTypeAny ? SchemaOutput<TOutputSchema> : unknown>(config: QueryObjectConfig<TInputSchema, TOutputSchema, TContext, TAuth, TResult>): StandaloneQueryDefinition<TInputSchema, TOutputSchema extends ZodTypeAny ? TOutputSchema : ZodTypeAny, TContext, TAuth, TResult>;
|
|
@@ -628,5 +850,4 @@ export type ServeContextFactory<TContext extends Record<string, unknown>, TAuth
|
|
|
628
850
|
request: ServeRequest;
|
|
629
851
|
auth: TAuth | null;
|
|
630
852
|
}) => MaybePromise<TContext>);
|
|
631
|
-
export {};
|
|
632
853
|
//# sourceMappingURL=types.d.ts.map
|