@ontemper/edi 1.2.0-beta.3 → 1.2.0-beta.5
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/CHANGELOG.md +23 -0
- package/README.md +18 -25
- package/dist/control-numbers.d.ts +9 -11
- package/dist/control-numbers.js +53 -39
- package/dist/index.d.ts +6 -11
- package/dist/index.js +18 -31
- package/package.json +4 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## [1.1.7](https://github.com/ontemper/temper/releases/tag/%40ontemper%2Fedi-v1.1.7) (2026-07-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* stamp zero acknowledgment envelope control numbers ([#2421](https://github.com/ontemper/temper/pull/2421))
|
|
7
|
+
|
|
8
|
+
## [1.0.13](https://github.com/unnbounddev/unnbound-sdks/compare/unnbound-edi-sdk-v1.0.12...unnbound-edi-sdk-v1.0.13) (2025-11-25)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* setup ci/cd ([dd2640f](https://github.com/unnbounddev/unnbound-sdks/commit/dd2640f01e39f1342f3e08dc882164b50331c7bb))
|
|
14
|
+
* setup ci/cd ([520c03a](https://github.com/unnbounddev/unnbound-sdks/commit/520c03aacd978d7923b3bcf45c4f74a870be019d))
|
|
15
|
+
|
|
16
|
+
## [1.0.12](https://github.com/unnbounddev/unnbound-sdks/compare/unnbound-edi-sdk-v1.0.11...unnbound-edi-sdk-v1.0.12) (2025-11-25)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* remove unused files ([6dc00c2](https://github.com/unnbounddev/unnbound-sdks/commit/6dc00c20b092b17e9eb2108ef83dc5beafdef3f5))
|
|
22
|
+
* setup ci/cd ([d3759c1](https://github.com/unnbounddev/unnbound-sdks/commit/d3759c14f7863e4c8d2f5e80bdbbf2446df79f1a))
|
|
23
|
+
* setup ci/cd ([7e06fc8](https://github.com/unnbounddev/unnbound-sdks/commit/7e06fc84ae7bafba3e9c2c0225f9f9d614fa9207))
|
package/README.md
CHANGED
|
@@ -354,21 +354,20 @@ run().catch(console.error);
|
|
|
354
354
|
|
|
355
355
|
The SDK manages ISA13 and GS06 control numbers for each sender and receiver pair. `toX12()` automatically stamps
|
|
356
356
|
empty or all-zero ISA13, GS06, and ST02 fields. It preserves valid non-zero values. ISA13 and GS06 use the
|
|
357
|
-
centralized
|
|
357
|
+
centralized counter service. ST02 is assigned `"0001"`.
|
|
358
358
|
|
|
359
|
-
Each Temper environment
|
|
359
|
+
Each Temper environment has a separate counter ledger. Production allocations continue the partner's production
|
|
360
|
+
sequence. Sandbox and staging allocations do not consume production control numbers. A ledger rolls over after
|
|
361
|
+
`999999999`, so the next value is `000000001`.
|
|
360
362
|
|
|
361
363
|
### Automatic environment routing
|
|
362
364
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
`control_number_environment_missing` code before
|
|
366
|
-
automatic allocation from using the wrong environment.
|
|
365
|
+
Current workflow deployments inject `UNNBOUND_ENVIRONMENT`. The SDK also accepts `TEMPER_ENVIRONMENT` as the
|
|
366
|
+
future canonical name and prefers it when present. The value must be `sandbox`, `staging`, or `production`. A missing
|
|
367
|
+
or invalid value causes a `ControlNumberError` with the `control_number_environment_missing` code before any HTTP request.
|
|
367
368
|
|
|
368
|
-
`getNextControlNumber()` and `toX12()`
|
|
369
|
-
select a counter, and `toX12()` does not change it.
|
|
370
|
-
|
|
371
|
-
### Manage counters directly
|
|
369
|
+
`getNextControlNumber()`, `getCurrentControlNumber()`, and `toX12()` use this environment. They do not accept an
|
|
370
|
+
environment override. ISA15 (`UsageIndicator_15`) does not select a counter, and `toX12()` does not change it.
|
|
372
371
|
|
|
373
372
|
```typescript
|
|
374
373
|
import { getCurrentControlNumber, getNextControlNumber, setControlNumber } from '@ontemper/edi';
|
|
@@ -379,25 +378,18 @@ const receiverId = 'ZZ:RECEIVER';
|
|
|
379
378
|
const next = await getNextControlNumber('ISA13', senderId, receiverId);
|
|
380
379
|
const current = await getCurrentControlNumber('ISA13', senderId, receiverId);
|
|
381
380
|
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
environment: 'production',
|
|
385
|
-
});
|
|
386
|
-
await setControlNumber('ISA13', senderId, receiverId, 4600, 9, {
|
|
387
|
-
environment: 'production',
|
|
388
|
-
});
|
|
381
|
+
// Legacy production migration: store 4599 as the last-used value.
|
|
382
|
+
await setControlNumber('ISA13', senderId, receiverId, 4599);
|
|
389
383
|
```
|
|
390
384
|
|
|
391
|
-
`
|
|
392
|
-
`
|
|
393
|
-
An explicit environment takes precedence over `UNNBOUND_ENVIRONMENT`. Without this option, both methods require
|
|
394
|
-
the ambient environment. `getNextControlNumber()` accepts no environment override.
|
|
385
|
+
`setControlNumber()` is the legacy production setter. Its value is the last-used number, so setting `4599` makes the
|
|
386
|
+
next allocation `4600`. It uses the flat production route and does not use the environment variables.
|
|
395
387
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
388
|
+
Use the Builder agent `set_edi_control_number` tool for per-environment seeding. The tool value is the next number.
|
|
389
|
+
For example, seeding `4600` makes the next allocation `4600`. Seeding is forward-only. Re-seeding the same value is
|
|
390
|
+
a no-op.
|
|
399
391
|
|
|
400
|
-
These helpers require `UNNBOUND_API_URL
|
|
392
|
+
These helpers require `UNNBOUND_API_URL`. Temper configures it in workflow environments.
|
|
401
393
|
|
|
402
394
|
## Requirements
|
|
403
395
|
|
|
@@ -405,6 +397,7 @@ These helpers require `UNNBOUND_API_URL`, which is preconfigured in workflow env
|
|
|
405
397
|
- TypeScript (for TypeScript projects)
|
|
406
398
|
- The EDI connection env — `UNNBOUND_EDI_BASE_URL`, plus `UNNBOUND_EDI_API_KEY` where the path needs a credential — is platform-injected per environment in Temper workflows; nothing to configure. Supply a key yourself only for the standalone legacy EDINation-cloud path.
|
|
407
399
|
- `UNNBOUND_API_URL` (for control number auto-stamping, pre-configured in workflow environments)
|
|
400
|
+
- `UNNBOUND_ENVIRONMENT` for current counter routing; `TEMPER_ENVIRONMENT` is the preferred future name
|
|
408
401
|
|
|
409
402
|
## Dependencies
|
|
410
403
|
|
|
@@ -3,11 +3,7 @@ export type TemperEnvironment = 'sandbox' | 'staging' | 'production';
|
|
|
3
3
|
/** @public */
|
|
4
4
|
export type ControlNumberCounterName = 'ISA13' | 'GS06';
|
|
5
5
|
/** @public */
|
|
6
|
-
export
|
|
7
|
-
readonly environment?: TemperEnvironment;
|
|
8
|
-
}
|
|
9
|
-
/** @public */
|
|
10
|
-
export type ControlNumberErrorCode = 'control_number_environment_missing' | 'counter_already_started' | 'control_number_bad_request' | 'control_number_unauthorized' | 'control_number_unknown_error';
|
|
6
|
+
export type ControlNumberErrorCode = 'counter_already_started' | 'control_number_environment_missing' | 'control_number_bad_request' | 'control_number_unauthorized' | 'control_number_unknown_error';
|
|
11
7
|
interface ControlNumberErrorOptions extends ErrorOptions {
|
|
12
8
|
code: ControlNumberErrorCode;
|
|
13
9
|
message: string;
|
|
@@ -18,12 +14,12 @@ export declare class ControlNumberError extends Error {
|
|
|
18
14
|
constructor({ code, message, ...options }: ControlNumberErrorOptions);
|
|
19
15
|
}
|
|
20
16
|
/** @public */
|
|
21
|
-
export declare const isControlNumberError: (error:
|
|
17
|
+
export declare const isControlNumberError: (error: ErrorOptions['cause']) => error is ControlNumberError;
|
|
22
18
|
/**
|
|
23
19
|
* Get the next control number for an EDI counter.
|
|
24
20
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* The centralized service isolates counters by Temper environment.
|
|
22
|
+
* It rolls 999999999 over to 1.
|
|
27
23
|
*
|
|
28
24
|
* @param counterName - Counter type: 'ISA13' or 'GS06'
|
|
29
25
|
* @param senderId - Sender qualifier + ID (e.g. "ZZ:SENDER123")
|
|
@@ -36,10 +32,12 @@ export declare function getNextControlNumber(counterName: ControlNumberCounterNa
|
|
|
36
32
|
* Get the current control number value without incrementing.
|
|
37
33
|
*/
|
|
38
34
|
/** @public */
|
|
39
|
-
export declare function getCurrentControlNumber(counterName: ControlNumberCounterName, senderId: string, receiverId: string, maxDigits?: number
|
|
35
|
+
export declare function getCurrentControlNumber(counterName: ControlNumberCounterName, senderId: string, receiverId: string, maxDigits?: number): Promise<string>;
|
|
40
36
|
/**
|
|
41
|
-
* Set
|
|
37
|
+
* Set the last-used production control number through the legacy endpoint.
|
|
38
|
+
*
|
|
39
|
+
* Use the Builder agent `set_edi_control_number` tool for per-environment seeding.
|
|
42
40
|
*/
|
|
43
41
|
/** @public */
|
|
44
|
-
export declare function setControlNumber(counterName: ControlNumberCounterName, senderId: string, receiverId: string, value: number, maxDigits?: number
|
|
42
|
+
export declare function setControlNumber(counterName: ControlNumberCounterName, senderId: string, receiverId: string, value: number, maxDigits?: number): Promise<string>;
|
|
45
43
|
export {};
|
package/dist/control-numbers.js
CHANGED
|
@@ -79,19 +79,26 @@ exports.ControlNumberError = ControlNumberError;
|
|
|
79
79
|
const isControlNumberError = (error) => error instanceof ControlNumberError;
|
|
80
80
|
exports.isControlNumberError = isControlNumberError;
|
|
81
81
|
const requireEnvironment = () => {
|
|
82
|
-
const environment = process.env.UNNBOUND_ENVIRONMENT;
|
|
82
|
+
const environment = process.env.TEMPER_ENVIRONMENT ?? process.env.UNNBOUND_ENVIRONMENT;
|
|
83
83
|
if (environment === 'sandbox' || environment === 'staging' || environment === 'production') {
|
|
84
84
|
return environment;
|
|
85
85
|
}
|
|
86
86
|
throw new ControlNumberError({
|
|
87
87
|
code: 'control_number_environment_missing',
|
|
88
|
-
message: "UNNBOUND_ENVIRONMENT must be set to 'sandbox', 'staging', or 'production' because automatic control-number routing needs it.",
|
|
88
|
+
message: "TEMPER_ENVIRONMENT or UNNBOUND_ENVIRONMENT must be set to 'sandbox', 'staging', or 'production' because automatic control-number routing needs it.",
|
|
89
89
|
});
|
|
90
90
|
};
|
|
91
|
-
function unwrapControlNumberError(error) {
|
|
91
|
+
function unwrapControlNumberError(error, environmentScoped = false) {
|
|
92
92
|
if (error instanceof ControlNumberError)
|
|
93
93
|
throw error;
|
|
94
94
|
if ((0, axios_1.isAxiosError)(error)) {
|
|
95
|
+
if (environmentScoped && error.response?.status === 404) {
|
|
96
|
+
throw new ControlNumberError({
|
|
97
|
+
code: 'control_number_unknown_error',
|
|
98
|
+
message: 'The Temper API does not support environment-scoped EDI control numbers yet.',
|
|
99
|
+
cause: error,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
95
102
|
if (error.response?.status === 409) {
|
|
96
103
|
throw new ControlNumberError({
|
|
97
104
|
code: 'counter_already_started',
|
|
@@ -102,7 +109,7 @@ function unwrapControlNumberError(error) {
|
|
|
102
109
|
if (error.response?.status === 400) {
|
|
103
110
|
throw new ControlNumberError({
|
|
104
111
|
code: 'control_number_bad_request',
|
|
105
|
-
message: "Invalid EDI control number request. Use counter name 'ISA13' or 'GS06' with trading partner IDs
|
|
112
|
+
message: "Invalid EDI control number request. Use counter name 'ISA13' or 'GS06' with trading partner IDs.",
|
|
106
113
|
cause: error,
|
|
107
114
|
});
|
|
108
115
|
}
|
|
@@ -120,25 +127,11 @@ function unwrapControlNumberError(error) {
|
|
|
120
127
|
cause: error,
|
|
121
128
|
});
|
|
122
129
|
}
|
|
123
|
-
async function requestControlNumber(operation, input, environment) {
|
|
124
|
-
const request = { ...input, environment: environment ?? requireEnvironment() };
|
|
125
|
-
try {
|
|
126
|
-
const response = operation === 'count'
|
|
127
|
-
? await getApiClient().get(`/api/v2/internal/edi/control-numbers/${operation}`, {
|
|
128
|
-
params: request,
|
|
129
|
-
})
|
|
130
|
-
: await getApiClient().post(`/api/v2/internal/edi/control-numbers/${operation}`, request);
|
|
131
|
-
return response.data;
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
return unwrapControlNumberError(error);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
130
|
/**
|
|
138
131
|
* Get the next control number for an EDI counter.
|
|
139
132
|
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
133
|
+
* The centralized service isolates counters by Temper environment.
|
|
134
|
+
* It rolls 999999999 over to 1.
|
|
142
135
|
*
|
|
143
136
|
* @param counterName - Counter type: 'ISA13' or 'GS06'
|
|
144
137
|
* @param senderId - Sender qualifier + ID (e.g. "ZZ:SENDER123")
|
|
@@ -147,32 +140,53 @@ async function requestControlNumber(operation, input, environment) {
|
|
|
147
140
|
*/
|
|
148
141
|
/** @public */
|
|
149
142
|
async function getNextControlNumber(counterName, senderId, receiverId, maxDigits = 9) {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
143
|
+
const environment = requireEnvironment();
|
|
144
|
+
try {
|
|
145
|
+
const { data } = await getApiClient().post(`/api/v2/internal/edi/control-numbers/${environment}/increment`, {
|
|
146
|
+
tradingPartnerKey: `${senderId}:${receiverId}`,
|
|
147
|
+
counterName,
|
|
148
|
+
});
|
|
149
|
+
return String(data.value).padStart(maxDigits, '0');
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
return unwrapControlNumberError(error, true);
|
|
153
|
+
}
|
|
155
154
|
}
|
|
156
155
|
/**
|
|
157
156
|
* Get the current control number value without incrementing.
|
|
158
157
|
*/
|
|
159
158
|
/** @public */
|
|
160
|
-
async function getCurrentControlNumber(counterName, senderId, receiverId, maxDigits = 9
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
159
|
+
async function getCurrentControlNumber(counterName, senderId, receiverId, maxDigits = 9) {
|
|
160
|
+
const environment = requireEnvironment();
|
|
161
|
+
try {
|
|
162
|
+
const { data } = await getApiClient().get(`/api/v2/internal/edi/control-numbers/${environment}/count`, {
|
|
163
|
+
params: {
|
|
164
|
+
tradingPartnerKey: `${senderId}:${receiverId}`,
|
|
165
|
+
counterName,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
return String(data.value).padStart(maxDigits, '0');
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
return unwrapControlNumberError(error, true);
|
|
172
|
+
}
|
|
166
173
|
}
|
|
167
174
|
/**
|
|
168
|
-
* Set
|
|
175
|
+
* Set the last-used production control number through the legacy endpoint.
|
|
176
|
+
*
|
|
177
|
+
* Use the Builder agent `set_edi_control_number` tool for per-environment seeding.
|
|
169
178
|
*/
|
|
170
179
|
/** @public */
|
|
171
|
-
async function setControlNumber(counterName, senderId, receiverId, value, maxDigits = 9
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
180
|
+
async function setControlNumber(counterName, senderId, receiverId, value, maxDigits = 9) {
|
|
181
|
+
try {
|
|
182
|
+
const { data } = await getApiClient().post('/api/v2/internal/edi/control-numbers/set', {
|
|
183
|
+
tradingPartnerKey: `${senderId}:${receiverId}`,
|
|
184
|
+
counterName,
|
|
185
|
+
value,
|
|
186
|
+
});
|
|
187
|
+
return String(data.value).padStart(maxDigits, '0');
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
return unwrapControlNumberError(error);
|
|
191
|
+
}
|
|
178
192
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export type {
|
|
1
|
+
import { type X12Interchange } from './edination-client';
|
|
2
|
+
export type { ControlNumberErrorCode } from './control-numbers';
|
|
3
3
|
export { ControlNumberError, getCurrentControlNumber, getNextControlNumber, isControlNumberError, setControlNumber, } from './control-numbers';
|
|
4
4
|
export * from './edination-client/model';
|
|
5
5
|
interface UnnboundErrorOptions<C extends string = string> extends ErrorOptions {
|
|
@@ -14,7 +14,7 @@ export type TemperEdiClientErrorCode = 'edi_read_error' | 'edi_write_error' | 'e
|
|
|
14
14
|
export declare class TemperEdiClientError extends UnnboundError<TemperEdiClientErrorCode> {
|
|
15
15
|
constructor({ message, code, ...o }: UnnboundErrorOptions<TemperEdiClientErrorCode>);
|
|
16
16
|
}
|
|
17
|
-
export declare const isTemperEdiClientError: (error:
|
|
17
|
+
export declare const isTemperEdiClientError: (error: ErrorOptions['cause']) => error is TemperEdiClientError;
|
|
18
18
|
/**
|
|
19
19
|
* A retryable failure that does not indicate an invalid EDI document.
|
|
20
20
|
*/
|
|
@@ -22,7 +22,7 @@ export declare class EdiInfrastructureError extends UnnboundError<'infrastructur
|
|
|
22
22
|
readonly retryable = true;
|
|
23
23
|
constructor({ message, ...o }: Omit<UnnboundErrorOptions<'infrastructure_error'>, 'code'>);
|
|
24
24
|
}
|
|
25
|
-
export declare const isEdiInfrastructureError: (error:
|
|
25
|
+
export declare const isEdiInfrastructureError: (error: ErrorOptions['cause']) => error is EdiInfrastructureError;
|
|
26
26
|
export interface FromX12Options {
|
|
27
27
|
input: unknown;
|
|
28
28
|
}
|
|
@@ -41,14 +41,9 @@ export declare class TemperEdiClient {
|
|
|
41
41
|
private unwrap;
|
|
42
42
|
private unwrapError;
|
|
43
43
|
fromX12({ input }: FromX12Options): Promise<X12Interchange[]>;
|
|
44
|
-
/**
|
|
45
|
-
* Stamp ISA13/GS06/ST02 control numbers on the interchange if not already set.
|
|
46
|
-
* Uses the Restate-backed counter service for atomic, per-trading-partner sequencing.
|
|
47
|
-
* ST02 is always "0001" (one transaction per file per ticket).
|
|
48
|
-
* Zero-filled values from acknowledgment generation are placeholders, not manual overrides.
|
|
49
|
-
*/
|
|
44
|
+
/** Allocate every remote number before mutating the interchange. */
|
|
50
45
|
private stampControlNumbers;
|
|
51
|
-
toX12({ input }: ToX12Options): Promise<
|
|
46
|
+
toX12({ input }: ToX12Options): Promise<File>;
|
|
52
47
|
validateX12({ input }: ValidateX12Options): Promise<import("./edination-client").OperationResult>;
|
|
53
48
|
acknowledgeX12({ input }: AcknolwedgeX12Options): Promise<X12Interchange[]>;
|
|
54
49
|
}
|
package/dist/index.js
CHANGED
|
@@ -118,12 +118,13 @@ class TemperEdiClient {
|
|
|
118
118
|
});
|
|
119
119
|
// Gateway normalises EdiFabric's camelCase to PascalCase before forwarding
|
|
120
120
|
const responseData = error.response?.data;
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
let details;
|
|
122
|
+
if (responseData instanceof Object &&
|
|
123
123
|
'Details' in responseData &&
|
|
124
|
-
Array.isArray(responseData.Details)
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
Array.isArray(responseData.Details) &&
|
|
125
|
+
responseData.Details.every((detail) => String(detail) === detail)) {
|
|
126
|
+
details = responseData.Details.map(String);
|
|
127
|
+
}
|
|
127
128
|
if (status === 400 && details?.length) {
|
|
128
129
|
throw new TemperEdiClientError({
|
|
129
130
|
message: `EDI validation failed: ${details.join('; ')}`,
|
|
@@ -143,35 +144,30 @@ class TemperEdiClient {
|
|
|
143
144
|
}
|
|
144
145
|
fromX12({ input }) {
|
|
145
146
|
return (0, unnbound_logger_sdk_1.startSpan)('X12 to JSON', () => {
|
|
147
|
+
// SAFETY: generated client accepts File; Buffer/Blob inputs are valid File-like bodies
|
|
146
148
|
return this.X12.x12ReadPost({ body: input })
|
|
147
149
|
.then(this.unwrap.bind(this))
|
|
148
150
|
.catch((error) => this.unwrapError(error, 'edi_read_error'));
|
|
149
151
|
}, (o) => buildEdiX12Payload('fromX12', { input, output: o?.result }));
|
|
150
152
|
}
|
|
151
|
-
/**
|
|
152
|
-
* Stamp ISA13/GS06/ST02 control numbers on the interchange if not already set.
|
|
153
|
-
* Uses the Restate-backed counter service for atomic, per-trading-partner sequencing.
|
|
154
|
-
* ST02 is always "0001" (one transaction per file per ticket).
|
|
155
|
-
* Zero-filled values from acknowledgment generation are placeholders, not manual overrides.
|
|
156
|
-
*/
|
|
153
|
+
/** Allocate every remote number before mutating the interchange. */
|
|
157
154
|
async stampControlNumbers(input) {
|
|
158
155
|
const isa = input.ISA;
|
|
159
|
-
const senderQual = (isa.SenderIDQualifier_5
|
|
160
|
-
const senderId = (isa.InterchangeSenderID_6
|
|
161
|
-
const receiverQual = (isa.ReceiverIDQualifier_7
|
|
162
|
-
const receiverId = (isa.InterchangeReceiverID_8
|
|
156
|
+
const senderQual = (isa.SenderIDQualifier_5 ?? '').trim();
|
|
157
|
+
const senderId = (isa.InterchangeSenderID_6 ?? '').trim();
|
|
158
|
+
const receiverQual = (isa.ReceiverIDQualifier_7 ?? '').trim();
|
|
159
|
+
const receiverId = (isa.InterchangeReceiverID_8 ?? '').trim();
|
|
163
160
|
const senderKey = `${senderQual}:${senderId}`;
|
|
164
161
|
const receiverKey = `${receiverQual}:${receiverId}`;
|
|
165
|
-
// Allocate before mutating so a failed request cannot leave partial stamps.
|
|
166
162
|
const isa13 = needsControlNumber(isa.InterchangeControlNumber_13)
|
|
167
163
|
? await (0, control_numbers_1.getNextControlNumber)('ISA13', senderKey, receiverKey, 9)
|
|
168
164
|
: null;
|
|
165
|
+
const groups = input.Groups;
|
|
169
166
|
const gs06Values = [];
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
if (needsControlNumber(groups[i].GS.GroupControlNumber_6)) {
|
|
167
|
+
for (const group of groups) {
|
|
168
|
+
if (needsControlNumber(group.GS.GroupControlNumber_6)) {
|
|
173
169
|
const value = await (0, control_numbers_1.getNextControlNumber)('GS06', senderKey, receiverKey, 9);
|
|
174
|
-
gs06Values.push({
|
|
170
|
+
gs06Values.push({ group, value });
|
|
175
171
|
}
|
|
176
172
|
}
|
|
177
173
|
if (isa13) {
|
|
@@ -180,8 +176,7 @@ class TemperEdiClient {
|
|
|
180
176
|
input.IEATrailers[0].InterchangeControlNumber_2 = isa13;
|
|
181
177
|
}
|
|
182
178
|
}
|
|
183
|
-
for (const {
|
|
184
|
-
const group = groups[index];
|
|
179
|
+
for (const { group, value } of gs06Values) {
|
|
185
180
|
group.GS.GroupControlNumber_6 = value;
|
|
186
181
|
if (group.GETrailers?.length) {
|
|
187
182
|
group.GETrailers[0].GroupControlNumber_2 = value;
|
|
@@ -199,15 +194,7 @@ class TemperEdiClient {
|
|
|
199
194
|
}
|
|
200
195
|
}
|
|
201
196
|
async toX12({ input }) {
|
|
202
|
-
|
|
203
|
-
await this.stampControlNumbers(input);
|
|
204
|
-
}
|
|
205
|
-
catch (error) {
|
|
206
|
-
if (error instanceof control_numbers_1.ControlNumberError)
|
|
207
|
-
throw error;
|
|
208
|
-
// Workflows can still serialize documents whose control numbers were set manually.
|
|
209
|
-
unnbound_logger_sdk_1.logger.warn({ err: error }, '[EDI SDK] Failed to auto-stamp control numbers, proceeding without');
|
|
210
|
-
}
|
|
197
|
+
await this.stampControlNumbers(input);
|
|
211
198
|
return (0, unnbound_logger_sdk_1.startSpan)('JSON to X12', () => {
|
|
212
199
|
return this.X12.x12WritePost({ x12Interchange: input })
|
|
213
200
|
.then(this.unwrap.bind(this))
|
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.2.0-beta.
|
|
4
|
+
"version": "1.2.0-beta.5",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"author": "Unnbound Team",
|
|
@@ -16,12 +16,13 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"axios": "1.18.0",
|
|
19
|
-
"unnbound-logger-sdk": "3.
|
|
19
|
+
"unnbound-logger-sdk": "3.1.1"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/jest": "^29.5.12",
|
|
23
23
|
"@types/node": "^24.12.2",
|
|
24
|
-
"vitest": "^4.0.15"
|
|
24
|
+
"vitest": "^4.0.15",
|
|
25
|
+
"zod": "3.25.76"
|
|
25
26
|
},
|
|
26
27
|
"files": [
|
|
27
28
|
"examples/*",
|