A JavaScript array can report a length of two while containing only one actual row. If an order adapter validates it with every(), the missing position is skipped and the check can return true. A batch contract that requires one valid record at every position needs a separate density check.
For a Shopify 3PL adapter, this is an in-memory transformation issue. Ordinary JSON arrays do not contain holes, but assigning a distant array index or deleting a row after parsing can introduce them. The same concern applies to a drop shipping import assembled by application code.
Validate positions before accepting rows
MDN documents that every() skips empty slots. The function below visits each numeric position and requires an own property there. It then creates a fresh array of the accepted fields.
const assert = require('node:assert/strict');
function readBatch(rows) {
if (!Array.isArray(rows) || rows.length < 1 || rows.length > 1000) {
throw new TypeError('Expected 1 to 1000 rows');
}
const accepted = [];
for (let i = 0; i < rows.length; i++) {
if (!Object.hasOwn(rows, i)) throw new TypeError(`Missing row ${i}`);
const row = rows[i];
if (!row || typeof row !== 'object' || Array.isArray(row) ||
!Object.hasOwn(row, 'orderId') ||
typeof row.orderId !== 'string' || row.orderId.trim() === '' ||
!Object.hasOwn(row, 'quantity') ||
!Number.isSafeInteger(row.quantity) || row.quantity < 1) {
throw new TypeError(`Invalid row ${i}`);
}
accepted.push({ orderId: row.orderId, quantity: row.quantity });
}
return accepted;
}
const sample = { orderId: 'local-example-1', quantity: 2 };
const sparse = [sample, ,];
assert.equal(sparse.length, 2);
assert.equal(sparse.every(row => row.quantity > 0), true);
assert.throws(() => readBatch(sparse), /Missing row 1/);
const deleted = [sample, sample];
delete deleted[0];
assert.throws(() => readBatch(deleted), /Missing row 0/);
const inherited = new Array(1);
const localPrototype = Object.create(Array.prototype);
localPrototype[0] = sample;
Object.setPrototypeOf(inherited, localPrototype);
assert.equal(inherited.every(row => row.quantity > 0), true);
assert.throws(() => readBatch(inherited), /Missing row 0/);
for (const invalid of [[], new Array(1001), [undefined], [null],
[{ orderId: 'x', quantity: 0 }], { 0: sample, length: 1 }]) {
assert.throws(() => readBatch(invalid), TypeError);
}
const source = [sample];
const result = readBatch(source);
assert.deepEqual(result, [sample]);
assert.notEqual(result, source);
assert.notEqual(result[0], sample);
assert.deepEqual(source, [sample]);
console.log('Dense warehouse batch checks passed');
Save this as dense-batch.cjs and run it with Node.js. The checks demonstrate a hole, a deleted position and an inherited numeric property that every() can visit. They also reject explicit missing values and an array-like object, and confirm that valid input produces new flat records without changing the source.
The 1,000-row limit is an illustrative application limit, not a Shopify limit. Object.hasOwn() distinguishes the array's own positions from inherited ones. This function assumes ordinary data objects; it is not a sandbox for hostile getters, proxies or objects changing during validation.
Keep acceptance separate from dispatch
In a shopify fulfillment workflow, accepting a dense input batch should precede any operation that creates warehouse work. This example performs no network call, inventory reservation or order release. A real china fulfillment interface still needs its own field rules, authorization and duplicate handling.
Suppose an integration inquiry uses the phrase International Fulfillment for Folligen. Its batch contract should still explain what each array position represents; that hypothetical label supplies no proof of a client relationship or working integration. Ask a china 3PL to confirm the actual import format before adapting the example.
For the operational setup questions outside this local JavaScript check, see YX Fulfillment's Shopify order setup guide.
Warehouse workstations and equipment.

Top comments (0)