@hypequery/serve 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1039 -0
  3. package/dist/adapters/fetch.d.ts +3 -0
  4. package/dist/adapters/fetch.d.ts.map +1 -0
  5. package/dist/adapters/fetch.js +26 -0
  6. package/dist/adapters/node.d.ts +8 -0
  7. package/dist/adapters/node.d.ts.map +1 -0
  8. package/dist/adapters/node.js +105 -0
  9. package/dist/adapters/utils.d.ts +39 -0
  10. package/dist/adapters/utils.d.ts.map +1 -0
  11. package/dist/adapters/utils.js +114 -0
  12. package/dist/adapters/vercel.d.ts +7 -0
  13. package/dist/adapters/vercel.d.ts.map +1 -0
  14. package/dist/adapters/vercel.js +13 -0
  15. package/dist/auth.d.ts +14 -0
  16. package/dist/auth.d.ts.map +1 -0
  17. package/dist/auth.js +37 -0
  18. package/dist/client-config.d.ts +44 -0
  19. package/dist/client-config.d.ts.map +1 -0
  20. package/dist/client-config.js +53 -0
  21. package/dist/dev.d.ts +9 -0
  22. package/dist/dev.d.ts.map +1 -0
  23. package/dist/dev.js +24 -0
  24. package/dist/docs-ui.d.ts +3 -0
  25. package/dist/docs-ui.d.ts.map +1 -0
  26. package/dist/docs-ui.js +34 -0
  27. package/dist/endpoint.d.ts +5 -0
  28. package/dist/endpoint.d.ts.map +1 -0
  29. package/dist/endpoint.js +58 -0
  30. package/dist/index.d.ts +13 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +12 -0
  33. package/dist/openapi.d.ts +3 -0
  34. package/dist/openapi.d.ts.map +1 -0
  35. package/dist/openapi.js +189 -0
  36. package/dist/queries.d.ts +3 -0
  37. package/dist/queries.d.ts.map +1 -0
  38. package/dist/queries.js +1 -0
  39. package/dist/query.d.ts +4 -0
  40. package/dist/query.d.ts.map +1 -0
  41. package/dist/query.js +1 -0
  42. package/dist/router.d.ts +13 -0
  43. package/dist/router.d.ts.map +1 -0
  44. package/dist/router.js +56 -0
  45. package/dist/sdk-generator.d.ts +7 -0
  46. package/dist/sdk-generator.d.ts.map +1 -0
  47. package/dist/sdk-generator.js +143 -0
  48. package/dist/server.d.ts +9 -0
  49. package/dist/server.d.ts.map +1 -0
  50. package/dist/server.js +580 -0
  51. package/dist/tenant.d.ts +35 -0
  52. package/dist/tenant.d.ts.map +1 -0
  53. package/dist/tenant.js +49 -0
  54. package/dist/type-tests/builder.test-d.d.ts +13 -0
  55. package/dist/type-tests/builder.test-d.d.ts.map +1 -0
  56. package/dist/type-tests/builder.test-d.js +20 -0
  57. package/dist/types.d.ts +363 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +1 -0
  60. package/package.json +50 -0
@@ -0,0 +1,13 @@
1
+ export * from "./types.js";
2
+ export * from "./server.js";
3
+ export * from "./router.js";
4
+ export * from "./endpoint.js";
5
+ export * from "./openapi.js";
6
+ export * from "./docs-ui.js";
7
+ export * from "./auth.js";
8
+ export * from "./client-config.js";
9
+ export * from "./adapters/node.js";
10
+ export * from "./adapters/fetch.js";
11
+ export * from "./adapters/vercel.js";
12
+ export * from "./dev.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export * from "./types.js";
2
+ export * from "./server.js";
3
+ export * from "./router.js";
4
+ export * from "./endpoint.js";
5
+ export * from "./openapi.js";
6
+ export * from "./docs-ui.js";
7
+ export * from "./auth.js";
8
+ export * from "./client-config.js";
9
+ export * from "./adapters/node.js";
10
+ export * from "./adapters/fetch.js";
11
+ export * from "./adapters/vercel.js";
12
+ export * from "./dev.js";
@@ -0,0 +1,3 @@
1
+ import type { OpenApiDocument, OpenApiOptions, ServeEndpoint } from "./types.js";
2
+ export declare const buildOpenApiDocument: (endpoints: ServeEndpoint<any, any, any, any>[], options?: OpenApiOptions) => OpenApiDocument;
3
+ //# sourceMappingURL=openapi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAqLjF,eAAO,MAAM,oBAAoB,GAC/B,WAAW,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,EAC9C,UAAU,cAAc,KACvB,eAyCF,CAAC"}
@@ -0,0 +1,189 @@
1
+ import { zodToJsonSchema } from "zod-to-json-schema";
2
+ const ERROR_SCHEMA = {
3
+ type: "object",
4
+ properties: {
5
+ error: {
6
+ type: "object",
7
+ properties: {
8
+ type: { type: "string" },
9
+ message: { type: "string" },
10
+ details: { type: "object" },
11
+ },
12
+ required: ["type", "message"],
13
+ },
14
+ },
15
+ required: ["error"],
16
+ };
17
+ const dereferenceSchema = (schema) => {
18
+ if (!schema || typeof schema !== "object") {
19
+ return schema;
20
+ }
21
+ if (schema.$ref && schema.definitions) {
22
+ const refKey = String(schema.$ref).split("/").pop();
23
+ if (refKey && schema.definitions[refKey]) {
24
+ return schema.definitions[refKey];
25
+ }
26
+ }
27
+ return schema;
28
+ };
29
+ const removeDefinitions = (schema) => {
30
+ if (!schema || typeof schema !== "object") {
31
+ return schema;
32
+ }
33
+ // Handle arrays
34
+ if (Array.isArray(schema)) {
35
+ return schema.map(item => removeDefinitions(item));
36
+ }
37
+ // If this schema has a $ref and definitions, inline the definition
38
+ if (schema.$ref && schema.definitions) {
39
+ const refKey = String(schema.$ref).split("/").pop();
40
+ if (refKey && schema.definitions[refKey]) {
41
+ const resolved = schema.definitions[refKey];
42
+ delete schema.$ref;
43
+ delete schema.definitions;
44
+ return removeDefinitions({ ...schema, ...resolved });
45
+ }
46
+ }
47
+ // Remove definitions property if it exists
48
+ const { definitions: _definitions, $ref: _ref, ...rest } = schema;
49
+ // Recursively clean nested objects and arrays
50
+ const result = {};
51
+ for (const [key, value] of Object.entries(rest)) {
52
+ if (Array.isArray(value)) {
53
+ result[key] = value.map(item => typeof item === "object" && item !== null ? removeDefinitions(item) : item);
54
+ }
55
+ else if (typeof value === "object" && value !== null) {
56
+ result[key] = removeDefinitions(value);
57
+ }
58
+ else {
59
+ result[key] = value;
60
+ }
61
+ }
62
+ return result;
63
+ };
64
+ const toJsonSchema = (schema, name) => {
65
+ if (!schema) {
66
+ return { type: "object" };
67
+ }
68
+ const jsonSchema = zodToJsonSchema(schema, {
69
+ target: "openApi3",
70
+ name,
71
+ $refStrategy: "none",
72
+ });
73
+ return removeDefinitions(jsonSchema);
74
+ };
75
+ const toQueryParameters = (schema, name) => {
76
+ if (!schema) {
77
+ return [];
78
+ }
79
+ const jsonSchema = dereferenceSchema(toJsonSchema(schema, name));
80
+ if (!jsonSchema || typeof jsonSchema !== "object") {
81
+ return [];
82
+ }
83
+ const schemaType = jsonSchema.type;
84
+ const isObjectType = schemaType === "object" || (Array.isArray(schemaType) && schemaType.includes("object"));
85
+ if (!isObjectType || typeof jsonSchema.properties !== "object") {
86
+ return [];
87
+ }
88
+ const properties = jsonSchema.properties;
89
+ const requiredSet = new Set(Array.isArray(jsonSchema.required) ? jsonSchema.required : []);
90
+ return Object.entries(properties).map(([key, value]) => ({
91
+ name: key,
92
+ in: "query",
93
+ required: requiredSet.has(key),
94
+ schema: value,
95
+ }));
96
+ };
97
+ const toOperation = (endpoint, nameSuffix) => {
98
+ const operation = {
99
+ operationId: endpoint.key,
100
+ summary: endpoint.metadata.summary,
101
+ description: endpoint.metadata.description,
102
+ tags: endpoint.metadata.tags.length ? endpoint.metadata.tags : undefined,
103
+ responses: {
104
+ 200: {
105
+ description: "Successful response",
106
+ content: {
107
+ "application/json": {
108
+ schema: toJsonSchema(endpoint.outputSchema, `${endpoint.key}${nameSuffix}`),
109
+ },
110
+ },
111
+ },
112
+ default: {
113
+ description: "Error response",
114
+ content: {
115
+ "application/json": {
116
+ schema: ERROR_SCHEMA,
117
+ },
118
+ },
119
+ },
120
+ },
121
+ };
122
+ const queryParameters = endpoint.method === "GET"
123
+ ? toQueryParameters(endpoint.inputSchema, `${endpoint.key}Query`)
124
+ : [];
125
+ if (queryParameters.length > 0) {
126
+ operation.parameters = queryParameters;
127
+ }
128
+ else if (endpoint.inputSchema) {
129
+ operation.requestBody = {
130
+ required: true,
131
+ content: {
132
+ "application/json": {
133
+ schema: toJsonSchema(endpoint.inputSchema, `${endpoint.key}Request`),
134
+ },
135
+ },
136
+ };
137
+ }
138
+ if (endpoint.metadata.requiresAuth) {
139
+ operation.security = [{ ApiKeyAuth: [] }];
140
+ }
141
+ return operation;
142
+ };
143
+ const normalizeInfo = (options) => {
144
+ const info = options?.info;
145
+ return {
146
+ title: info?.title ?? "hypequery API",
147
+ version: options?.version ?? "1.0.0",
148
+ description: info?.description,
149
+ termsOfService: info?.termsOfService,
150
+ contact: info?.contact,
151
+ license: info?.license,
152
+ };
153
+ };
154
+ export const buildOpenApiDocument = (endpoints, options) => {
155
+ var _a;
156
+ const document = {
157
+ openapi: "3.1.0",
158
+ info: normalizeInfo(options),
159
+ servers: options?.servers ?? [],
160
+ paths: {},
161
+ };
162
+ let needsSecurityScheme = false;
163
+ for (const endpoint of endpoints) {
164
+ if (endpoint.metadata.visibility && endpoint.metadata.visibility !== "public") {
165
+ continue;
166
+ }
167
+ const path = endpoint.metadata.path || "/";
168
+ const method = endpoint.method.toLowerCase();
169
+ const pathItem = ((_a = document.paths)[path] ?? (_a[path] = {}));
170
+ const operation = toOperation(endpoint, "Response");
171
+ if (endpoint.metadata.requiresAuth) {
172
+ needsSecurityScheme = true;
173
+ }
174
+ pathItem[method] = operation;
175
+ }
176
+ if (needsSecurityScheme) {
177
+ document.components = {
178
+ ...(document.components ?? {}),
179
+ securitySchemes: {
180
+ ApiKeyAuth: {
181
+ type: "apiKey",
182
+ name: "Authorization",
183
+ in: "header",
184
+ },
185
+ },
186
+ };
187
+ }
188
+ return document;
189
+ };
@@ -0,0 +1,3 @@
1
+ import type { AuthContext, ServeQueriesMap } from "./types.js";
2
+ export declare const defineQueries: <TContext extends Record<string, unknown> = Record<string, unknown>, TAuth extends AuthContext = AuthContext, const TQueries extends ServeQueriesMap<TContext, TAuth> = ServeQueriesMap<TContext, TAuth>>(queries: TQueries) => TQueries;
3
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/D,eAAO,MAAM,aAAa,GACxB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,KAAK,SAAS,WAAW,GAAG,WAAW,EACvC,KAAK,CAAC,QAAQ,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,EAE1F,SAAS,QAAQ,KAChB,QAAmB,CAAC"}
@@ -0,0 +1 @@
1
+ export const defineQueries = (queries) => queries;
@@ -0,0 +1,4 @@
1
+ import type { ZodTypeAny } from "zod";
2
+ import type { AuthContext, SchemaOutput, ServeQueryConfig } from "./types.js";
3
+ export declare const defineQuery: <TInputSchema extends ZodTypeAny | undefined = undefined, TOutputSchema extends ZodTypeAny = ZodTypeAny, TContext extends Record<string, unknown> = Record<string, unknown>, TAuth extends AuthContext = AuthContext, TResult = SchemaOutput<TOutputSchema>>(definition: ServeQueryConfig<TInputSchema, TOutputSchema, TContext, TAuth, TResult>) => ServeQueryConfig<TInputSchema, TOutputSchema, TContext, TAuth, TResult>;
4
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9E,eAAO,MAAM,WAAW,GACtB,YAAY,SAAS,UAAU,GAAG,SAAS,GAAG,SAAS,EACvD,aAAa,SAAS,UAAU,GAAG,UAAU,EAC7C,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,KAAK,SAAS,WAAW,GAAG,WAAW,EACvC,OAAO,GAAG,YAAY,CAAC,aAAa,CAAC,EAErC,YAAY,gBAAgB,CAAC,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,KAClF,gBAAgB,CAAC,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAe,CAAC"}
package/dist/query.js ADDED
@@ -0,0 +1 @@
1
+ export const defineQuery = (definition) => definition;
@@ -0,0 +1,13 @@
1
+ import type { EndpointRegistry, HttpMethod, ServeEndpoint } from "./types.js";
2
+ export declare const normalizeRoutePath: (path: string) => string;
3
+ export declare const applyBasePath: (basePath: string, path: string) => string;
4
+ export declare class ServeRouter implements EndpointRegistry {
5
+ private readonly basePath;
6
+ private routes;
7
+ constructor(basePath?: string);
8
+ list(): ServeEndpoint<any, any, any, any, any>[];
9
+ register(endpoint: ServeEndpoint<any, any, any, any>): void;
10
+ match(method: HttpMethod, path: string): ServeEndpoint<any, any, any, any, any> | null;
11
+ markRoutesRequireAuth(): void;
12
+ }
13
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAI9E,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,WAG9C,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,UAAU,MAAM,EAAE,MAAM,MAAM,WAM3D,CAAC;AAEF,qBAAa,WAAY,YAAW,gBAAgB;IAGtC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAFrC,OAAO,CAAC,MAAM,CAA2C;gBAE5B,QAAQ,SAAK;IAE1C,IAAI;IAIJ,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAuBpD,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM;IAStC,qBAAqB;CAetB"}
package/dist/router.js ADDED
@@ -0,0 +1,56 @@
1
+ const trimSlashes = (value) => value.replace(/^\/+|\/+$/g, "");
2
+ export const normalizeRoutePath = (path) => {
3
+ const trimmed = trimSlashes(path || "/");
4
+ return `/${trimmed}`.replace(/\/+/g, "/").replace(/\/$/, trimmed ? "" : "/");
5
+ };
6
+ export const applyBasePath = (basePath, path) => {
7
+ const parts = [trimSlashes(basePath ?? ""), trimSlashes(path)]
8
+ .filter(Boolean)
9
+ .join("/");
10
+ const combined = parts ? `/${parts}` : "/";
11
+ return combined.replace(/\/+/g, "/").replace(/\/$/, combined === "/" ? "/" : "");
12
+ };
13
+ export class ServeRouter {
14
+ constructor(basePath = "") {
15
+ this.basePath = basePath;
16
+ this.routes = [];
17
+ }
18
+ list() {
19
+ return [...this.routes];
20
+ }
21
+ register(endpoint) {
22
+ const path = endpoint.metadata.path || "/";
23
+ const normalizedPath = applyBasePath(this.basePath, path);
24
+ const method = endpoint.method;
25
+ const existing = this.routes.find((route) => route.metadata.path === normalizedPath && route.method === method);
26
+ if (existing) {
27
+ throw new Error(`Route already registered for ${method} ${normalizedPath}`);
28
+ }
29
+ this.routes.push({
30
+ ...endpoint,
31
+ metadata: {
32
+ ...endpoint.metadata,
33
+ path: normalizedPath,
34
+ method,
35
+ },
36
+ });
37
+ }
38
+ match(method, path) {
39
+ const normalizedPath = normalizeRoutePath(path);
40
+ return (this.routes.find((route) => route.method === method && route.metadata.path === normalizedPath) ?? null);
41
+ }
42
+ markRoutesRequireAuth() {
43
+ this.routes = this.routes.map((route) => {
44
+ if (route.metadata.requiresAuth === false) {
45
+ return route;
46
+ }
47
+ return {
48
+ ...route,
49
+ metadata: {
50
+ ...route.metadata,
51
+ requiresAuth: true,
52
+ },
53
+ };
54
+ });
55
+ }
56
+ }
@@ -0,0 +1,7 @@
1
+ export interface GenerateSdkOptions {
2
+ input: string;
3
+ output: string;
4
+ clientName?: string;
5
+ }
6
+ export declare const generateSdkClient: (options: GenerateSdkOptions) => Promise<void>;
7
+ //# sourceMappingURL=sdk-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-generator.d.ts","sourceRoot":"","sources":["../src/sdk-generator.ts"],"names":[],"mappings":"AAuHA,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAuBD,eAAO,MAAM,iBAAiB,GAAU,SAAS,kBAAkB,kBAalE,CAAC"}
@@ -0,0 +1,143 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, isAbsolute, join, resolve } from "node:path";
3
+ import openapiTS, { astToString } from "openapi-typescript";
4
+ const TEMPLATE_CLIENT = (clientName) => [
5
+ 'import type { paths } from "./types";',
6
+ '',
7
+ 'type FetchImpl = typeof fetch;',
8
+ '',
9
+ 'type ExtractJsonResponse<T> = T extends { responses: infer Responses }',
10
+ ' ? Responses extends Record<string, any>',
11
+ ' ? Responses[200] extends { content: { "application/json": infer R } }',
12
+ ' ? R',
13
+ ' : Responses[201] extends { content: { "application/json": infer R } }',
14
+ ' ? R',
15
+ ' : unknown',
16
+ ' : unknown',
17
+ ' : unknown;',
18
+ '',
19
+ 'type ExtractBody<T> = T extends { requestBody: { content: { "application/json": infer Body } } }',
20
+ ' ? Body',
21
+ ' : undefined;',
22
+ '',
23
+ 'type ExtractQuery<T> = T extends { parameters: { query: infer Params } }',
24
+ ' ? Params',
25
+ ' : undefined;',
26
+ '',
27
+ 'type RequestOptions<Path extends keyof paths, Method extends keyof paths[Path]> = {',
28
+ ' path: Path;',
29
+ ' method: Method;',
30
+ ' query?: ExtractQuery<paths[Path][Method]>;',
31
+ ' body?: ExtractBody<paths[Path][Method]>;',
32
+ ' headers?: Record<string, string>;',
33
+ ' fetch?: FetchImpl;',
34
+ '} & Omit<RequestInit, "body" | "method">;',
35
+ '',
36
+ 'interface ClientConfig {',
37
+ ' baseUrl: string;',
38
+ ' headers?: Record<string, string>;',
39
+ ' fetch?: FetchImpl;',
40
+ '}',
41
+ '',
42
+ 'const encodeQueryValue = (value: unknown) =>',
43
+ ' Array.isArray(value)',
44
+ ' ? value.map((v) => encodeURIComponent(String(v))).join(",")',
45
+ ' : encodeURIComponent(String(value));',
46
+ '',
47
+ 'const buildUrl = (baseUrl: string, path: string, query?: Record<string, unknown>) => {',
48
+ ' const url = new URL(path, baseUrl);',
49
+ '',
50
+ ' if (query) {',
51
+ ' Object.entries(query).forEach(([key, value]) => {',
52
+ ' if (value === undefined || value === null) {',
53
+ ' return;',
54
+ ' }',
55
+ '',
56
+ ' if (Array.isArray(value)) {',
57
+ ' value.forEach((entry) => url.searchParams.append(key, String(entry)));',
58
+ ' } else if (typeof value === "object") {',
59
+ ' url.searchParams.append(key, encodeQueryValue(JSON.stringify(value)));',
60
+ ' } else {',
61
+ ' url.searchParams.append(key, encodeQueryValue(value));',
62
+ ' }',
63
+ ' });',
64
+ ' }',
65
+ '',
66
+ ' return url;',
67
+ '};',
68
+ '',
69
+ `export class ${clientName} {`,
70
+ ' constructor(private readonly config: ClientConfig) {}',
71
+ '',
72
+ ' async request<Path extends keyof paths, Method extends keyof paths[Path]>(',
73
+ ' options: RequestOptions<Path, Method>',
74
+ ' ): Promise<ExtractJsonResponse<paths[Path][Method]>> {',
75
+ ' const target = buildUrl(this.config.baseUrl, options.path as string, options.query);',
76
+ ' const fetchImpl = options.fetch ?? this.config.fetch ?? globalThis.fetch;',
77
+ '',
78
+ ' if (!fetchImpl) {',
79
+ ' throw new Error("No fetch implementation available. Provide one via config.fetch.");',
80
+ ' }',
81
+ '',
82
+ ' const headers = {',
83
+ ' "content-type": "application/json",',
84
+ ' ...(this.config.headers ?? {}),',
85
+ ' ...(options.headers ?? {}),',
86
+ ' };',
87
+ '',
88
+ ' const response = await fetchImpl(target.toString(), {',
89
+ ' ...options,',
90
+ ' method: options.method as string,',
91
+ ' headers,',
92
+ ' body: options.body !== undefined ? JSON.stringify(options.body) : undefined,',
93
+ ' });',
94
+ '',
95
+ ' if (!response.ok) {',
96
+ ' const errorText = await response.text();',
97
+ ' throw new Error(`Request failed with status ${response.status}: ${errorText}`);',
98
+ ' }',
99
+ '',
100
+ ' const text = await response.text();',
101
+ ' if (!text) {',
102
+ ' return undefined as ExtractJsonResponse<paths[Path][Method]>;',
103
+ ' }',
104
+ '',
105
+ ' return JSON.parse(text);',
106
+ ' }',
107
+ '}',
108
+ '',
109
+ `export const createClient = (config: ClientConfig) => new ${clientName}(config);`,
110
+ '',
111
+ ].join("\n");
112
+ const TEMPLATE_INDEX = `export * from "./client";
113
+ export * from "./types";
114
+ `;
115
+ const isHttpUrl = (value) => /^https?:\/\//i.test(value);
116
+ const loadDocument = async (input) => {
117
+ if (isHttpUrl(input)) {
118
+ const response = await fetch(input);
119
+ if (!response.ok) {
120
+ throw new Error(`Failed to fetch OpenAPI spec from ${input}: ${response.status}`);
121
+ }
122
+ return response.json();
123
+ }
124
+ const absolutePath = isAbsolute(input) ? input : resolve(process.cwd(), input);
125
+ const contents = await readFile(absolutePath, "utf8");
126
+ return JSON.parse(contents);
127
+ };
128
+ const writeFileSafe = async (filePath, contents) => {
129
+ await mkdir(dirname(filePath), { recursive: true });
130
+ await writeFile(filePath, contents, "utf8");
131
+ };
132
+ export const generateSdkClient = async (options) => {
133
+ const document = await loadDocument(options.input);
134
+ const typesAst = await openapiTS(document, {
135
+ exportType: true,
136
+ });
137
+ const types = astToString(typesAst);
138
+ const outputDir = isAbsolute(options.output) ? options.output : resolve(process.cwd(), options.output);
139
+ const clientName = options.clientName ?? "HypeQueryClient";
140
+ await writeFileSafe(join(outputDir, "types.ts"), types);
141
+ await writeFileSafe(join(outputDir, "client.ts"), TEMPLATE_CLIENT(clientName));
142
+ await writeFileSafe(join(outputDir, "index.ts"), TEMPLATE_INDEX);
143
+ };
@@ -0,0 +1,9 @@
1
+ import type { AuthContext, ServeBuilder, ServeConfig, ServeContextFactory, ServeEndpointMap, ServeInitializer, ServeQueriesMap } from "./types.js";
2
+ export declare const defineServe: <TContext extends Record<string, unknown> = Record<string, unknown>, TAuth extends AuthContext = AuthContext, const TQueries extends ServeQueriesMap<TContext, TAuth> = ServeQueriesMap<TContext, TAuth>>(config: ServeConfig<TContext, TAuth, TQueries>) => ServeBuilder<ServeEndpointMap<TQueries, TContext, TAuth>, TContext, TAuth>;
3
+ type InferInitializerContext<TFactory, TAuth extends AuthContext> = TFactory extends ServeContextFactory<infer TContext, TAuth> ? TContext : never;
4
+ type ServeInitializerOptions<TFactory extends ServeContextFactory<any, TAuth>, TAuth extends AuthContext> = Omit<ServeConfig<InferInitializerContext<TFactory, TAuth>, TAuth, ServeQueriesMap<InferInitializerContext<TFactory, TAuth>, TAuth>>, "queries" | "context"> & {
5
+ context: TFactory;
6
+ };
7
+ export declare const initServe: <TFactory extends ServeContextFactory<any, TAuth>, TAuth extends AuthContext = AuthContext>(options: ServeInitializerOptions<TFactory, TAuth>) => ServeInitializer<InferInitializerContext<TFactory, TAuth>, TAuth>;
8
+ export {};
9
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,WAAW,EAaX,YAAY,EACZ,WAAW,EACX,mBAAmB,EAEnB,gBAAgB,EAEhB,gBAAgB,EAGhB,eAAe,EAShB,MAAM,YAAY,CAAC;AAqiBpB,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,KAAK,CAAC,QAAQ,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,EAE1F,QAAQ,WAAW,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,KAC7C,YAAY,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,CA2L3E,CAAC;AA6BF,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,CACjE,EACD,SAAS,GAAG,SAAS,CACtB,GAAG;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;AAQ1B,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,CAsBN,CAAC"}