@jaypie/express 1.2.20 → 1.2.22

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.
@@ -3,6 +3,7 @@ export type { ApiGatewayV1Event, CreateLambdaHandlerOptions, FunctionUrlEvent, L
3
3
  export { EXPRESS } from "./constants.js";
4
4
  export { default as cors } from "./cors.helper.js";
5
5
  export type { CorsConfig } from "./cors.helper.js";
6
+ export { default as fabricApiResponse } from "./fabricApiResponse.js";
6
7
  export { default as expressHandler } from "./expressHandler.js";
7
8
  export type { ExpressHandlerLocals, ExpressHandlerOptions, JaypieHandlerSetup, JaypieHandlerTeardown, JaypieHandlerValidate, } from "./expressHandler.js";
8
9
  export { default as expressHttpCodeHandler } from "./http.handler.js";
@@ -5,6 +5,13 @@ export type JaypieHandlerValidate = (req: Request, res: Response) => Promise<boo
5
5
  export type ExpressHandlerLocals = (req: Request, res: Response) => Promise<unknown> | unknown;
6
6
  export interface ExpressHandlerOptions {
7
7
  chaos?: string;
8
+ /**
9
+ * When true, the handler's return value is wrapped with
10
+ * `fabricApiResponse` before `res.json()`. Plain objects become
11
+ * `{ data: value }`; pre-wrapped `{ data }` or `{ errors }` payloads
12
+ * pass through unchanged. `null` / `undefined` become `{ data: null }`.
13
+ */
14
+ fabric?: boolean;
8
15
  locals?: Record<string, unknown | ExpressHandlerLocals>;
9
16
  name?: string;
10
17
  secrets?: string[];
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Wrap a service return value in the canonical Jaypie API envelope.
3
+ *
4
+ * Rules:
5
+ * - `null` / `undefined` → `{ data: null }`
6
+ * - `{ data }` with exactly one key → passthrough
7
+ * - `{ errors }` with exactly one key → passthrough
8
+ * - everything else (including `{ data, other }`) → `{ data: value }`
9
+ *
10
+ * The "only one key, and that key is `data` or `errors`" check prevents
11
+ * false positives where a domain object happens to contain a `data` field.
12
+ */
13
+ export declare function fabricApiResponse(result: unknown): unknown;
14
+ export default fabricApiResponse;
@@ -3,6 +3,7 @@ export type { ApiGatewayV1Event, CreateLambdaHandlerOptions, FunctionUrlEvent, L
3
3
  export { EXPRESS } from "./constants.js";
4
4
  export { default as cors } from "./cors.helper.js";
5
5
  export type { CorsConfig } from "./cors.helper.js";
6
+ export { default as fabricApiResponse } from "./fabricApiResponse.js";
6
7
  export { default as expressHandler } from "./expressHandler.js";
7
8
  export type { ExpressHandlerLocals, ExpressHandlerOptions, JaypieHandlerSetup, JaypieHandlerTeardown, JaypieHandlerValidate, } from "./expressHandler.js";
8
9
  export { default as expressHttpCodeHandler } from "./http.handler.js";
package/dist/esm/index.js CHANGED
@@ -1355,6 +1355,48 @@ var cors_helper = (config) => {
1355
1355
  };
1356
1356
  };
1357
1357
 
1358
+ //
1359
+ //
1360
+ // Helpers
1361
+ //
1362
+ function isWrappedData(value) {
1363
+ return (typeof value === "object" &&
1364
+ value !== null &&
1365
+ !Array.isArray(value) &&
1366
+ Object.keys(value).length === 1 &&
1367
+ "data" in value);
1368
+ }
1369
+ function isWrappedErrors(value) {
1370
+ return (typeof value === "object" &&
1371
+ value !== null &&
1372
+ !Array.isArray(value) &&
1373
+ Object.keys(value).length === 1 &&
1374
+ "errors" in value);
1375
+ }
1376
+ //
1377
+ //
1378
+ // Main
1379
+ //
1380
+ /**
1381
+ * Wrap a service return value in the canonical Jaypie API envelope.
1382
+ *
1383
+ * Rules:
1384
+ * - `null` / `undefined` → `{ data: null }`
1385
+ * - `{ data }` with exactly one key → passthrough
1386
+ * - `{ errors }` with exactly one key → passthrough
1387
+ * - everything else (including `{ data, other }`) → `{ data: value }`
1388
+ *
1389
+ * The "only one key, and that key is `data` or `errors`" check prevents
1390
+ * false positives where a domain object happens to contain a `data` field.
1391
+ */
1392
+ function fabricApiResponse(result) {
1393
+ if (result === null || result === undefined)
1394
+ return { data: null };
1395
+ if (isWrappedData(result) || isWrappedErrors(result))
1396
+ return result;
1397
+ return { data: result };
1398
+ }
1399
+
1358
1400
  //
1359
1401
  //
1360
1402
  // Helper Functions
@@ -1717,7 +1759,7 @@ function expressHandler(handlerOrOptions, optionsOrHandler) {
1717
1759
  //
1718
1760
  // Validate
1719
1761
  //
1720
- let { chaos, locals, name, secrets, setup = [], teardown = [], unavailable, validate, } = options;
1762
+ let { chaos, fabric, locals, name, secrets, setup = [], teardown = [], unavailable, validate, } = options;
1721
1763
  if (typeof handler !== "function") {
1722
1764
  throw new BadRequestError(`Argument "${handler}" doesn't match type "function"`);
1723
1765
  }
@@ -1871,6 +1913,9 @@ function expressHandler(handlerOrOptions, optionsOrHandler) {
1871
1913
  // Process
1872
1914
  //
1873
1915
  response = (await jaypieFunction(req, res, ...params));
1916
+ if (fabric) {
1917
+ response = fabricApiResponse(response);
1918
+ }
1874
1919
  //
1875
1920
  //
1876
1921
  // Error Handling
@@ -1987,7 +2032,11 @@ function expressHandler(handlerOrOptions, optionsOrHandler) {
1987
2032
  // Replace UUIDs with :id for better aggregation
1988
2033
  path = path.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, ":id");
1989
2034
  // Add request data to session report
1990
- logger$1.report({ path, status: String(res.statusCode) });
2035
+ logger$1.report({
2036
+ method: req.method,
2037
+ path,
2038
+ status: String(res.statusCode),
2039
+ });
1991
2040
  // Submit metric if Datadog is configured
1992
2041
  if (hasDatadogEnv()) {
1993
2042
  let metricPrefix = "project";
@@ -2268,7 +2317,11 @@ function expressStreamHandler(handlerOrOptions, optionsOrHandler) {
2268
2317
  }
2269
2318
  path = path.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, ":id");
2270
2319
  // Add request data to session report
2271
- logger.report({ path, status: String(res.statusCode) });
2320
+ logger.report({
2321
+ method: req.method,
2322
+ path,
2323
+ status: String(res.statusCode),
2324
+ });
2272
2325
  // Submit metric if Datadog is configured
2273
2326
  if (hasDatadogEnv()) {
2274
2327
  let metricPrefix = "project";
@@ -2348,5 +2401,5 @@ const noContentRoute = routes.noContentRoute;
2348
2401
  const notFoundRoute = routes.notFoundRoute;
2349
2402
  const notImplementedRoute = routes.notImplementedRoute;
2350
2403
 
2351
- export { EXPRESS, LambdaRequest, LambdaResponseBuffered, LambdaResponseStreaming, badRequestRoute, cors_helper as cors, createLambdaHandler, createLambdaStreamHandler, echoRoute, expressHandler, httpHandler as expressHttpCodeHandler, expressStreamHandler, forbiddenRoute, getCurrentInvoke, getCurrentInvokeUuid, goneRoute, methodNotAllowedRoute, noContentRoute, notFoundRoute, notImplementedRoute };
2404
+ export { EXPRESS, LambdaRequest, LambdaResponseBuffered, LambdaResponseStreaming, badRequestRoute, cors_helper as cors, createLambdaHandler, createLambdaStreamHandler, echoRoute, expressHandler, httpHandler as expressHttpCodeHandler, expressStreamHandler, fabricApiResponse, forbiddenRoute, getCurrentInvoke, getCurrentInvokeUuid, goneRoute, methodNotAllowedRoute, noContentRoute, notFoundRoute, notImplementedRoute };
2352
2405
  //# sourceMappingURL=index.js.map