@ontemper/edi 1.1.5 → 1.1.6

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 CHANGED
@@ -142,10 +142,8 @@ const acknowledgment = await edi.acknowledgeX12({
142
142
 
143
143
  The EDI client throws two distinct error classes. The distinction matters for file routing:
144
144
  a `TemperEdiClientError` is a verdict on the input document (bad file — don't retry) or a
145
- persistent auth failure, while an `EdiInfrastructureError` is a transient platform fault —
146
- the SDK's own plumbing failed (tracing/logging/serialization) or the EDI service was
147
- transiently unavailable (network failure, timeout, 5xx, rate limit). It says nothing about
148
- the document, so keep the file and retry (`error.retryable === true`).
145
+ persistent authentication failure, while an `EdiInfrastructureError` is retryable and does
146
+ not indicate that the document is invalid (`error.retryable === true`).
149
147
 
150
148
  ```typescript
151
149
  import { isEdiInfrastructureError, isTemperEdiClientError } from '@ontemper/edi';
@@ -155,11 +153,14 @@ async function processFile(rawX12: string) {
155
153
  return await edi.fromX12({ input: rawX12 });
156
154
  } catch (error) {
157
155
  if (isEdiInfrastructureError(error)) {
158
- // Transient platform fault — the document is fine. Keep the file and rethrow
159
- // so your poll loop / caller retries.
156
+ // Keep the file and rethrow so the caller can retry.
160
157
  throw error;
161
158
  }
162
159
  if (isTemperEdiClientError(error)) {
160
+ if (error.code === 'edi_unauthorized_error') {
161
+ // Surface authentication failures instead of quarantining the file.
162
+ throw error;
163
+ }
163
164
  // A verdict on the document (see codes below) — handle it terminally (e.g.
164
165
  // quarantine the file) and STOP. Do not rethrow into retry paths.
165
166
  console.error('EDI Error:', error.code, error.message);
@@ -183,11 +184,11 @@ async function processFile(rawX12: string) {
183
184
  | `edi_unauthorized_error` | Unauthorized access to EDI service |
184
185
  | `edi_unknown_error` | Legacy — no longer produced |
185
186
 
186
- `EdiInfrastructureError` (transient platform fault, `retryable: true`):
187
+ `EdiInfrastructureError` (`retryable: true`):
187
188
 
188
189
  | Code | Description |
189
190
  | ---------------------- | ------------------------------------------------------------------------------------ |
190
- | `infrastructure_error` | SDK plumbing failure or transient EDI-service fault — not caused by the input document |
191
+ | `infrastructure_error` | Retryable failure unrelated to the input document |
191
192
 
192
193
  ## Type Definitions
193
194
 
package/dist/index.d.ts CHANGED
@@ -16,10 +16,7 @@ export declare class TemperEdiClientError extends UnnboundError<TemperEdiClientE
16
16
  }
17
17
  export declare const isTemperEdiClientError: (error: unknown) => error is TemperEdiClientError;
18
18
  /**
19
- * A failure in the SDK's own plumbing (logging/instrumentation/tracing), not a verdict
20
- * on the EDI payload. Deliberately NOT a TemperEdiClientError and NOT an `edi_*` code:
21
- * workflows route `edi_*` errors as bad files, while these are transient platform
22
- * faults the workflow should retry (T-3235).
19
+ * A retryable failure that does not indicate an invalid EDI document.
23
20
  */
24
21
  export declare class EdiInfrastructureError extends UnnboundError<'infrastructure_error'> {
25
22
  readonly retryable = true;
package/dist/index.js CHANGED
@@ -66,10 +66,7 @@ exports.TemperEdiClientError = TemperEdiClientError;
66
66
  const isTemperEdiClientError = (error) => error instanceof TemperEdiClientError;
67
67
  exports.isTemperEdiClientError = isTemperEdiClientError;
68
68
  /**
69
- * A failure in the SDK's own plumbing (logging/instrumentation/tracing), not a verdict
70
- * on the EDI payload. Deliberately NOT a TemperEdiClientError and NOT an `edi_*` code:
71
- * workflows route `edi_*` errors as bad files, while these are transient platform
72
- * faults the workflow should retry (T-3235).
69
+ * A retryable failure that does not indicate an invalid EDI document.
73
70
  */
74
71
  class EdiInfrastructureError extends UnnboundError {
75
72
  retryable = true;
@@ -83,10 +80,6 @@ const isEdiInfrastructureError = (error) => error instanceof EdiInfrastructureEr
83
80
  exports.isEdiInfrastructureError = isEdiInfrastructureError;
84
81
  const buildEdiPayload = (edi) => ({ type: 'edi', edi });
85
82
  const buildEdiX12Payload = (operation, x12) => buildEdiPayload({ operation, type: 'x12', x12 });
86
- // One traced instance for the whole process, created once at module load. Never trace
87
- // the global axios export: in-place wrapping there accumulated a span layer per
88
- // TemperEdiClient construction (stack overflow after enough polls) and leaked EDI
89
- // payload capture into unrelated code sharing global axios (T-3235).
90
83
  const ediAxios = (0, unnbound_logger_sdk_1.traceAxios)(axios_1.default.create(), { getPayload: internal_1.internal });
91
84
  class TemperEdiClient {
92
85
  X12;
@@ -112,24 +105,12 @@ class TemperEdiClient {
112
105
  if (error instanceof EdiInfrastructureError)
113
106
  throw error;
114
107
  if ((0, axios_1.isAxiosError)(error)) {
115
- // 401 = missing/expired/invalid credential (e.g. the sandbox EDI-gateway JWT),
116
- // 403 = access denied. Neither is a verdict on the document.
117
- if (error.status === 401 || error.status === 403)
108
+ const status = error.response?.status ?? error.status;
109
+ if (status === 401 || status === 403)
118
110
  throw new TemperEdiClientError({
119
111
  message: 'Unauthorized access to EDI service (credentials missing, expired, or invalid). Reach out to support.',
120
112
  code: 'edi_unauthorized_error',
121
113
  });
122
- // Transport failures (no response: ECONNREFUSED/timeout/DNS), 5xx, and
123
- // rate-limit/timeout statuses are transient service faults, not verdicts on
124
- // the document — a brief EDI-service outage must never quarantine valid
125
- // files in /error (T-3235).
126
- const status = error.response?.status;
127
- if (status === undefined || status >= 500 || status === 408 || status === 429) {
128
- throw new EdiInfrastructureError({
129
- message: `EDI service unreachable or transiently failing (${status ?? error.code ?? 'no response'}): ${error.message}`,
130
- cause: error,
131
- });
132
- }
133
114
  // Gateway normalises EdiFabric's camelCase to PascalCase before forwarding
134
115
  const responseData = error.response?.data;
135
116
  const details = typeof responseData === 'object' &&
@@ -138,18 +119,18 @@ class TemperEdiClient {
138
119
  Array.isArray(responseData.Details)
139
120
  ? responseData.Details
140
121
  : undefined;
141
- const message = error.response?.status === 400 && details?.length
142
- ? `EDI validation failed: ${details.join('; ')}`
143
- : responseData && typeof responseData === 'object'
144
- ? `EDI request failed (${error.response?.status}): ${JSON.stringify(responseData)}`
145
- : error.message;
146
- throw new TemperEdiClientError({ message, code, cause: error });
122
+ if (status === 400 && details?.length) {
123
+ throw new TemperEdiClientError({
124
+ message: `EDI validation failed: ${details.join('; ')}`,
125
+ code,
126
+ cause: error,
127
+ });
128
+ }
129
+ throw new EdiInfrastructureError({
130
+ message: `EDI service request failed (${status ?? error.code ?? 'no response'}): ${error.message}`,
131
+ cause: error,
132
+ });
147
133
  }
148
- // Not an axios error → the failure never reached the EDI HTTP exchange. It was
149
- // raised by the SDK's own plumbing (span/logging instrumentation, request
150
- // serialization), so it must not be reported as a verdict on the file: workflows
151
- // route `edi_*` errors to /error, and that misrouted valid partner files when the
152
- // instrumentation layer crashed (T-3235).
153
134
  throw new EdiInfrastructureError({
154
135
  message: `EDI client infrastructure failure (not caused by the input document): ${error instanceof Error ? error.message : String(error)}`,
155
136
  cause: error,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ontemper/edi",
3
3
  "description": "An EDI client with structured logging.",
4
- "version": "1.1.5",
4
+ "version": "1.1.6",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "author": "Unnbound Team",