channel-worker 2.5.8 → 2.5.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "channel-worker",
3
- "version": "2.5.8",
3
+ "version": "2.5.10",
4
4
  "description": "Channel Manager worker daemon — runs on remote machines to execute video pipeline jobs",
5
5
  "main": "lib/daemon.js",
6
6
  "bin": {
@@ -128,22 +128,40 @@ async function dumpFailure(page, tag, log) {
128
128
  // "Đã hiểu" / "Bỏ qua" inside the dialog, then check again.
129
129
  async function dismissBsOnboarding(page, log) {
130
130
  for (let pass = 0; pass < 3; pass++) {
131
- const dlg = page.locator("[role='dialog']").first();
132
- const has = await dlg.count().catch(() => 0);
133
- if (!has || !(await dlg.isVisible().catch(() => false))) return;
131
+ // Pick the FIRST visible dialog that is NOT the Reels composer. The
132
+ // Reels modal ('Tạo thước phim' / 'Create reel') has its own '✕' Close
133
+ // button with aria-label='Đóng'; without this guard dismissBsOnboarding
134
+ // happily closes the composer immediately after we just opened it, and
135
+ // the subsequent 'Thêm video' click can't find the modal.
136
+ const dlgInfo = await page.evaluate(() => {
137
+ const dlgs = document.querySelectorAll("[role='dialog']");
138
+ for (const d of dlgs) {
139
+ const r = d.getBoundingClientRect();
140
+ if (r.width < 8 || r.height < 8) continue;
141
+ const cs = getComputedStyle(d);
142
+ if (cs.visibility === 'hidden' || cs.display === 'none') continue;
143
+ const txt = (d.innerText || '').slice(0, 400);
144
+ // Skip the Reels composer — that's the modal we just opened.
145
+ if (/Tạo thước phim|Create reel|Create a reel|Tạo thư�?c phim/i.test(txt)) continue;
146
+ d.setAttribute('__fbpw_onboarding__', '1');
147
+ return { tag: 'ok', preview: txt.slice(0, 80) };
148
+ }
149
+ return null;
150
+ }).catch(() => null);
151
+ if (!dlgInfo) return;
134
152
  const phrases = ['Đã hiểu', 'Got it', 'Bỏ qua', 'Skip', 'Để sau', 'Not now', 'Đóng', 'Close', 'Tiếp tục', 'Continue'];
135
153
  let clicked = false;
136
154
  for (const p of phrases) {
137
155
  const candidates = [
138
- `[role='dialog'] [aria-label*='${p}']`,
139
- `[role='dialog'] [role='button']:has-text('${p}')`,
140
- `[role='dialog'] button:has-text('${p}')`,
156
+ `[__fbpw_onboarding__='1'] [aria-label*='${p}']`,
157
+ `[__fbpw_onboarding__='1'] [role='button']:has-text('${p}')`,
158
+ `[__fbpw_onboarding__='1'] button:has-text('${p}')`,
141
159
  ];
142
160
  for (const sel of candidates) {
143
161
  const hit = await firstVisible(page.locator(sel), 3);
144
162
  if (!hit) continue;
145
163
  try {
146
- log('info', `[fb-pw] dismissing BS onboarding via "${sel}"`);
164
+ log('info', `[fb-pw] dismissing BS onboarding via "${sel}" (dlg="${dlgInfo.preview}")`);
147
165
  await hit.click({ timeout: 2500 });
148
166
  await page.waitForTimeout(700);
149
167
  clicked = true;
@@ -152,9 +170,11 @@ async function dismissBsOnboarding(page, log) {
152
170
  }
153
171
  if (clicked) break;
154
172
  }
173
+ // Clean up the marker attr regardless of outcome.
174
+ await page.evaluate(() => document.querySelectorAll("[__fbpw_onboarding__]").forEach((el) => el.removeAttribute('__fbpw_onboarding__'))).catch(() => {});
155
175
  if (!clicked) {
156
- try { await page.keyboard.press('Escape'); } catch {}
157
- await page.waitForTimeout(500);
176
+ // Don't blindly press Escape would also close the Reels composer
177
+ // if it's the topmost dialog. Bail instead.
158
178
  return;
159
179
  }
160
180
  }
@@ -1299,6 +1319,17 @@ async function run({ page, payload, log }) {
1299
1319
  throw new Error(`FB publish: thumbnail_url provided but the "Chỉnh sửa hình thu nhỏ" overlay was never detected before publish (step ${step + 1}). Refusing to ship without custom thumb. Inspect dump screenshots in Temp\\cm-worker-pw\\.`);
1300
1320
  }
1301
1321
  log('info', `[fb-pw] click publish "${pub.verb}" via "${pub.sel}" (step ${step + 1})`);
1322
+ // DRY-RUN MODE (temporary, for QA): skip the actual publish click so
1323
+ // we can verify the upstream flow (modal scoping, video upload, thumb
1324
+ // step, metadata fill) without spawning real Reels every iteration.
1325
+ // Throws a recognisable error so the daemon marks the cmd failed
1326
+ // without retrying. REMOVE this block once the page-wall composer
1327
+ // fix is verified end-to-end.
1328
+ if (process.env.FB_PW_DRY_RUN === '1' || payload._dry_run === true) {
1329
+ await dumpInventory(page, log, `dry-run-at-publish-${step + 1}`);
1330
+ await dumpFailure(page, `dry-run-at-publish-${step + 1}`, log);
1331
+ throw new Error(`[fb-pw] DRY-RUN: reached publish step ${step + 1} successfully. Pub button found via "${pub.sel}" verb="${pub.verb}". Thumb=${customThumbDone ? 'uploaded' : 'NOT uploaded'}. NOT clicking. Inspect dump screenshots in Temp\\cm-worker-pw\\.`);
1332
+ }
1302
1333
  // Snapshot the captured-IDs list RIGHT BEFORE the publish click. The
1303
1334
  // network listener captures from EVERY graph response, including the
1304
1335
  // pre-publish page wall feed (~100+ IDs). Only IDs captured AFTER