← back to Dw Rotation Activator
Require confirmed Online Store availability before counting publication
0add27a785a2bb7821ea3d2ab3be6d99cc37f2a0 · 2026-09-09 12:21:58 -0700 · Steve Abrams
Files touched
A lib/publication-result.jsM rotate-activate.jsA test/publication-result.test.js
Diff
commit 0add27a785a2bb7821ea3d2ab3be6d99cc37f2a0
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 9 12:21:58 2026 -0700
Require confirmed Online Store availability before counting publication
---
lib/publication-result.js | 15 +++++++++++++++
rotate-activate.js | 11 ++++++++---
test/publication-result.test.js | 26 ++++++++++++++++++++++++++
3 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/lib/publication-result.js b/lib/publication-result.js
new file mode 100644
index 0000000..856767b
--- /dev/null
+++ b/lib/publication-result.js
@@ -0,0 +1,15 @@
+'use strict';
+
+function confirmedPublishMutation(response) {
+ const payload = response?.json?.data?.publishablePublish;
+ return response?.status === 200 && !response.json?.errors?.length &&
+ Array.isArray(payload?.userErrors) && payload.userErrors.length === 0;
+}
+
+function confirmedOnlineStore(response, productId) {
+ const product = response?.json?.data?.product;
+ return response?.status === 200 && !response.json?.errors?.length &&
+ typeof productId === 'string' && product?.id === productId && product.onStore === true;
+}
+
+module.exports = { confirmedPublishMutation, confirmedOnlineStore };
diff --git a/rotate-activate.js b/rotate-activate.js
index a3a4443..39aaf77 100644
--- a/rotate-activate.js
+++ b/rotate-activate.js
@@ -50,6 +50,7 @@ const { mfrGate } = require('./lib/mfr-gate.js');
const { canonicalProduct, widthFromLive, completeLiveProduct } = require('./lib/live-product-fields.js');
const { buildRepairReport } = require('./lib/readiness-repairs.js');
const { confirmedActivation } = require('./lib/activation-result.js');
+const { confirmedPublishMutation, confirmedOnlineStore } = require('./lib/publication-result.js');
const { countHourlyActivations } = require('./lib/hourly-activation-count.js');
const { activationAllowance, assertDailyCatchup } = require('./lib/activation-allowance.js');
const { reusedMfrSet, stagingColorFor } = require('./lib/mfr-gate-resolve.js');
@@ -149,13 +150,17 @@ async function loadPubs() {
async function publishToChannels(pid) {
const pubs = await loadPubs();
if (!pubs.length) return { published: false, why: 'no-publications-scope' };
+ const onlineStore = pubs.find(p => p.name === 'Online Store');
+ if (!onlineStore) return { published: false, why: 'Online Store publication is missing' };
const input = pubs.map((p) => ({ publicationId: p.id }));
const r = await gqlRetry(
`mutation($id:ID!,$input:[PublicationInput!]!){publishablePublish(id:$id,input:$input){userErrors{field message}}}`,
{ id: pid, input });
- const ue = r.json?.data?.publishablePublish?.userErrors || [];
- const real = ue.filter((e) => !/already|cannot be published to itself/i.test(e.message || ''));
- if (real.length) return { published: false, errors: real };
+ if (!confirmedPublishMutation(r)) return { published: false, why: 'Shopify did not confirm publication' };
+ const current = await gqlRetry(
+ `query($id:ID!,$publicationId:ID!){product(id:$id){id onStore:publishedOnPublication(publicationId:$publicationId)}}`,
+ { id: pid, publicationId: onlineStore.id });
+ if (!confirmedOnlineStore(current, pid)) return { published: false, why: 'Online Store publication was not confirmed by read-back' };
return { published: true, channels: pubs.length };
}
diff --git a/test/publication-result.test.js b/test/publication-result.test.js
new file mode 100644
index 0000000..39279df
--- /dev/null
+++ b/test/publication-result.test.js
@@ -0,0 +1,26 @@
+'use strict';
+const test = require('node:test');
+const assert = require('node:assert/strict');
+const { confirmedPublishMutation, confirmedOnlineStore } = require('../lib/publication-result');
+
+test('publication requires a complete successful mutation reply', () => {
+ assert.equal(confirmedPublishMutation({ status: 200, json: { data: { publishablePublish: { userErrors: [] } } } }), true);
+ for (const r of [null, {}, { status: 200, json: null }, { status: 200, json: {} },
+ { status: 429, json: { data: { publishablePublish: { userErrors: [] } } } },
+ { status: 200, json: { errors: [{ message: 'THROTTLED' }] } },
+ { status: 200, json: { data: { publishablePublish: { userErrors: [{ message: 'not allowed' }] } } } },
+ { status: 200, json: { data: { publishablePublish: {} } } }])
+ assert.equal(confirmedPublishMutation(r), false);
+});
+
+test('publication additionally requires an independent current Online Store read', () => {
+ const good = { status: 200, json: { data: { product: { id: 'p1', onStore: true } } } };
+ assert.equal(confirmedOnlineStore(good, 'p1'), true);
+ assert.equal(confirmedOnlineStore(good, 'p2'), false);
+ for (const r of [null, {}, { status: 200, json: null }, { status: 200, json: {} },
+ { status: 200, json: { data: { product: null } } },
+ { status: 200, json: { data: { product: { id: 'p1', onStore: false } } } },
+ { status: 500, json: good.json },
+ { status: 200, json: { ...good.json, errors: [{ message: 'access denied' }] } }])
+ assert.equal(confirmedOnlineStore(r, 'p1'), false);
+});
← 9720a3e Enable verified one-day activation catch-up within daily all
·
back to Dw Rotation Activator
·
Record verified 462-product loading and unresolved Google ch 0bd5974 →