@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 +40 -16
- package/dist/edination-client/api/edi-model-api.d.ts +5 -4
- package/dist/edination-client/api/edifact-api.d.ts +5 -4
- package/dist/edination-client/api/hl7-api.d.ts +4 -3
- package/dist/edination-client/api/ncpdp-api.d.ts +4 -3
- package/dist/edination-client/api/vda-api.d.ts +4 -3
- package/dist/edination-client/api/x12-api.d.ts +5 -4
- package/dist/index.d.ts +5 -5
- package/dist/index.js +46 -32
- package/examples/node-edi.ts +2 -2
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
#
|
|
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
|
|
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
|
|
16
|
+
npm install @ontemper/edi
|
|
17
17
|
# or
|
|
18
|
-
bun add
|
|
18
|
+
bun add @ontemper/edi
|
|
19
19
|
# or
|
|
20
|
-
yarn add
|
|
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 {
|
|
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
|
|
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
|
|
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
|
-
###
|
|
143
|
+
### TemperEdiClientError
|
|
142
144
|
|
|
143
145
|
```typescript
|
|
144
|
-
import {
|
|
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 (
|
|
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
|
|
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 {
|
|
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
|
|
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
|
-
-
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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
|
|
13
|
-
export declare class
|
|
14
|
-
constructor({ message, code, ...o }: UnnboundErrorOptions<
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
57
|
+
class TemperEdiClientError extends UnnboundError {
|
|
58
58
|
constructor({ message, code, ...o }) {
|
|
59
59
|
super({ message, code, ...o });
|
|
60
|
-
this.name = '
|
|
60
|
+
this.name = 'TemperEdiClientError';
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
exports.
|
|
64
|
-
const
|
|
65
|
-
exports.
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
106
|
+
throw new TemperEdiClientError({
|
|
100
107
|
message: error.message,
|
|
101
108
|
code: 'edi_unknown_error',
|
|
102
109
|
cause: error,
|
|
103
110
|
});
|
|
104
|
-
throw new
|
|
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
|
|
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
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
group.
|
|
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" (
|
|
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?.
|
|
168
|
+
if (!tx?.ST?.TransactionSetControlNumber_02) {
|
|
156
169
|
if (tx?.ST)
|
|
157
|
-
tx.ST.
|
|
170
|
+
tx.ST.TransactionSetControlNumber_02 = '0001';
|
|
158
171
|
if (tx?.SE)
|
|
159
|
-
tx.SE.
|
|
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
|
-
|
|
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.
|
|
211
|
+
exports.TemperEdiClient = TemperEdiClient;
|
package/examples/node-edi.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { logger } from 'unnbound-logger-sdk';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { TemperEdiClient } from '../src';
|
|
4
4
|
|
|
5
5
|
const run = async () => {
|
|
6
|
-
const edi = new
|
|
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": "
|
|
10
|
+
"typecheck": "tsgo --noEmit",
|
|
11
11
|
"lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
|
|
12
|
-
"lint:fix": "
|
|
12
|
+
"lint:fix": "pnpm run lint --fix",
|
|
13
13
|
"format": "biome format --write .",
|
|
14
14
|
"format:check": "biome format .",
|
|
15
|
-
"prepublishOnly": "
|
|
16
|
-
"start:example": "
|
|
15
|
+
"prepublishOnly": "pnpm run build",
|
|
16
|
+
"start:example": "tsx watch examples/node-edi.ts",
|
|
17
17
|
"version:bump": "npm version patch",
|
|
18
|
-
"release": "
|
|
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": "
|
|
33
|
-
"unnbound-logger-sdk": "
|
|
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": "^
|
|
37
|
+
"@types/node": "^24.12.2"
|
|
38
38
|
},
|
|
39
39
|
"files": [
|
|
40
40
|
"examples/*",
|