@ontemper/edi 1.1.0 → 1.1.2-beta.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.
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # Unnbound EDI Client
1
+ # Temper EDI Client
2
2
 
3
3
  A TypeScript EDI client with structured logging and distributed tracing capabilities, built for processing X12 EDI documents with comprehensive error handling and automatic span tracking.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - **X12 EDI Processing**: Complete X12 document parsing, validation, and generation
8
- - **Structured Logging**: Built-in integration with Unnbound Logger for comprehensive operation tracking
8
+ - **Structured Logging**: Built-in integration with Temper Logger for comprehensive operation tracking
9
9
  - **Distributed Tracing**: Automatic span creation for all EDI operations with detailed payload information
10
10
  - **Type Safety**: Full TypeScript support with comprehensive type definitions
11
11
  - **Error Handling**: Custom error types with detailed error codes and context
@@ -13,11 +13,11 @@ A TypeScript EDI client with structured logging and distributed tracing capabili
13
13
  ## Installation
14
14
 
15
15
  ```bash
16
- npm install unnbound-edi-sdk
16
+ npm install @ontemper/edi
17
17
  # or
18
- bun add unnbound-edi-sdk
18
+ bun add @ontemper/edi
19
19
  # or
20
- yarn add unnbound-edi-sdk
20
+ yarn add @ontemper/edi
21
21
  ```
22
22
 
23
23
  ## Environment Variables
@@ -29,13 +29,13 @@ yarn add unnbound-edi-sdk
29
29
  ## Quick Start
30
30
 
31
31
  ```typescript
32
- import { UnnboundEdiClient } from 'unnbound-edi-sdk';
32
+ import { TemperEdiClient } from '@ontemper/edi';
33
33
  import { logger } from 'unnbound-logger-sdk';
34
34
 
35
35
  // Set your API key
36
36
  process.env.UNNBOUND_EDI_API_KEY = 'your-api-key';
37
37
 
38
- const edi = new UnnboundEdiClient();
38
+ const edi = new TemperEdiClient();
39
39
 
40
40
  // Parse X12 document to JSON
41
41
  const x12Interchanges = await edi.fromX12({
@@ -63,7 +63,7 @@ const acknowledgment = await edi.acknowledgeX12({
63
63
  ### Constructor
64
64
 
65
65
  ```typescript
66
- new UnnboundEdiClient();
66
+ new TemperEdiClient();
67
67
  ```
68
68
 
69
69
  Creates a new EDI client instance. Requires `UNNBOUND_EDI_API_KEY` environment variable to be set.
@@ -88,7 +88,7 @@ const x12Interchanges = await edi.fromX12({
88
88
 
89
89
  #### `toX12(options: ToX12Options): Promise<unknown>`
90
90
 
91
- Converts JSON X12 interchange objects back to X12 format.
91
+ Converts JSON X12 interchange objects back to X12 format. **Automatically stamps control numbers** (ISA13, GS06, ST02) and their matching trailers if not already set.
92
92
 
93
93
  ```typescript
94
94
  const x12Document = await edi.toX12({
@@ -102,6 +102,8 @@ const x12Document = await edi.toX12({
102
102
 
103
103
  **Returns:** X12 document as string
104
104
 
105
+ **Control number auto-stamping:** Leave `InterchangeControlNumber_13`, `GroupControlNumber_6`, and `TransactionSetControlNumber_02` empty or omit them. The SDK fetches atomic, per-trading-partner control numbers from a centralized counter service. If values are already set, they are left unchanged.
106
+
105
107
  #### `validateX12(options: ValidateX12Options): Promise<OperationResult>`
106
108
 
107
109
  Validates X12 interchange objects against EDI standards.
@@ -138,15 +140,15 @@ const acknowledgment = await edi.acknowledgeX12({
138
140
 
139
141
  The EDI client provides custom error types for different operation failures:
140
142
 
141
- ### UnnboundEdiClientError
143
+ ### TemperEdiClientError
142
144
 
143
145
  ```typescript
144
- import { UnnboundEdiClientError, isUnnboundEdiClientError } from 'unnbound-edi-sdk';
146
+ import { TemperEdiClientError, isTemperEdiClientError } from '@ontemper/edi';
145
147
 
146
148
  try {
147
149
  await edi.fromX12({ input: invalidX12 });
148
150
  } catch (error) {
149
- if (isUnnboundEdiClientError(error)) {
151
+ if (isTemperEdiClientError(error)) {
150
152
  console.error('EDI Error:', error.code, error.message);
151
153
  // Handle specific EDI errors
152
154
  }
@@ -228,7 +230,7 @@ interface OperationDetail {
228
230
 
229
231
  ## Logging and Tracing
230
232
 
231
- The Unnbound EDI Client automatically creates spans for all operations and logs detailed information including:
233
+ The Temper EDI Client automatically creates spans for all operations and logs detailed information including:
232
234
 
233
235
  - Operation type and timing
234
236
  - Input and output data
@@ -247,11 +249,11 @@ The Unnbound EDI Client automatically creates spans for all operations and logs
247
249
  ## Complete Example
248
250
 
249
251
  ```typescript
250
- import { UnnboundEdiClient } from 'unnbound-edi-sdk';
252
+ import { TemperEdiClient } from '@ontemper/edi';
251
253
  import { logger } from 'unnbound-logger-sdk';
252
254
 
253
255
  const run = async () => {
254
- const edi = new UnnboundEdiClient();
256
+ const edi = new TemperEdiClient();
255
257
 
256
258
  const x12Data = `ISA*00* *00* *12*NOTP *12*NOTP *080501*1700*U*00401*000001000*0*P*>
257
259
  GS*PO*NOTP*NOTP*20080501*1700*1000*X*004010
@@ -306,11 +308,33 @@ IEA*1*000001000`;
306
308
  run().catch(console.error);
307
309
  ```
308
310
 
311
+ ## Control Numbers
312
+
313
+ The SDK provides functions for managing EDI control numbers (ISA13, GS06) via the centralized counter service:
314
+
315
+ ```typescript
316
+ import { getNextControlNumber, getCurrentControlNumber, setControlNumber } from '@ontemper/edi';
317
+
318
+ // Get next control number (atomic increment)
319
+ const next = await getNextControlNumber('ISA13', 'ZZ:SENDER', 'ZZ:RECEIVER');
320
+
321
+ // Peek at current value without incrementing
322
+ const current = await getCurrentControlNumber('ISA13', 'ZZ:SENDER', 'ZZ:RECEIVER');
323
+
324
+ // Set a starting value (for migrations)
325
+ await setControlNumber('ISA13', 'ZZ:SENDER', 'ZZ:RECEIVER', 1000);
326
+ ```
327
+
328
+ In most cases you don't need these directly — `toX12()` calls `getNextControlNumber` automatically for any empty ISA13/GS06 fields.
329
+
330
+ Requires `UNNBOUND_API_URL` environment variable (pre-configured in all workflow environments).
331
+
309
332
  ## Requirements
310
333
 
311
334
  - Node.js >= 22.0.0
312
335
  - TypeScript (for TypeScript projects)
313
- - Unnbound EDI API key
336
+ - Temper EDI API key
337
+ - `UNNBOUND_API_URL` (for control number auto-stamping, pre-configured in workflow environments)
314
338
 
315
339
  ## Dependencies
316
340
 
@@ -10,6 +10,7 @@
10
10
  * Do not edit the class manually.
11
11
  */
12
12
  import type { AxiosInstance, AxiosPromise, RawAxiosRequestConfig } from 'axios';
13
+ import globalAxios from 'axios';
13
14
  import { BaseAPI, type RequestArgs } from '../base';
14
15
  import type { Configuration } from '../configuration';
15
16
  import type { EdiModel } from '../model';
@@ -237,7 +238,7 @@ export declare class EdiModelApi extends BaseAPI implements EdiModelApiInterface
237
238
  * @throws {RequiredError}
238
239
  * @memberof EdiModelApi
239
240
  */
240
- modelsGet(requestParameters?: EdiModelApiModelsGetRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<EdiModel[], any, {}>>;
241
+ modelsGet(requestParameters?: EdiModelApiModelsGetRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<EdiModel[], any, {}>>;
241
242
  /**
242
243
  *
243
244
  * @summary Delete an EDI model
@@ -246,7 +247,7 @@ export declare class EdiModelApi extends BaseAPI implements EdiModelApiInterface
246
247
  * @throws {RequiredError}
247
248
  * @memberof EdiModelApi
248
249
  */
249
- modelsIdDelete(requestParameters: EdiModelApiModelsIdDeleteRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<void, any, {}>>;
250
+ modelsIdDelete(requestParameters: EdiModelApiModelsIdDeleteRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<void, any, {}>>;
250
251
  /**
251
252
  *
252
253
  * @summary Retrieve an EDI model
@@ -255,7 +256,7 @@ export declare class EdiModelApi extends BaseAPI implements EdiModelApiInterface
255
256
  * @throws {RequiredError}
256
257
  * @memberof EdiModelApi
257
258
  */
258
- modelsIdGet(requestParameters: EdiModelApiModelsIdGetRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<File, any, {}>>;
259
+ modelsIdGet(requestParameters: EdiModelApiModelsIdGetRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<File, any, {}>>;
259
260
  /**
260
261
  *
261
262
  * @summary Upload EDI models in either SEF or OpenEDI format
@@ -264,5 +265,5 @@ export declare class EdiModelApi extends BaseAPI implements EdiModelApiInterface
264
265
  * @throws {RequiredError}
265
266
  * @memberof EdiModelApi
266
267
  */
267
- modelsPost(requestParameters?: EdiModelApiModelsPostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<void, any, {}>>;
268
+ modelsPost(requestParameters?: EdiModelApiModelsPostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<void, any, {}>>;
268
269
  }
@@ -10,6 +10,7 @@
10
10
  * Do not edit the class manually.
11
11
  */
12
12
  import type { AxiosInstance, AxiosPromise, RawAxiosRequestConfig } from 'axios';
13
+ import globalAxios from 'axios';
13
14
  import { BaseAPI, type RequestArgs } from '../base';
14
15
  import type { Configuration } from '../configuration';
15
16
  import type { EdifactInterchange } from '../model';
@@ -422,7 +423,7 @@ export declare class EdifactApi extends BaseAPI implements EdifactApiInterface {
422
423
  * @throws {RequiredError}
423
424
  * @memberof EdifactApi
424
425
  */
425
- edifactAckPost(requestParameters?: EdifactApiEdifactAckPostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<EdifactInterchange[], any, {}>>;
426
+ edifactAckPost(requestParameters?: EdifactApiEdifactAckPostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<EdifactInterchange[], any, {}>>;
426
427
  /**
427
428
  *
428
429
  * @summary Convert EDIFACT files to JSON
@@ -431,7 +432,7 @@ export declare class EdifactApi extends BaseAPI implements EdifactApiInterface {
431
432
  * @throws {RequiredError}
432
433
  * @memberof EdifactApi
433
434
  */
434
- edifactReadPost(requestParameters?: EdifactApiEdifactReadPostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<EdifactInterchange[], any, {}>>;
435
+ edifactReadPost(requestParameters?: EdifactApiEdifactReadPostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<EdifactInterchange[], any, {}>>;
435
436
  /**
436
437
  *
437
438
  * @summary Validate EDIFACT messages
@@ -440,7 +441,7 @@ export declare class EdifactApi extends BaseAPI implements EdifactApiInterface {
440
441
  * @throws {RequiredError}
441
442
  * @memberof EdifactApi
442
443
  */
443
- edifactValidatePost(requestParameters?: EdifactApiEdifactValidatePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<OperationResult, any, {}>>;
444
+ edifactValidatePost(requestParameters?: EdifactApiEdifactValidatePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<OperationResult, any, {}>>;
444
445
  /**
445
446
  *
446
447
  * @summary Convert JSON to EDIFACT files
@@ -449,5 +450,5 @@ export declare class EdifactApi extends BaseAPI implements EdifactApiInterface {
449
450
  * @throws {RequiredError}
450
451
  * @memberof EdifactApi
451
452
  */
452
- edifactWritePost(requestParameters?: EdifactApiEdifactWritePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<File, any, {}>>;
453
+ edifactWritePost(requestParameters?: EdifactApiEdifactWritePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<File, any, {}>>;
453
454
  }
@@ -10,6 +10,7 @@
10
10
  * Do not edit the class manually.
11
11
  */
12
12
  import type { AxiosInstance, AxiosPromise, RawAxiosRequestConfig } from 'axios';
13
+ import globalAxios from 'axios';
13
14
  import { BaseAPI, type RequestArgs } from '../base';
14
15
  import type { Configuration } from '../configuration';
15
16
  import type { Hl7Interchange } from '../model';
@@ -272,7 +273,7 @@ export declare class Hl7Api extends BaseAPI implements Hl7ApiInterface {
272
273
  * @throws {RequiredError}
273
274
  * @memberof Hl7Api
274
275
  */
275
- hl7ReadPost(requestParameters?: Hl7ApiHl7ReadPostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<Hl7Interchange[], any, {}>>;
276
+ hl7ReadPost(requestParameters?: Hl7ApiHl7ReadPostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<Hl7Interchange[], any, {}>>;
276
277
  /**
277
278
  *
278
279
  * @summary Validate HL7 messages
@@ -281,7 +282,7 @@ export declare class Hl7Api extends BaseAPI implements Hl7ApiInterface {
281
282
  * @throws {RequiredError}
282
283
  * @memberof Hl7Api
283
284
  */
284
- hl7ValidatePost(requestParameters?: Hl7ApiHl7ValidatePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<OperationResult, any, {}>>;
285
+ hl7ValidatePost(requestParameters?: Hl7ApiHl7ValidatePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<OperationResult, any, {}>>;
285
286
  /**
286
287
  *
287
288
  * @summary Convert JSON to HL7 files
@@ -290,5 +291,5 @@ export declare class Hl7Api extends BaseAPI implements Hl7ApiInterface {
290
291
  * @throws {RequiredError}
291
292
  * @memberof Hl7Api
292
293
  */
293
- hl7WritePost(requestParameters?: Hl7ApiHl7WritePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<File, any, {}>>;
294
+ hl7WritePost(requestParameters?: Hl7ApiHl7WritePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<File, any, {}>>;
294
295
  }
@@ -10,6 +10,7 @@
10
10
  * Do not edit the class manually.
11
11
  */
12
12
  import type { AxiosInstance, AxiosPromise, RawAxiosRequestConfig } from 'axios';
13
+ import globalAxios from 'axios';
13
14
  import { BaseAPI, type RequestArgs } from '../base';
14
15
  import type { Configuration } from '../configuration';
15
16
  import type { NcpdpTransmission } from '../model';
@@ -256,7 +257,7 @@ export declare class NcpdpApi extends BaseAPI implements NcpdpApiInterface {
256
257
  * @throws {RequiredError}
257
258
  * @memberof NcpdpApi
258
259
  */
259
- ncpdpReadPost(requestParameters?: NcpdpApiNcpdpReadPostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<NcpdpTransmission, any, {}>>;
260
+ ncpdpReadPost(requestParameters?: NcpdpApiNcpdpReadPostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<NcpdpTransmission, any, {}>>;
260
261
  /**
261
262
  *
262
263
  * @summary Validate NCPDP messages
@@ -265,7 +266,7 @@ export declare class NcpdpApi extends BaseAPI implements NcpdpApiInterface {
265
266
  * @throws {RequiredError}
266
267
  * @memberof NcpdpApi
267
268
  */
268
- ncpdpValidatePost(requestParameters?: NcpdpApiNcpdpValidatePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<OperationResult, any, {}>>;
269
+ ncpdpValidatePost(requestParameters?: NcpdpApiNcpdpValidatePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<OperationResult, any, {}>>;
269
270
  /**
270
271
  *
271
272
  * @summary Convert JSON to NCPDP files
@@ -274,5 +275,5 @@ export declare class NcpdpApi extends BaseAPI implements NcpdpApiInterface {
274
275
  * @throws {RequiredError}
275
276
  * @memberof NcpdpApi
276
277
  */
277
- ncpdpWritePost(requestParameters?: NcpdpApiNcpdpWritePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<File, any, {}>>;
278
+ ncpdpWritePost(requestParameters?: NcpdpApiNcpdpWritePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<File, any, {}>>;
278
279
  }
@@ -10,6 +10,7 @@
10
10
  * Do not edit the class manually.
11
11
  */
12
12
  import type { AxiosInstance, AxiosPromise, RawAxiosRequestConfig } from 'axios';
13
+ import globalAxios from 'axios';
13
14
  import { BaseAPI, type RequestArgs } from '../base';
14
15
  import type { Configuration } from '../configuration';
15
16
  import type { FlatMessage } from '../model';
@@ -240,7 +241,7 @@ export declare class VdaApi extends BaseAPI implements VdaApiInterface {
240
241
  * @throws {RequiredError}
241
242
  * @memberof VdaApi
242
243
  */
243
- vdaReadPost(requestParameters?: VdaApiVdaReadPostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<FlatMessage[], any, {}>>;
244
+ vdaReadPost(requestParameters?: VdaApiVdaReadPostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<FlatMessage[], any, {}>>;
244
245
  /**
245
246
  *
246
247
  * @summary Validate VDA messages
@@ -249,7 +250,7 @@ export declare class VdaApi extends BaseAPI implements VdaApiInterface {
249
250
  * @throws {RequiredError}
250
251
  * @memberof VdaApi
251
252
  */
252
- vdaValidatePost(requestParameters?: VdaApiVdaValidatePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<OperationResult, any, {}>>;
253
+ vdaValidatePost(requestParameters?: VdaApiVdaValidatePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<OperationResult, any, {}>>;
253
254
  /**
254
255
  *
255
256
  * @summary Convert JSON to VDA files
@@ -258,5 +259,5 @@ export declare class VdaApi extends BaseAPI implements VdaApiInterface {
258
259
  * @throws {RequiredError}
259
260
  * @memberof VdaApi
260
261
  */
261
- vdaWritePost(requestParameters?: VdaApiVdaWritePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<File, any, {}>>;
262
+ vdaWritePost(requestParameters?: VdaApiVdaWritePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<File, any, {}>>;
262
263
  }
@@ -10,6 +10,7 @@
10
10
  * Do not edit the class manually.
11
11
  */
12
12
  import type { AxiosInstance, AxiosPromise, RawAxiosRequestConfig } from 'axios';
13
+ import globalAxios from 'axios';
13
14
  import { BaseAPI, type RequestArgs } from '../base';
14
15
  import type { Configuration } from '../configuration';
15
16
  import type { OperationResult } from '../model';
@@ -406,7 +407,7 @@ export declare class X12Api extends BaseAPI implements X12ApiInterface {
406
407
  * @throws {RequiredError}
407
408
  * @memberof X12Api
408
409
  */
409
- x12AckPost(requestParameters?: X12ApiX12AckPostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<X12Interchange[], any, {}>>;
410
+ x12AckPost(requestParameters?: X12ApiX12AckPostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<X12Interchange[], any, {}>>;
410
411
  /**
411
412
  *
412
413
  * @summary Convert X12 files to JSON
@@ -415,7 +416,7 @@ export declare class X12Api extends BaseAPI implements X12ApiInterface {
415
416
  * @throws {RequiredError}
416
417
  * @memberof X12Api
417
418
  */
418
- x12ReadPost(requestParameters?: X12ApiX12ReadPostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<X12Interchange[], any, {}>>;
419
+ x12ReadPost(requestParameters?: X12ApiX12ReadPostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<X12Interchange[], any, {}>>;
419
420
  /**
420
421
  *
421
422
  * @summary Validate X12 messages
@@ -424,7 +425,7 @@ export declare class X12Api extends BaseAPI implements X12ApiInterface {
424
425
  * @throws {RequiredError}
425
426
  * @memberof X12Api
426
427
  */
427
- x12ValidatePost(requestParameters?: X12ApiX12ValidatePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<OperationResult, any, {}>>;
428
+ x12ValidatePost(requestParameters?: X12ApiX12ValidatePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<OperationResult, any, {}>>;
428
429
  /**
429
430
  *
430
431
  * @summary Convert JSON to X12 files
@@ -433,5 +434,5 @@ export declare class X12Api extends BaseAPI implements X12ApiInterface {
433
434
  * @throws {RequiredError}
434
435
  * @memberof X12Api
435
436
  */
436
- x12WritePost(requestParameters?: X12ApiX12WritePostRequest, options?: RawAxiosRequestConfig): Promise<import("axios").AxiosResponse<File, any, {}>>;
437
+ x12WritePost(requestParameters?: X12ApiX12WritePostRequest, options?: RawAxiosRequestConfig): Promise<globalAxios.AxiosResponse<File, any, {}>>;
437
438
  }
package/dist/index.d.ts CHANGED
@@ -9,11 +9,11 @@ declare class UnnboundError<C extends string = string> extends Error {
9
9
  code: C;
10
10
  constructor({ message, code, ...o }: UnnboundErrorOptions<C>);
11
11
  }
12
- export type UnnboundEdiClientErrorCode = 'edi_read_error' | 'edi_write_error' | 'edi_validate_error' | 'edi_acknowledge_error' | 'edi_unauthorized_error' | 'edi_unknown_error';
13
- export declare class UnnboundEdiClientError extends UnnboundError<UnnboundEdiClientErrorCode> {
14
- constructor({ message, code, ...o }: UnnboundErrorOptions<UnnboundEdiClientErrorCode>);
12
+ export type TemperEdiClientErrorCode = 'edi_read_error' | 'edi_write_error' | 'edi_validate_error' | 'edi_acknowledge_error' | 'edi_unauthorized_error' | 'edi_unknown_error';
13
+ export declare class TemperEdiClientError extends UnnboundError<TemperEdiClientErrorCode> {
14
+ constructor({ message, code, ...o }: UnnboundErrorOptions<TemperEdiClientErrorCode>);
15
15
  }
16
- export declare const isUnnboundEdiClientError: (error: unknown) => error is UnnboundEdiClientError;
16
+ export declare const isTemperEdiClientError: (error: unknown) => error is TemperEdiClientError;
17
17
  export interface FromX12Options {
18
18
  input: unknown;
19
19
  }
@@ -26,7 +26,7 @@ export interface ValidateX12Options {
26
26
  export interface AcknolwedgeX12Options {
27
27
  input: X12Interchange;
28
28
  }
29
- export declare class UnnboundEdiClient {
29
+ export declare class TemperEdiClient {
30
30
  private X12;
31
31
  constructor();
32
32
  private unwrap;
package/dist/index.js CHANGED
@@ -36,7 +36,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
36
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.UnnboundEdiClient = exports.isUnnboundEdiClientError = exports.UnnboundEdiClientError = exports.setControlNumber = exports.getCurrentControlNumber = exports.getNextControlNumber = void 0;
39
+ exports.TemperEdiClient = exports.isTemperEdiClientError = exports.TemperEdiClientError = exports.setControlNumber = exports.getCurrentControlNumber = exports.getNextControlNumber = void 0;
40
40
  const axios_1 = __importStar(require("axios"));
41
41
  const unnbound_logger_sdk_1 = require("unnbound-logger-sdk");
42
42
  const internal_1 = require("unnbound-logger-sdk/dist/internal");
@@ -54,18 +54,18 @@ class UnnboundError extends Error {
54
54
  this.code = code;
55
55
  }
56
56
  }
57
- class UnnboundEdiClientError extends UnnboundError {
57
+ class TemperEdiClientError extends UnnboundError {
58
58
  constructor({ message, code, ...o }) {
59
59
  super({ message, code, ...o });
60
- this.name = 'UnnboundEdiClientError';
60
+ this.name = 'TemperEdiClientError';
61
61
  }
62
62
  }
63
- exports.UnnboundEdiClientError = UnnboundEdiClientError;
64
- const isUnnboundEdiClientError = (error) => error instanceof UnnboundEdiClientError;
65
- exports.isUnnboundEdiClientError = isUnnboundEdiClientError;
63
+ exports.TemperEdiClientError = TemperEdiClientError;
64
+ const isTemperEdiClientError = (error) => error instanceof TemperEdiClientError;
65
+ exports.isTemperEdiClientError = isTemperEdiClientError;
66
66
  const buildEdiPayload = (edi) => ({ type: 'edi', edi });
67
67
  const buildEdiX12Payload = (operation, x12) => buildEdiPayload({ operation, type: 'x12', x12 });
68
- class UnnboundEdiClient {
68
+ class TemperEdiClient {
69
69
  X12;
70
70
  constructor() {
71
71
  const apiKey = process.env.UNNBOUND_EDI_API_KEY;
@@ -85,23 +85,30 @@ class UnnboundEdiClient {
85
85
  return response.data;
86
86
  }
87
87
  unwrapError(error, code) {
88
- if (error instanceof UnnboundEdiClientError)
88
+ if (error instanceof TemperEdiClientError)
89
89
  throw error;
90
90
  if ((0, axios_1.isAxiosError)(error)) {
91
91
  if (error.status === 403)
92
- throw new UnnboundEdiClientError({
92
+ throw new TemperEdiClientError({
93
93
  message: 'Unauthorized access to EDI service. Reach out to support.',
94
94
  code: 'edi_unauthorized_error',
95
95
  });
96
- throw new UnnboundEdiClientError({ message: error.message, code, cause: error });
96
+ const responseData = error.response?.data;
97
+ const details = responseData?.Details;
98
+ const message = error.response?.status === 400 && details?.length
99
+ ? `EDI validation failed: ${details.join('; ')}`
100
+ : responseData && typeof responseData === 'object'
101
+ ? `EDI request failed (${error.response?.status}): ${JSON.stringify(responseData)}`
102
+ : error.message;
103
+ throw new TemperEdiClientError({ message, code, cause: error });
97
104
  }
98
105
  if (error instanceof Error)
99
- throw new UnnboundEdiClientError({
106
+ throw new TemperEdiClientError({
100
107
  message: error.message,
101
108
  code: 'edi_unknown_error',
102
109
  cause: error,
103
110
  });
104
- throw new UnnboundEdiClientError({
111
+ throw new TemperEdiClientError({
105
112
  message: 'Unknown error occured in EDI client.',
106
113
  code: 'edi_unknown_error',
107
114
  cause: error,
@@ -121,7 +128,7 @@ class UnnboundEdiClient {
121
128
  * If a control number is already set, it is left unchanged (opt-out for manual overrides).
122
129
  */
123
130
  async stampControlNumbers(input) {
124
- const { getNextControlNumber } = await Promise.resolve().then(() => __importStar(require('./control-numbers')));
131
+ const { getNextControlNumber } = await import('./control-numbers.js');
125
132
  const isa = input.ISA;
126
133
  const senderQual = (isa.SenderIDQualifier_5 || '').trim();
127
134
  const senderId = (isa.InterchangeSenderID_6 || '').trim();
@@ -129,34 +136,40 @@ class UnnboundEdiClient {
129
136
  const receiverId = (isa.InterchangeReceiverID_8 || '').trim();
130
137
  const senderKey = `${senderQual}:${senderId}`;
131
138
  const receiverKey = `${receiverQual}:${receiverId}`;
132
- // ISA13 interchange control number (9 digits, zero-padded)
133
- if (!isa.InterchangeControlNumber_13) {
134
- const isa13 = await getNextControlNumber('ISA13', senderKey, receiverKey, 9);
139
+ // Phase 1: Fetch all needed control numbers (no mutations yet).
140
+ // If any fetch fails, no fields are mutated — avoids partial stamping.
141
+ const isa13 = !isa.InterchangeControlNumber_13
142
+ ? await getNextControlNumber('ISA13', senderKey, receiverKey, 9)
143
+ : null;
144
+ const gs06Values = [];
145
+ for (let i = 0; i < input.Groups.length; i++) {
146
+ if (!input.Groups[i].GS.GroupControlNumber_6) {
147
+ const value = await getNextControlNumber('GS06', senderKey, receiverKey, 9);
148
+ gs06Values.push({ index: i, value });
149
+ }
150
+ }
151
+ // Phase 2: Apply all mutations (only reached if all fetches succeeded).
152
+ if (isa13) {
135
153
  isa.InterchangeControlNumber_13 = isa13;
136
- // IEA02 must match ISA13
137
154
  if (input.IEATrailers?.length) {
138
155
  input.IEATrailers[0].InterchangeControlNumber_2 = isa13;
139
156
  }
140
157
  }
141
- // GS06 functional group control number (per group)
142
- for (const group of input.Groups) {
143
- if (!group.GS.GroupControlNumber_6) {
144
- const gs06 = await getNextControlNumber('GS06', senderKey, receiverKey, 9);
145
- group.GS.GroupControlNumber_6 = gs06;
146
- // GE02 must match GS06
147
- if (group.GETrailers?.length) {
148
- group.GETrailers[0].GroupControlNumber_2 = gs06;
149
- }
158
+ for (const { index, value } of gs06Values) {
159
+ const group = input.Groups[index];
160
+ group.GS.GroupControlNumber_6 = value;
161
+ if (group.GETrailers?.length) {
162
+ group.GETrailers[0].GroupControlNumber_2 = value;
150
163
  }
151
164
  }
152
- // ST02 — always "0001" (one transaction per file, no persistence needed)
165
+ // ST02 — always "0001" (pure assignment, no external calls)
153
166
  for (const group of input.Groups) {
154
167
  for (const tx of group.Transactions) {
155
- if (tx?.ST?.TransactionSetControlNumber_2 === undefined || tx?.ST?.TransactionSetControlNumber_2 === null) {
168
+ if (!tx?.ST?.TransactionSetControlNumber_02) {
156
169
  if (tx?.ST)
157
- tx.ST.TransactionSetControlNumber_2 = '0001';
170
+ tx.ST.TransactionSetControlNumber_02 = '0001';
158
171
  if (tx?.SE)
159
- tx.SE.TransactionSetControlNumber_2 = '0001';
172
+ tx.SE.TransactionSetControlNumber_02 = '0001';
160
173
  }
161
174
  }
162
175
  }
@@ -168,7 +181,8 @@ class UnnboundEdiClient {
168
181
  }
169
182
  catch (error) {
170
183
  // Log but don't fail — workflows can still set control numbers manually
171
- console.warn('[EDI SDK] Failed to auto-stamp control numbers, proceeding without:', error);
184
+ const { logger } = await import('unnbound-logger-sdk');
185
+ logger.warn({ err: error }, '[EDI SDK] Failed to auto-stamp control numbers, proceeding without');
172
186
  }
173
187
  return (0, unnbound_logger_sdk_1.startSpan)('JSON to X12', () => {
174
188
  return this.X12.x12WritePost({ x12Interchange: input })
@@ -194,4 +208,4 @@ class UnnboundEdiClient {
194
208
  }, (o) => buildEdiX12Payload('acknowledgeX12', { input, output: o?.result }));
195
209
  }
196
210
  }
197
- exports.UnnboundEdiClient = UnnboundEdiClient;
211
+ exports.TemperEdiClient = TemperEdiClient;
@@ -1,9 +1,9 @@
1
1
  import { logger } from 'unnbound-logger-sdk';
2
2
 
3
- import { UnnboundEdiClient } from '../src';
3
+ import { TemperEdiClient } from '../src';
4
4
 
5
5
  const run = async () => {
6
- const edi = new UnnboundEdiClient();
6
+ const edi = new TemperEdiClient();
7
7
 
8
8
  const data = `ISA*00* *00* *12*NOTP *12*NOTP *080501*1700*U*00401*000001000*0*P*>
9
9
  GS*PO*NOTP*NOTP*20080501*1700*1000*X*004010
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@ontemper/edi",
3
3
  "description": "An EDI client with structured logging.",
4
- "version": "1.1.0",
4
+ "version": "1.1.2-beta.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc",
9
9
  "test": "echo 'No tests'",
10
- "typecheck": "tsc -noEmit",
10
+ "typecheck": "tsgo --noEmit",
11
11
  "lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
12
- "lint:fix": "bun run lint --fix",
12
+ "lint:fix": "pnpm run lint --fix",
13
13
  "format": "biome format --write .",
14
14
  "format:check": "biome format .",
15
- "prepublishOnly": "bun run build",
16
- "start:example": "bun --watch examples/node-edi.ts",
15
+ "prepublishOnly": "pnpm run build",
16
+ "start:example": "tsx watch examples/node-edi.ts",
17
17
  "version:bump": "npm version patch",
18
- "release": "bun run build && bun publish --access public",
18
+ "release": "pnpm run build && pnpm publish --access public",
19
19
  "codegen": "npx --yes @openapitools/openapi-generator-cli generate -c openapitools.json -o ./src/edination-client"
20
20
  },
21
21
  "author": "Unnbound Team",
@@ -29,12 +29,12 @@
29
29
  "url": "https://github.com/unnbounddev/unnbound-sdks/issues"
30
30
  },
31
31
  "dependencies": {
32
- "axios": "^1.12.2",
33
- "unnbound-logger-sdk": "3.0.35"
32
+ "axios": "1.13.6",
33
+ "unnbound-logger-sdk": "workspace:*"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/jest": "^29.5.12",
37
- "@types/node": "^22"
37
+ "@types/node": "^24.12.2"
38
38
  },
39
39
  "files": [
40
40
  "examples/*",