@ontemper/edi 1.2.0-beta.4 → 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/README.md CHANGED
@@ -362,9 +362,9 @@ sequence. Sandbox and staging allocations do not consume production control numb
362
362
 
363
363
  ### Automatic environment routing
364
364
 
365
- Temper injects `TEMPER_ENVIRONMENT` into workflows. The SDK uses `UNNBOUND_ENVIRONMENT` only when
366
- `TEMPER_ENVIRONMENT` is absent. The value must be `sandbox`, `staging`, or `production`. A missing or invalid value
367
- causes a `ControlNumberError` with the `control_number_environment_missing` code before any HTTP request.
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.
368
368
 
369
369
  `getNextControlNumber()`, `getCurrentControlNumber()`, and `toX12()` use this environment. They do not accept an
370
370
  environment override. ISA15 (`UsageIndicator_15`) does not select a counter, and `toX12()` does not change it.
@@ -397,7 +397,7 @@ These helpers require `UNNBOUND_API_URL`. Temper configures it in workflow envir
397
397
  - TypeScript (for TypeScript projects)
398
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.
399
399
  - `UNNBOUND_API_URL` (for control number auto-stamping, pre-configured in workflow environments)
400
- - `TEMPER_ENVIRONMENT` for counter routing, with `UNNBOUND_ENVIRONMENT` as the legacy fallback
400
+ - `UNNBOUND_ENVIRONMENT` for current counter routing; `TEMPER_ENVIRONMENT` is the preferred future name
401
401
 
402
402
  ## Dependencies
403
403
 
@@ -127,19 +127,6 @@ function unwrapControlNumberError(error, environmentScoped = false) {
127
127
  cause: error,
128
128
  });
129
129
  }
130
- async function requestControlNumber(operation, input) {
131
- const environment = requireEnvironment();
132
- const path = `/api/v2/internal/edi/control-numbers/${environment}/${operation}`;
133
- try {
134
- const response = operation === 'count'
135
- ? await getApiClient().get(path, { params: input })
136
- : await getApiClient().post(path, input);
137
- return response.data;
138
- }
139
- catch (error) {
140
- return unwrapControlNumberError(error, true);
141
- }
142
- }
143
130
  /**
144
131
  * Get the next control number for an EDI counter.
145
132
  *
@@ -153,22 +140,36 @@ async function requestControlNumber(operation, input) {
153
140
  */
154
141
  /** @public */
155
142
  async function getNextControlNumber(counterName, senderId, receiverId, maxDigits = 9) {
156
- const data = await requestControlNumber('increment', {
157
- tradingPartnerKey: `${senderId}:${receiverId}`,
158
- counterName,
159
- });
160
- return String(data.value).padStart(maxDigits, '0');
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
+ }
161
154
  }
162
155
  /**
163
156
  * Get the current control number value without incrementing.
164
157
  */
165
158
  /** @public */
166
159
  async function getCurrentControlNumber(counterName, senderId, receiverId, maxDigits = 9) {
167
- const data = await requestControlNumber('count', {
168
- tradingPartnerKey: `${senderId}:${receiverId}`,
169
- counterName,
170
- });
171
- return String(data.value).padStart(maxDigits, '0');
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
+ }
172
173
  }
173
174
  /**
174
175
  * Set the last-used production control number through the legacy endpoint.
package/dist/index.d.ts CHANGED
@@ -41,12 +41,7 @@ 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 centralized per-environment service for atomic 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
46
  toX12({ input }: ToX12Options): Promise<File>;
52
47
  validateX12({ input }: ValidateX12Options): Promise<import("./edination-client").OperationResult>;
package/dist/index.js CHANGED
@@ -150,30 +150,24 @@ class TemperEdiClient {
150
150
  .catch((error) => this.unwrapError(error, 'edi_read_error'));
151
151
  }, (o) => buildEdiX12Payload('fromX12', { input, output: o?.result }));
152
152
  }
153
- /**
154
- * Stamp ISA13/GS06/ST02 control numbers on the interchange if not already set.
155
- * Uses the centralized per-environment service for atomic partner sequencing.
156
- * ST02 is always "0001" (one transaction per file per ticket).
157
- * Zero-filled values from acknowledgment generation are placeholders, not manual overrides.
158
- */
153
+ /** Allocate every remote number before mutating the interchange. */
159
154
  async stampControlNumbers(input) {
160
155
  const isa = input.ISA;
161
- const senderQual = (isa.SenderIDQualifier_5 || '').trim();
162
- const senderId = (isa.InterchangeSenderID_6 || '').trim();
163
- const receiverQual = (isa.ReceiverIDQualifier_7 || '').trim();
164
- const receiverId = (isa.InterchangeReceiverID_8 || '').trim();
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();
165
160
  const senderKey = `${senderQual}:${senderId}`;
166
161
  const receiverKey = `${receiverQual}:${receiverId}`;
167
- // Allocate before mutating so a failed request cannot leave partial stamps.
168
162
  const isa13 = needsControlNumber(isa.InterchangeControlNumber_13)
169
163
  ? await (0, control_numbers_1.getNextControlNumber)('ISA13', senderKey, receiverKey, 9)
170
164
  : null;
165
+ const groups = input.Groups;
171
166
  const gs06Values = [];
172
- const groups = input.Groups ?? [];
173
- for (let i = 0; i < groups.length; i++) {
174
- if (needsControlNumber(groups[i].GS.GroupControlNumber_6)) {
167
+ for (const group of groups) {
168
+ if (needsControlNumber(group.GS.GroupControlNumber_6)) {
175
169
  const value = await (0, control_numbers_1.getNextControlNumber)('GS06', senderKey, receiverKey, 9);
176
- gs06Values.push({ index: i, value });
170
+ gs06Values.push({ group, value });
177
171
  }
178
172
  }
179
173
  if (isa13) {
@@ -182,8 +176,7 @@ class TemperEdiClient {
182
176
  input.IEATrailers[0].InterchangeControlNumber_2 = isa13;
183
177
  }
184
178
  }
185
- for (const { index, value } of gs06Values) {
186
- const group = groups[index];
179
+ for (const { group, value } of gs06Values) {
187
180
  group.GS.GroupControlNumber_6 = value;
188
181
  if (group.GETrailers?.length) {
189
182
  group.GETrailers[0].GroupControlNumber_2 = value;
@@ -201,14 +194,7 @@ class TemperEdiClient {
201
194
  }
202
195
  }
203
196
  async toX12({ input }) {
204
- // Auto-stamp control numbers before writing X12
205
- try {
206
- await this.stampControlNumbers(input);
207
- }
208
- catch (error) {
209
- // Workflows can still serialize documents whose control numbers were set manually.
210
- unnbound_logger_sdk_1.logger.warn({ err: error }, '[EDI SDK] Failed to auto-stamp control numbers, proceeding without');
211
- }
197
+ await this.stampControlNumbers(input);
212
198
  return (0, unnbound_logger_sdk_1.startSpan)('JSON to X12', () => {
213
199
  return this.X12.x12WritePost({ x12Interchange: input })
214
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",
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",