@cadenza.io/service 2.17.73 → 2.17.75

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/dist/index.d.mts CHANGED
@@ -22926,6 +22926,8 @@ declare class RestController {
22926
22926
  private resolveTransportDiagnosticsOptions;
22927
22927
  private ensureFetchClientDiagnostics;
22928
22928
  private getErrorMessage;
22929
+ private resolveJsonBodyLimit;
22930
+ private parseFetchResponse;
22929
22931
  private resolveDelegationTimeoutMs;
22930
22932
  private recordFetchClientError;
22931
22933
  private collectFetchTransportDiagnostics;
package/dist/index.d.ts CHANGED
@@ -22926,6 +22926,8 @@ declare class RestController {
22926
22926
  private resolveTransportDiagnosticsOptions;
22927
22927
  private ensureFetchClientDiagnostics;
22928
22928
  private getErrorMessage;
22929
+ private resolveJsonBodyLimit;
22930
+ private parseFetchResponse;
22929
22931
  private resolveDelegationTimeoutMs;
22930
22932
  private recordFetchClientError;
22931
22933
  private collectFetchTransportDiagnostics;
package/dist/index.js CHANGED
@@ -3663,11 +3663,12 @@ var RestController = class _RestController {
3663
3663
  * @returns {Promise<any>} A promise that resolves to the parsed response data if the request is successful.
3664
3664
  * @throws {Error} Throws an error if the request fails due to issues such as timeout or other unexpected errors.
3665
3665
  */
3666
- this.fetchDataWithTimeout = async function(url, requestInit, timeoutMs) {
3666
+ this.fetchDataWithTimeout = async (url, requestInit, timeoutMs) => {
3667
3667
  const signal = AbortSignal.timeout(timeoutMs);
3668
3668
  try {
3669
3669
  const response = await (0, import_node_fetch.default)(url, { ...requestInit, signal });
3670
- return await response.json();
3670
+ const parsedResponse = await this.parseFetchResponse(response);
3671
+ return parsedResponse.data;
3671
3672
  } catch (error) {
3672
3673
  if (error?.name === "AbortError") {
3673
3674
  CadenzaService.log(
@@ -3733,7 +3734,11 @@ var RestController = class _RestController {
3733
3734
  }
3734
3735
  console.log("Service inserted...");
3735
3736
  const app = (0, import_express.default)();
3736
- app.use(import_body_parser.default.json());
3737
+ app.use(
3738
+ import_body_parser.default.json({
3739
+ limit: this.resolveJsonBodyLimit()
3740
+ })
3741
+ );
3737
3742
  switch (ctx.__securityProfile) {
3738
3743
  case "low":
3739
3744
  app.use((0, import_helmet.default)());
@@ -3906,6 +3911,32 @@ var RestController = class _RestController {
3906
3911
  )
3907
3912
  );
3908
3913
  });
3914
+ app.use(
3915
+ (error, _req, res, next) => {
3916
+ if (!error) {
3917
+ next();
3918
+ return;
3919
+ }
3920
+ const statusCode = typeof error.statusCode === "number" ? error.statusCode : typeof error.status === "number" ? error.status : error.type === "entity.too.large" ? 413 : 500;
3921
+ const message = error.type === "entity.too.large" ? `Request payload exceeded REST body limit ${this.resolveJsonBodyLimit()}.` : this.getErrorMessage(error);
3922
+ CadenzaService.log(
3923
+ "REST request failed before route completion.",
3924
+ {
3925
+ error: message,
3926
+ type: error.type,
3927
+ statusCode,
3928
+ path: _req?.path,
3929
+ method: _req?.method
3930
+ },
3931
+ statusCode >= 500 ? "error" : "warning"
3932
+ );
3933
+ res.status(statusCode).json({
3934
+ __status: "error",
3935
+ errored: true,
3936
+ __error: message
3937
+ });
3938
+ }
3939
+ );
3909
3940
  return true;
3910
3941
  },
3911
3942
  "Starts REST server and initiates meta-handling"
@@ -4444,6 +4475,42 @@ var RestController = class _RestController {
4444
4475
  return String(error);
4445
4476
  }
4446
4477
  }
4478
+ resolveJsonBodyLimit() {
4479
+ const configuredLimit = process.env.CADENZA_REST_BODY_LIMIT?.trim();
4480
+ return configuredLimit && configuredLimit.length > 0 ? configuredLimit : "10mb";
4481
+ }
4482
+ async parseFetchResponse(response) {
4483
+ const contentType = response.headers.get("content-type") ?? "";
4484
+ const rawText = await response.text();
4485
+ const headers = Object.fromEntries(response.headers.entries());
4486
+ if (rawText.length === 0) {
4487
+ return {
4488
+ ok: response.ok,
4489
+ status: response.status,
4490
+ statusText: response.statusText,
4491
+ headers,
4492
+ data: {}
4493
+ };
4494
+ }
4495
+ if (!contentType.toLowerCase().includes("application/json")) {
4496
+ throw new Error(
4497
+ `Expected JSON response from ${response.url ?? "remote service"} but received ${contentType || "unknown content type"} (HTTP ${response.status}). Body preview: ${rawText.slice(0, 200)}`
4498
+ );
4499
+ }
4500
+ try {
4501
+ return {
4502
+ ok: response.ok,
4503
+ status: response.status,
4504
+ statusText: response.statusText,
4505
+ headers,
4506
+ data: JSON.parse(rawText)
4507
+ };
4508
+ } catch (error) {
4509
+ throw new Error(
4510
+ `Failed to parse JSON response from ${response.url ?? "remote service"} (HTTP ${response.status}). Body preview: ${rawText.slice(0, 200)}. Parse error: ${this.getErrorMessage(error)}`
4511
+ );
4512
+ }
4513
+ }
4447
4514
  resolveDelegationTimeoutMs(ctx) {
4448
4515
  const syncing = ctx?.__syncing === true || ctx?.__metadata?.__syncing === true || Array.isArray(ctx?.joinedContexts) && ctx.joinedContexts.some(
4449
4516
  (joinedCtx) => joinedCtx?.__syncing === true || joinedCtx?.__metadata?.__syncing === true
@@ -9749,7 +9816,7 @@ var GraphSyncController = class _GraphSyncController {
9749
9816
  });
9750
9817
  const signalName = resolveSignalNameFromSyncContext(ctx);
9751
9818
  if (!signalName) {
9752
- return true;
9819
+ return false;
9753
9820
  }
9754
9821
  const signalObservers = CadenzaService.signalBroker.signalObservers;
9755
9822
  if (!signalObservers?.has(signalName)) {