@ontemper/edi 1.1.4 → 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,26 +142,32 @@ 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';
152
150
 
153
- try {
154
- await edi.fromX12({ input: rawX12 });
155
- } catch (error) {
156
- if (isEdiInfrastructureError(error)) {
157
- // Transient platform fault — the document is fine. Keep the file, retry later.
158
- throw error;
159
- }
160
- if (isTemperEdiClientError(error)) {
161
- // A verdict on the document (see codes below) — route the file to your error handling.
162
- console.error('EDI Error:', error.code, error.message);
151
+ async function processFile(rawX12: string) {
152
+ try {
153
+ return await edi.fromX12({ input: rawX12 });
154
+ } catch (error) {
155
+ if (isEdiInfrastructureError(error)) {
156
+ // Keep the file and rethrow so the caller can retry.
157
+ throw error;
158
+ }
159
+ if (isTemperEdiClientError(error)) {
160
+ if (error.code === 'edi_unauthorized_error') {
161
+ // Surface authentication failures instead of quarantining the file.
162
+ throw error;
163
+ }
164
+ // A verdict on the document (see codes below) — handle it terminally (e.g.
165
+ // quarantine the file) and STOP. Do not rethrow into retry paths.
166
+ console.error('EDI Error:', error.code, error.message);
167
+ return undefined;
168
+ }
169
+ throw error; // unrecognized — surface to the caller
163
170
  }
164
- throw error;
165
171
  }
166
172
  ```
167
173
 
@@ -178,11 +184,11 @@ try {
178
184
  | `edi_unauthorized_error` | Unauthorized access to EDI service |
179
185
  | `edi_unknown_error` | Legacy — no longer produced |
180
186
 
181
- `EdiInfrastructureError` (transient platform fault, `retryable: true`):
187
+ `EdiInfrastructureError` (`retryable: true`):
182
188
 
183
189
  | Code | Description |
184
190
  | ---------------------- | ------------------------------------------------------------------------------------ |
185
- | `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 |
186
192
 
187
193
  ## Type Definitions
188
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,22 +105,12 @@ class TemperEdiClient {
112
105
  if (error instanceof EdiInfrastructureError)
113
106
  throw error;
114
107
  if ((0, axios_1.isAxiosError)(error)) {
115
- if (error.status === 403)
108
+ const status = error.response?.status ?? error.status;
109
+ if (status === 401 || status === 403)
116
110
  throw new TemperEdiClientError({
117
- message: 'Unauthorized access to EDI service. Reach out to support.',
111
+ message: 'Unauthorized access to EDI service (credentials missing, expired, or invalid). Reach out to support.',
118
112
  code: 'edi_unauthorized_error',
119
113
  });
120
- // Transport failures (no response: ECONNREFUSED/timeout/DNS), 5xx, and
121
- // rate-limit/timeout statuses are transient service faults, not verdicts on
122
- // the document — a brief EDI-service outage must never quarantine valid
123
- // files in /error (T-3235).
124
- const status = error.response?.status;
125
- if (status === undefined || status >= 500 || status === 408 || status === 429) {
126
- throw new EdiInfrastructureError({
127
- message: `EDI service unreachable or transiently failing (${status ?? error.code ?? 'no response'}): ${error.message}`,
128
- cause: error,
129
- });
130
- }
131
114
  // Gateway normalises EdiFabric's camelCase to PascalCase before forwarding
132
115
  const responseData = error.response?.data;
133
116
  const details = typeof responseData === 'object' &&
@@ -136,18 +119,18 @@ class TemperEdiClient {
136
119
  Array.isArray(responseData.Details)
137
120
  ? responseData.Details
138
121
  : undefined;
139
- const message = error.response?.status === 400 && details?.length
140
- ? `EDI validation failed: ${details.join('; ')}`
141
- : responseData && typeof responseData === 'object'
142
- ? `EDI request failed (${error.response?.status}): ${JSON.stringify(responseData)}`
143
- : error.message;
144
- 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
+ });
145
133
  }
146
- // Not an axios error → the failure never reached the EDI HTTP exchange. It was
147
- // raised by the SDK's own plumbing (span/logging instrumentation, request
148
- // serialization), so it must not be reported as a verdict on the file: workflows
149
- // route `edi_*` errors to /error, and that misrouted valid partner files when the
150
- // instrumentation layer crashed (T-3235).
151
134
  throw new EdiInfrastructureError({
152
135
  message: `EDI client infrastructure failure (not caused by the input document): ${error instanceof Error ? error.message : String(error)}`,
153
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.4",
4
+ "version": "1.1.6",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "author": "Unnbound Team",