@hypequery/serve 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +220 -185
  2. package/dist/adapters/node.d.ts +1 -1
  3. package/dist/adapters/node.d.ts.map +1 -1
  4. package/dist/adapters/node.js +114 -21
  5. package/dist/auth.d.ts +27 -17
  6. package/dist/auth.d.ts.map +1 -1
  7. package/dist/auth.js +27 -17
  8. package/dist/cors.d.ts +17 -0
  9. package/dist/cors.d.ts.map +1 -0
  10. package/dist/cors.js +82 -0
  11. package/dist/dev.js +1 -1
  12. package/dist/errors.d.ts +24 -0
  13. package/dist/errors.d.ts.map +1 -0
  14. package/dist/errors.js +22 -0
  15. package/dist/index.d.ts +4 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +4 -0
  18. package/dist/pipeline.d.ts +8 -1
  19. package/dist/pipeline.d.ts.map +1 -1
  20. package/dist/pipeline.js +36 -7
  21. package/dist/rate-limit.d.ts +86 -0
  22. package/dist/rate-limit.d.ts.map +1 -0
  23. package/dist/rate-limit.js +137 -0
  24. package/dist/serve.d.ts +16 -0
  25. package/dist/serve.d.ts.map +1 -0
  26. package/dist/serve.js +88 -0
  27. package/dist/server/builder.d.ts +1 -1
  28. package/dist/server/builder.d.ts.map +1 -1
  29. package/dist/server/builder.js +1 -0
  30. package/dist/server/define-serve.d.ts.map +1 -1
  31. package/dist/server/define-serve.js +3 -0
  32. package/dist/server/execute-query.d.ts.map +1 -1
  33. package/dist/server/execute-query.js +6 -1
  34. package/dist/server/init-serve.d.ts.map +1 -1
  35. package/dist/server/init-serve.js +23 -8
  36. package/dist/type-tests/builder.test-d.d.ts +8 -2
  37. package/dist/type-tests/builder.test-d.d.ts.map +1 -1
  38. package/dist/type-tests/builder.test-d.js +17 -1
  39. package/dist/types.d.ts +102 -5
  40. package/dist/types.d.ts.map +1 -1
  41. package/package.json +9 -1
@@ -1,17 +1,30 @@
1
1
  import { createServer } from "http";
2
2
  import { once } from "node:events";
3
3
  import { normalizeHeaders, parseQueryParams, parseRequestBody, serializeResponseBody, } from "./utils.js";
4
- const readRequestBody = async (req) => {
4
+ const DEFAULT_REQUEST_TIMEOUT = 30000; // 30 seconds
5
+ const DEFAULT_BODY_LIMIT = 1048576; // 1 MB
6
+ const DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT = 10000; // 10 seconds
7
+ const readRequestBody = async (req, bodyLimit) => {
5
8
  const chunks = [];
9
+ let totalLength = 0;
6
10
  for await (const chunk of req) {
7
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
11
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
12
+ totalLength += buf.length;
13
+ if (bodyLimit > 0 && totalLength > bodyLimit) {
14
+ // Destroy the stream to stop reading
15
+ req.destroy();
16
+ const error = new Error("Request body too large");
17
+ error.code = "PAYLOAD_TOO_LARGE";
18
+ throw error;
19
+ }
20
+ chunks.push(buf);
8
21
  }
9
22
  return Buffer.concat(chunks);
10
23
  };
11
- const buildServeRequest = async (req) => {
24
+ const buildServeRequest = async (req, bodyLimit) => {
12
25
  const method = (req.method ?? "GET").toUpperCase();
13
26
  const url = new URL(req.url ?? "/", "http://localhost");
14
- const bodyBuffer = await readRequestBody(req);
27
+ const bodyBuffer = await readRequestBody(req, bodyLimit);
15
28
  const headers = normalizeHeaders(req.headers);
16
29
  const contentType = headers["content-type"] ?? headers["Content-Type"];
17
30
  const body = await parseRequestBody(bodyBuffer, contentType);
@@ -25,6 +38,8 @@ const buildServeRequest = async (req) => {
25
38
  };
26
39
  };
27
40
  const sendResponse = (res, response) => {
41
+ if (res.writableEnded)
42
+ return;
28
43
  res.statusCode = response.status;
29
44
  const headers = response.headers ?? {};
30
45
  for (const [key, value] of Object.entries(headers)) {
@@ -39,6 +54,24 @@ const sendResponse = (res, response) => {
39
54
  res.end(serialized);
40
55
  };
41
56
  const sendError = (res, error) => {
57
+ if (res.writableEnded)
58
+ return;
59
+ // Handle body-too-large errors
60
+ if (error &&
61
+ typeof error === "object" &&
62
+ "code" in error &&
63
+ error.code === "PAYLOAD_TOO_LARGE") {
64
+ sendResponse(res, {
65
+ status: 413,
66
+ body: {
67
+ error: {
68
+ type: "PAYLOAD_TOO_LARGE",
69
+ message: "Request body exceeds the configured size limit",
70
+ },
71
+ },
72
+ });
73
+ return;
74
+ }
42
75
  const payload = error && typeof error === "object" && "status" in error
43
76
  ? error
44
77
  : {
@@ -52,12 +85,39 @@ const sendError = (res, error) => {
52
85
  };
53
86
  sendResponse(res, payload);
54
87
  };
55
- export const createNodeHandler = (handler) => {
88
+ export const createNodeHandler = (handler, options = {}) => {
89
+ const bodyLimit = options.bodyLimit ?? DEFAULT_BODY_LIMIT;
90
+ const requestTimeout = options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
56
91
  return async (req, res) => {
57
92
  try {
58
- const request = await buildServeRequest(req);
59
- const response = await handler(request);
60
- sendResponse(res, response);
93
+ const request = await buildServeRequest(req, bodyLimit);
94
+ if (requestTimeout > 0) {
95
+ // Race the handler against the timeout
96
+ const timeoutPromise = new Promise((resolve) => {
97
+ const timer = setTimeout(() => {
98
+ resolve({
99
+ status: 504,
100
+ body: {
101
+ error: {
102
+ type: "GATEWAY_TIMEOUT",
103
+ message: `Request timed out after ${requestTimeout}ms`,
104
+ },
105
+ },
106
+ });
107
+ }, requestTimeout);
108
+ // Unref so the timer doesn't keep the process alive during shutdown
109
+ timer.unref();
110
+ });
111
+ const response = await Promise.race([
112
+ handler(request),
113
+ timeoutPromise,
114
+ ]);
115
+ sendResponse(res, response);
116
+ }
117
+ else {
118
+ const response = await handler(request);
119
+ sendResponse(res, response);
120
+ }
61
121
  }
62
122
  catch (error) {
63
123
  sendError(res, error);
@@ -65,12 +125,55 @@ export const createNodeHandler = (handler) => {
65
125
  };
66
126
  };
67
127
  export const startNodeServer = async (handler, options = {}) => {
68
- const listener = createNodeHandler(handler);
128
+ const listener = createNodeHandler(handler, options);
69
129
  const server = createServer(listener);
70
130
  const port = options.port ?? 3000;
71
131
  const hostname = options.hostname ?? "0.0.0.0";
132
+ const gracefulShutdownTimeout = options.gracefulShutdownTimeout ?? DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT;
133
+ // Track in-flight requests for graceful shutdown
134
+ let inFlightRequests = 0;
135
+ let isDraining = false;
136
+ server.on("request", (_req, res) => {
137
+ inFlightRequests++;
138
+ if (isDraining) {
139
+ // Signal to the client that the connection will close
140
+ res.setHeader("connection", "close");
141
+ }
142
+ res.on("close", () => {
143
+ inFlightRequests--;
144
+ });
145
+ });
146
+ const gracefulStop = () => new Promise((resolve) => {
147
+ isDraining = true;
148
+ // Stop accepting new connections
149
+ server.close(() => {
150
+ resolve();
151
+ });
152
+ // If there are no in-flight requests, we're done once server.close completes
153
+ if (inFlightRequests === 0) {
154
+ return;
155
+ }
156
+ // Wait for in-flight requests, with a hard deadline
157
+ const deadline = setTimeout(() => {
158
+ if (!options.quiet) {
159
+ console.log(`[hypequery/serve] Forcing shutdown with ${inFlightRequests} in-flight request(s)`);
160
+ }
161
+ // Force-close all remaining connections
162
+ server.closeAllConnections();
163
+ }, gracefulShutdownTimeout);
164
+ deadline.unref();
165
+ // Also resolve early if all requests finish before the deadline
166
+ const checkInterval = setInterval(() => {
167
+ if (inFlightRequests <= 0) {
168
+ clearTimeout(deadline);
169
+ clearInterval(checkInterval);
170
+ // server.close callback will resolve the promise
171
+ }
172
+ }, 50);
173
+ checkInterval.unref();
174
+ });
72
175
  const onAbort = () => {
73
- server.close();
176
+ gracefulStop();
74
177
  };
75
178
  if (options.signal) {
76
179
  if (options.signal.aborted) {
@@ -88,18 +191,8 @@ export const startNodeServer = async (handler, options = {}) => {
88
191
  : `${hostname}:${port}`;
89
192
  console.log(`hypequery serve listening on ${display}`);
90
193
  }
91
- const stop = () => new Promise((resolve, reject) => {
92
- server.close((err) => {
93
- if (err) {
94
- reject(err);
95
- }
96
- else {
97
- resolve();
98
- }
99
- });
100
- });
101
194
  return {
102
195
  server,
103
- stop,
196
+ stop: gracefulStop,
104
197
  };
105
198
  };
package/dist/auth.d.ts CHANGED
@@ -79,7 +79,7 @@ export declare const checkScopeAuthorization: (auth: AuthContext | null, require
79
79
  *
80
80
  * @deprecated Use `query.requireAuth()` instead for per-endpoint authentication.
81
81
  * This middleware is kept for complex use cases where guards aren't suitable.
82
- * See: https://hypequery.com/docs/serve/authentication#middleware-helpers
82
+ * See: https://hypequery.com/docs/authentication#middleware-helpers
83
83
  *
84
84
  * Use this as a global middleware via `api.use(requireAuthMiddleware())`.
85
85
  * For per-query guards, prefer `query.requireAuth()`.
@@ -91,7 +91,7 @@ export declare const requireAuthMiddleware: <TContext extends Record<string, unk
91
91
  *
92
92
  * @deprecated Use `query.requireRole(...)` instead for per-endpoint authorization.
93
93
  * This middleware is kept for complex use cases where guards aren't suitable.
94
- * See: https://hypequery.com/docs/serve/authentication#middleware-helpers
94
+ * See: https://hypequery.com/docs/authentication#middleware-helpers
95
95
  *
96
96
  * Use this as a global or per-query middleware via `api.use(requireRoleMiddleware('admin'))`.
97
97
  * For per-query guards, prefer `query.requireRole('admin')`.
@@ -103,7 +103,7 @@ export declare const requireRoleMiddleware: <TContext extends Record<string, unk
103
103
  *
104
104
  * @deprecated Use `query.requireScope(...)` instead for per-endpoint authorization.
105
105
  * This middleware is kept for complex use cases where guards aren't suitable.
106
- * See: https://hypequery.com/docs/serve/authentication#middleware-helpers
106
+ * See: https://hypequery.com/docs/authentication#middleware-helpers
107
107
  *
108
108
  * Use this as a global or per-query middleware via `api.use(requireScopeMiddleware('read:metrics'))`.
109
109
  * For per-query guards, prefer `query.requireScope('read:metrics')`.
@@ -146,7 +146,7 @@ export type TypedAuthContext<TRoles extends string, TScopes extends string> = Au
146
146
  *
147
147
  * @example
148
148
  * ```ts
149
- * import { createAuthSystem, defineServe, query } from '@hypequery/serve';
149
+ * import { createAuthSystem, initServe } from '@hypequery/serve';
150
150
  *
151
151
  * // Define your roles and scopes up front
152
152
  * const { useAuth, TypedAuth } = createAuthSystem({
@@ -154,26 +154,36 @@ export type TypedAuthContext<TRoles extends string, TScopes extends string> = Au
154
154
  * scopes: ['read:metrics', 'write:metrics', 'delete:metrics'] as const,
155
155
  * });
156
156
  *
157
- * // Extract the typed auth type for use with defineServe
157
+ * // Extract the typed auth type for use with initServe
158
158
  * type AppAuth = TypedAuth;
159
159
  *
160
- * const api = defineServe<AppAuth>({
160
+ * const { query, serve } = initServe<Record<string, never>, AppAuth>({
161
161
  * auth: useAuth(jwtStrategy),
162
- * queries: {
163
- * adminOnly: query.requireRole('admin').query(async ({ ctx }) => {
164
- * // TypeScript autocomplete for 'admin'
165
- * // ❌ Compile error on typo like 'admn'
166
- * return { secret: true };
167
- * }),
168
- * writeData: query.requireScope('write:metrics').query(async ({ ctx }) => {
169
- * // TypeScript autocomplete for 'write:metrics'
170
- * return { success: true };
171
- * }),
162
+ * });
163
+ *
164
+ * const adminOnly = query({
165
+ * requiredRoles: ['admin'],
166
+ * query: async () => {
167
+ * // ✅ TypeScript autocomplete for 'admin'
168
+ * // Compile error on typo like 'admn'
169
+ * return { secret: true };
172
170
  * },
173
171
  * });
172
+ *
173
+ * const writeData = query({
174
+ * requiredScopes: ['write:metrics'],
175
+ * query: async () => {
176
+ * // ✅ TypeScript autocomplete for 'write:metrics'
177
+ * return { success: true };
178
+ * },
179
+ * });
180
+ *
181
+ * const api = serve({
182
+ * queries: { adminOnly, writeData },
183
+ * });
174
184
  * ```
175
185
  */
176
- export declare const createAuthSystem: <TRoles extends string = string, TScopes extends string = string>(options?: CreateAuthSystemOptions<TRoles, TScopes>) => {
186
+ export declare const createAuthSystem: <TRoles extends string = string, TScopes extends string = string>() => {
177
187
  /**
178
188
  * Type-safe wrapper for auth strategies.
179
189
  * Ensures the strategy returns auth context with the correct role/scope types.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,eAAe,EACf,YAAY,EACb,MAAM,YAAY,CAAC;AAWpB;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,SAAS,YAAY,EAAE,MAAM,MAAM,KAAG,MAAM,GAAG,SAexE,CAAC;AAEF,qBAAa,SAAU,SAAQ,KAAM,YAAW,aAAa;IAC3D,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEtB,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAMhG;AAED,MAAM,WAAW,iBAAiB,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;CACxF;AAED;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,SAAS,WAAW,GAAG,WAAW,EAChE,SAAS,iBAAiB,CAAC,KAAK,CAAC,KAChC,YAAY,CAAC,KAAK,CAiBpB,CAAC;AAEF,MAAM,WAAW,qBAAqB,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;CACxF;AAED,eAAO,MAAM,oBAAoB,GAAI,KAAK,SAAS,WAAW,GAAG,WAAW,EAC1E,SAAS,qBAAqB,CAAC,KAAK,CAAC,KACpC,YAAY,CAAC,KAAK,CA0BpB,CAAC;AAEF,MAAM,WAAW,0BAA0B,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;CAC1F;AAED,eAAO,MAAM,yBAAyB,GAAI,KAAK,SAAS,WAAW,GAAG,WAAW,EAC/E,SAAS,0BAA0B,CAAC,KAAK,CAAC,KACzC,YAAY,CAAC,KAAK,CAepB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAAA;CAAE,CAAC;AAE/E;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,WAAW,GAAG,IAAI,EACxB,eAAe,MAAM,EAAE,KACtB,mBAWF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uBAAuB,GAClC,MAAM,WAAW,GAAG,IAAI,EACxB,gBAAgB,MAAM,EAAE,KACvB,mBAWF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,KAAK,SAAS,WAAW,GAAG,WAAW,OACpC,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAS3C,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,KAAK,SAAS,WAAW,GAAG,WAAW,EAEvC,GAAG,OAAO,MAAM,EAAE,KACjB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAUzC,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GACjC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,KAAK,SAAS,WAAW,GAAG,WAAW,EAEvC,GAAG,QAAQ,MAAM,EAAE,KAClB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAUzC,CAAC;AAEJ;;;GAGG;AACH,MAAM,WAAW,uBAAuB,CACtC,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,OAAO,SAAS,MAAM,GAAG,MAAM;IAE/B;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAE1B;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAC1B,MAAM,SAAS,MAAM,EACrB,OAAO,SAAS,MAAM,IACpB,oBAAoB,CAAC,MAAM,CAAC,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,OAAO,SAAS,MAAM,GAAG,MAAM;IAG7B;;;;;;;;;;;;;;;;;;;;;OAqBG;cACO,KAAK,SAAS,WAAW,YACvB,YAAY,CAAC,KAAK,CAAC,KAC5B,YAAY,CAAC,KAAK,CAAC;IAEtB;;;;;;;;OAQG;eAC2B,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC;CAElE,CAAC"}
package/dist/auth.js CHANGED
@@ -152,7 +152,7 @@ export const checkScopeAuthorization = (auth, requiredScopes) => {
152
152
  *
153
153
  * @deprecated Use `query.requireAuth()` instead for per-endpoint authentication.
154
154
  * This middleware is kept for complex use cases where guards aren't suitable.
155
- * See: https://hypequery.com/docs/serve/authentication#middleware-helpers
155
+ * See: https://hypequery.com/docs/authentication#middleware-helpers
156
156
  *
157
157
  * Use this as a global middleware via `api.use(requireAuthMiddleware())`.
158
158
  * For per-query guards, prefer `query.requireAuth()`.
@@ -172,7 +172,7 @@ export const requireAuthMiddleware = () => async (ctx, next) => {
172
172
  *
173
173
  * @deprecated Use `query.requireRole(...)` instead for per-endpoint authorization.
174
174
  * This middleware is kept for complex use cases where guards aren't suitable.
175
- * See: https://hypequery.com/docs/serve/authentication#middleware-helpers
175
+ * See: https://hypequery.com/docs/authentication#middleware-helpers
176
176
  *
177
177
  * Use this as a global or per-query middleware via `api.use(requireRoleMiddleware('admin'))`.
178
178
  * For per-query guards, prefer `query.requireRole('admin')`.
@@ -190,7 +190,7 @@ export const requireRoleMiddleware = (...roles) => async (ctx, next) => {
190
190
  *
191
191
  * @deprecated Use `query.requireScope(...)` instead for per-endpoint authorization.
192
192
  * This middleware is kept for complex use cases where guards aren't suitable.
193
- * See: https://hypequery.com/docs/serve/authentication#middleware-helpers
193
+ * See: https://hypequery.com/docs/authentication#middleware-helpers
194
194
  *
195
195
  * Use this as a global or per-query middleware via `api.use(requireScopeMiddleware('read:metrics'))`.
196
196
  * For per-query guards, prefer `query.requireScope('read:metrics')`.
@@ -212,7 +212,7 @@ export const requireScopeMiddleware = (...scopes) => async (ctx, next) => {
212
212
  *
213
213
  * @example
214
214
  * ```ts
215
- * import { createAuthSystem, defineServe, query } from '@hypequery/serve';
215
+ * import { createAuthSystem, initServe } from '@hypequery/serve';
216
216
  *
217
217
  * // Define your roles and scopes up front
218
218
  * const { useAuth, TypedAuth } = createAuthSystem({
@@ -220,26 +220,36 @@ export const requireScopeMiddleware = (...scopes) => async (ctx, next) => {
220
220
  * scopes: ['read:metrics', 'write:metrics', 'delete:metrics'] as const,
221
221
  * });
222
222
  *
223
- * // Extract the typed auth type for use with defineServe
223
+ * // Extract the typed auth type for use with initServe
224
224
  * type AppAuth = TypedAuth;
225
225
  *
226
- * const api = defineServe<AppAuth>({
226
+ * const { query, serve } = initServe<Record<string, never>, AppAuth>({
227
227
  * auth: useAuth(jwtStrategy),
228
- * queries: {
229
- * adminOnly: query.requireRole('admin').query(async ({ ctx }) => {
230
- * // TypeScript autocomplete for 'admin'
231
- * // ❌ Compile error on typo like 'admn'
232
- * return { secret: true };
233
- * }),
234
- * writeData: query.requireScope('write:metrics').query(async ({ ctx }) => {
235
- * // TypeScript autocomplete for 'write:metrics'
236
- * return { success: true };
237
- * }),
228
+ * });
229
+ *
230
+ * const adminOnly = query({
231
+ * requiredRoles: ['admin'],
232
+ * query: async () => {
233
+ * // ✅ TypeScript autocomplete for 'admin'
234
+ * // Compile error on typo like 'admn'
235
+ * return { secret: true };
238
236
  * },
239
237
  * });
238
+ *
239
+ * const writeData = query({
240
+ * requiredScopes: ['write:metrics'],
241
+ * query: async () => {
242
+ * // ✅ TypeScript autocomplete for 'write:metrics'
243
+ * return { success: true };
244
+ * },
245
+ * });
246
+ *
247
+ * const api = serve({
248
+ * queries: { adminOnly, writeData },
249
+ * });
240
250
  * ```
241
251
  */
242
- export const createAuthSystem = (options = {}) => {
252
+ export const createAuthSystem = () => {
243
253
  return {
244
254
  /**
245
255
  * Type-safe wrapper for auth strategies.
package/dist/cors.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { CorsConfig, ServeRequest, ServeResponse } from './types.js';
2
+ export interface ResolvedCorsConfig {
3
+ origin: string | string[] | ((origin: string) => boolean);
4
+ methods: string[];
5
+ allowedHeaders: string[];
6
+ exposedHeaders: string[];
7
+ credentials: boolean;
8
+ maxAge: number;
9
+ }
10
+ export declare const resolveCorsConfig: (config: boolean | CorsConfig | undefined) => ResolvedCorsConfig | null;
11
+ export declare const buildCorsHeaders: (config: ResolvedCorsConfig, requestOrigin: string | undefined) => Record<string, string>;
12
+ export declare const buildPreflightHeaders: (config: ResolvedCorsConfig, requestOrigin: string | undefined) => Record<string, string>;
13
+ export declare const handleCorsRequest: (config: ResolvedCorsConfig | null, request: ServeRequest) => {
14
+ preflightResponse: ServeResponse | null;
15
+ corsHeaders: Record<string, string>;
16
+ };
17
+ //# sourceMappingURL=cors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../src/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAM1E,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;IAC1D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,OAAO,GAAG,UAAU,GAAG,SAAS,KACvC,kBAAkB,GAAG,IAavB,CAAC;AA8BF,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,kBAAkB,EAC1B,eAAe,MAAM,GAAG,SAAS,KAChC,MAAM,CAAC,MAAM,EAAE,MAAM,CAqBvB,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,QAAQ,kBAAkB,EAC1B,eAAe,MAAM,GAAG,SAAS,KAChC,MAAM,CAAC,MAAM,EAAE,MAAM,CAWvB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,kBAAkB,GAAG,IAAI,EACjC,SAAS,YAAY,KACpB;IAAE,iBAAiB,EAAE,aAAa,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAsBhF,CAAC"}
package/dist/cors.js ADDED
@@ -0,0 +1,82 @@
1
+ const DEFAULT_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
2
+ const DEFAULT_ALLOWED_HEADERS = ['Content-Type', 'Authorization', 'X-Request-ID'];
3
+ const DEFAULT_MAX_AGE = 86400; // 24 hours
4
+ export const resolveCorsConfig = (config) => {
5
+ if (!config)
6
+ return null;
7
+ const opts = config === true ? {} : config;
8
+ return {
9
+ origin: opts.origin ?? '*',
10
+ methods: opts.methods ?? DEFAULT_METHODS,
11
+ allowedHeaders: opts.allowedHeaders ?? DEFAULT_ALLOWED_HEADERS,
12
+ exposedHeaders: opts.exposedHeaders ?? [],
13
+ credentials: opts.credentials ?? false,
14
+ maxAge: opts.maxAge ?? DEFAULT_MAX_AGE,
15
+ };
16
+ };
17
+ const matchOrigin = (config, requestOrigin) => {
18
+ if (!requestOrigin)
19
+ return null;
20
+ const { origin } = config;
21
+ if (origin === '*') {
22
+ // When credentials are enabled, we must echo the origin instead of "*"
23
+ return config.credentials ? requestOrigin : '*';
24
+ }
25
+ if (typeof origin === 'string') {
26
+ return origin === requestOrigin ? origin : null;
27
+ }
28
+ if (Array.isArray(origin)) {
29
+ return origin.includes(requestOrigin) ? requestOrigin : null;
30
+ }
31
+ if (typeof origin === 'function') {
32
+ return origin(requestOrigin) ? requestOrigin : null;
33
+ }
34
+ return null;
35
+ };
36
+ export const buildCorsHeaders = (config, requestOrigin) => {
37
+ const headers = {};
38
+ const allowedOrigin = matchOrigin(config, requestOrigin);
39
+ if (!allowedOrigin)
40
+ return headers;
41
+ headers['access-control-allow-origin'] = allowedOrigin;
42
+ if (allowedOrigin !== '*') {
43
+ headers['vary'] = 'Origin';
44
+ }
45
+ if (config.credentials) {
46
+ headers['access-control-allow-credentials'] = 'true';
47
+ }
48
+ if (config.exposedHeaders.length > 0) {
49
+ headers['access-control-expose-headers'] = config.exposedHeaders.join(', ');
50
+ }
51
+ return headers;
52
+ };
53
+ export const buildPreflightHeaders = (config, requestOrigin) => {
54
+ const headers = buildCorsHeaders(config, requestOrigin);
55
+ // No matching origin → don't add preflight headers
56
+ if (!headers['access-control-allow-origin'])
57
+ return headers;
58
+ headers['access-control-allow-methods'] = config.methods.join(', ');
59
+ headers['access-control-allow-headers'] = config.allowedHeaders.join(', ');
60
+ headers['access-control-max-age'] = String(config.maxAge);
61
+ return headers;
62
+ };
63
+ export const handleCorsRequest = (config, request) => {
64
+ if (!config) {
65
+ return { preflightResponse: null, corsHeaders: {} };
66
+ }
67
+ const requestOrigin = request.headers['origin'];
68
+ if (request.method === 'OPTIONS') {
69
+ return {
70
+ preflightResponse: {
71
+ status: 204,
72
+ headers: buildPreflightHeaders(config, requestOrigin),
73
+ body: '',
74
+ },
75
+ corsHeaders: {},
76
+ };
77
+ }
78
+ return {
79
+ preflightResponse: null,
80
+ corsHeaders: buildCorsHeaders(config, requestOrigin),
81
+ };
82
+ };
package/dist/dev.js CHANGED
@@ -7,7 +7,7 @@ export const serveDev = async (api, options = {}) => {
7
7
  const port = options.port ?? Number(process.env.PORT ?? 4000);
8
8
  const hostname = options.hostname ?? "localhost";
9
9
  const logger = options.logger ?? defaultLogger;
10
- const unsubscribe = api.queryLogger.on((event) => {
10
+ api.queryLogger.on((event) => {
11
11
  const line = formatQueryEvent(event);
12
12
  if (line)
13
13
  logger(line);
@@ -0,0 +1,24 @@
1
+ import type { ServeErrorType } from './types.js';
2
+ /**
3
+ * Structured error class for hypequery serve handlers and middleware.
4
+ *
5
+ * Throw this from a handler or middleware to return a specific HTTP status
6
+ * and error type to the client. The pipeline catch block recognises the
7
+ * `status` + `payload` shape and forwards it as-is.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * throw new ServeHttpError(403, 'UNAUTHORIZED', 'Insufficient permissions');
12
+ * throw new ServeHttpError(429, 'RATE_LIMITED', 'Too fast', { 'retry-after': '60' });
13
+ * ```
14
+ */
15
+ export declare class ServeHttpError extends Error {
16
+ readonly status: number;
17
+ readonly payload: {
18
+ type: ServeErrorType;
19
+ message: string;
20
+ };
21
+ readonly headers?: Record<string, string>;
22
+ constructor(status: number, type: ServeErrorType, message: string, headers?: Record<string, string>);
23
+ }
24
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,cAAc,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAGxC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAQnC"}
package/dist/errors.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Structured error class for hypequery serve handlers and middleware.
3
+ *
4
+ * Throw this from a handler or middleware to return a specific HTTP status
5
+ * and error type to the client. The pipeline catch block recognises the
6
+ * `status` + `payload` shape and forwards it as-is.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * throw new ServeHttpError(403, 'UNAUTHORIZED', 'Insufficient permissions');
11
+ * throw new ServeHttpError(429, 'RATE_LIMITED', 'Too fast', { 'retry-after': '60' });
12
+ * ```
13
+ */
14
+ export class ServeHttpError extends Error {
15
+ constructor(status, type, message, headers) {
16
+ super(message);
17
+ this.name = 'ServeHttpError';
18
+ this.status = status;
19
+ this.payload = { type, message };
20
+ this.headers = headers;
21
+ }
22
+ }
package/dist/index.d.ts CHANGED
@@ -6,10 +6,14 @@ export * from "./endpoint.js";
6
6
  export * from "./openapi.js";
7
7
  export * from "./docs-ui.js";
8
8
  export * from "./auth.js";
9
+ export * from "./cors.js";
10
+ export * from "./errors.js";
11
+ export * from "./rate-limit.js";
9
12
  export * from "./client-config.js";
10
13
  export * from "./utils.js";
11
14
  export * from "./adapters/node.js";
12
15
  export * from "./adapters/fetch.js";
13
16
  export * from "./adapters/vercel.js";
14
17
  export * from "./dev.js";
18
+ export * from "./serve.js";
15
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -6,9 +6,13 @@ export * from "./endpoint.js";
6
6
  export * from "./openapi.js";
7
7
  export * from "./docs-ui.js";
8
8
  export * from "./auth.js";
9
+ export * from "./cors.js";
10
+ export * from "./errors.js";
11
+ export * from "./rate-limit.js";
9
12
  export * from "./client-config.js";
10
13
  export * from "./utils.js";
11
14
  export * from "./adapters/node.js";
12
15
  export * from "./adapters/fetch.js";
13
16
  export * from "./adapters/vercel.js";
14
17
  export * from "./dev.js";
18
+ export * from "./serve.js";
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import type { AuthContext, AuthStrategy, DocsOptions, OpenApiOptions, ServeContextFactory, ServeEndpoint, ServeHandler, ServeLifecycleHooks, ServeMiddleware, ServeRequest, ServeResponse, TenantConfig } from './types.js';
3
3
  import { ServeQueryLogger } from './query-logger.js';
4
+ import { type ResolvedCorsConfig } from './cors.js';
4
5
  export interface ExecuteEndpointOptions<TContext extends Record<string, unknown>, TAuth extends AuthContext> {
5
6
  endpoint: ServeEndpoint<any, any, TContext, TAuth>;
6
7
  request: ServeRequest;
@@ -13,6 +14,11 @@ export interface ExecuteEndpointOptions<TContext extends Record<string, unknown>
13
14
  queryLogger?: ServeQueryLogger;
14
15
  additionalContext?: Partial<TContext>;
15
16
  verboseAuthErrors?: boolean;
17
+ /**
18
+ * When true (the default), internal error details are hidden from responses.
19
+ * Set to false for in-process execution where the caller is trusted.
20
+ */
21
+ sanitizeErrors?: boolean;
16
22
  }
17
23
  export declare const executeEndpoint: <TContext extends Record<string, unknown>, TAuth extends AuthContext>(options: ExecuteEndpointOptions<TContext, TAuth>) => Promise<ServeResponse>;
18
24
  interface HandlerOptions<TContext extends Record<string, unknown>, TAuth extends AuthContext> {
@@ -24,8 +30,9 @@ interface HandlerOptions<TContext extends Record<string, unknown>, TAuth extends
24
30
  hooks?: ServeLifecycleHooks<TAuth>;
25
31
  queryLogger?: ServeQueryLogger;
26
32
  verboseAuthErrors?: boolean;
33
+ corsConfig?: ResolvedCorsConfig | null;
27
34
  }
28
- export declare const createServeHandler: <TContext extends Record<string, unknown>, TAuth extends AuthContext>({ router, globalMiddlewares, authStrategies, tenantConfig, contextFactory, hooks, queryLogger, verboseAuthErrors, }: HandlerOptions<TContext, TAuth>) => ServeHandler;
35
+ export declare const createServeHandler: <TContext extends Record<string, unknown>, TAuth extends AuthContext>({ router, globalMiddlewares, authStrategies, tenantConfig, contextFactory, hooks, queryLogger, verboseAuthErrors, corsConfig, }: HandlerOptions<TContext, TAuth>) => ServeHandler;
29
36
  export declare const createOpenApiEndpoint: (path: string, getEndpoints: () => ServeEndpoint<any, any, any, any>[], options?: OpenApiOptions) => {
30
37
  key: string;
31
38
  method: "GET";
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAmB,MAAM,KAAK,CAAC;AAEzC,OAAO,KAAK,EACV,WAAW,EAEX,YAAY,EACZ,WAAW,EAKX,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,YAAY,EAGb,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AA+MrD,MAAM,WAAW,sBAAsB,CACrC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,KAAK,SAAS,WAAW;IAEzB,QAAQ,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACnD,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;IACtC,cAAc,CAAC,EAAE,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtD,iBAAiB,EAAE,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;IAChE,YAAY,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,eAAe,GAC1B,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,KAAK,SAAS,WAAW,EAEzB,SAAS,sBAAsB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAC/C,OAAO,CAAC,aAAa,CA+RvB,CAAC;AAEF,UAAU,cAAc,CACtB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,KAAK,SAAS,WAAW;IAEzB,MAAM,EAAE,OAAO,aAAa,EAAE,WAAW,CAAC;IAC1C,iBAAiB,EAAE,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;IAChE,cAAc,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;IACtC,YAAY,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,cAAc,CAAC,EAAE,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtD,KAAK,CAAC,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,KAAK,SAAS,WAAW,EACzB,qHASC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAG,YA2BpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,MAAM,MAAM,EACZ,cAAc,MAAM,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,EACvD,UAAU,cAAc;;;;;;;;;;;;;;;;;;;;;CA8BzB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,MAAM,MAAM,EACZ,aAAa,MAAM,EACnB,UAAU,WAAW;;;;;;;;;;;;;;;;;;;;;;;;CAyBmD,CAAC"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}