Workstations at YX Fulfillment.
A stock adapter can accept a valid quantity and still make the wrong release decision. A common shortcut is to exclude one known blocked status and treat everything else as available. When the upstream service adds another status, that shortcut can expose stock the receiving system does not understand.
Treat status translation as a small, explicit contract. The example below recognizes exactly three source values. Only AVAILABLE contributes units to the releasable total; HELD and DAMAGED contribute zero. An unknown, missing or differently cased value rejects the calculation.
These are illustrative status names, not a YX Fulfillment API specification. A real integration needs the actual source vocabulary and the warehouse's agreed allocation rules.
Use membership before reading the decision
A Map keeps this lookup separate from inherited object property names. Calling has first also distinguishes an absent key from a recognized key whose mapped value is false. See the MDN Map reference.
Save the complete example as stock-status.cjs and run node stock-status.cjs. It uses Node's built-in assertions and no external packages.
const assert = require('node:assert/strict');
const releaseRules = new Map([
['AVAILABLE', true],
['HELD', false],
['DAMAGED', false]
]);
function isReleasable(status) {
if (typeof status !== 'string' || !releaseRules.has(status)) {
throw new TypeError('Unknown stock status');
}
return releaseRules.get(status);
}
function releasableUnits(rows) {
if (!Array.isArray(rows)) throw new TypeError('Rows must be an array');
let total = 0;
for (const row of rows) {
if (row === null || typeof row !== 'object' || Array.isArray(row) ||
!Object.hasOwn(row, 'status') || !Object.hasOwn(row, 'quantity')) {
throw new TypeError('Stock row fields must be present');
}
const allowed = isReleasable(row.status);
if (!Number.isSafeInteger(row.quantity) || row.quantity < 0) {
throw new TypeError('Invalid stock quantity');
}
if (allowed) {
if (!Number.isSafeInteger(total + row.quantity)) {
throw new RangeError('Total exceeds safe integer range');
}
total += row.quantity;
}
}
return total;
}
assert.equal(isReleasable('AVAILABLE'), true);
assert.equal(isReleasable('HELD'), false);
assert.equal(isReleasable('DAMAGED'), false);
assert.equal(releasableUnits([
{ status: 'AVAILABLE', quantity: 3 },
{ status: 'HELD', quantity: 8 },
{ status: 'DAMAGED', quantity: 2 }
]), 3);
for (const status of ['INSPECTION_PENDING', 'available', ' AVAILABLE',
'toString', '__proto__', '', null, undefined]) {
assert.throws(() => isReleasable(status), TypeError);
}
assert.throws(() => releasableUnits([
{ status: 'AVAILABLE', quantity: 3 },
{ status: 'INSPECTION_PENDING', quantity: 1 }
]), TypeError);
assert.throws(() => releasableUnits([{ quantity: 2 }]), TypeError);
assert.throws(() => releasableUnits([
Object.create({ status: 'AVAILABLE', quantity: 2 })
]), TypeError);
assert.throws(() => releasableUnits([
{ status: 'HELD', quantity: -1 }
]), TypeError);
assert.throws(() => releasableUnits([
{ status: 'AVAILABLE', quantity: Number.MAX_SAFE_INTEGER },
{ status: 'AVAILABLE', quantity: 1 }
]), RangeError);
assert.equal(releasableUnits([]), 0);
console.log('Stock status contract checks passed');
The quantity checks support the example, but the important failure case is the mixed input containing an unknown status. The function throws instead of returning the subtotal it accumulated earlier. It performs no external writes, so the caller can decline to replace its existing result. Object.hasOwn checks that the required row fields belong to the row itself.
Define what happens after rejection
Do not catch the error and publish zero or the previous subtotal as a newly validated stock figure. Record the rejected batch reference and unrecognized status, retain the last valid result with its original timestamp, and send the mapping question to the integration owner. Whether ordering should pause depends on the surrounding application's agreed freshness and availability policy.
When a new source status is documented, add its decision deliberately and extend the contract tests. Trimming or uppercasing input also changes the contract; introduce either only when the upstream specification permits it.
I work with YX Fulfillment, where stock identity and release instructions are part of warehouse coordination. This standalone adapter example does not reserve units, resolve concurrent orders or prove that an upstream status is current. Those remain separate integration requirements. Its narrow guarantee is that an unfamiliar status cannot silently become permission to release stock.

Top comments (0)