← back to Pattern Vault
spoonflower: default to Browserbase cloud (no local Chrome); local fallback uses isolated bundled Chromium not real Chrome; drop real-Chrome manual helper per Steve
42412e96a8fa561ea594c7c87b24e64e6cff5d58 · 2026-07-16 10:06:57 -0700 · Steve Abrams
Files touched
M whimsical-compare/daily/scripts/capture_sf_session.jsD whimsical-compare/daily/scripts/sf_login_manual.shM whimsical-compare/daily/scripts/upload_sf.js
Diff
commit 42412e96a8fa561ea594c7c87b24e64e6cff5d58
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Jul 16 10:06:57 2026 -0700
spoonflower: default to Browserbase cloud (no local Chrome); local fallback uses isolated bundled Chromium not real Chrome; drop real-Chrome manual helper per Steve
---
.../daily/scripts/capture_sf_session.js | 23 +++-------
whimsical-compare/daily/scripts/sf_login_manual.sh | 52 ----------------------
whimsical-compare/daily/scripts/upload_sf.js | 23 +++++-----
3 files changed, 18 insertions(+), 80 deletions(-)
diff --git a/whimsical-compare/daily/scripts/capture_sf_session.js b/whimsical-compare/daily/scripts/capture_sf_session.js
index 0eaaa1e..813bb2f 100644
--- a/whimsical-compare/daily/scripts/capture_sf_session.js
+++ b/whimsical-compare/daily/scripts/capture_sf_session.js
@@ -34,31 +34,20 @@ const EMAIL = process.env.SPOONFLOWER_EMAIL || envFile.SPOONFLOWER_EMAIL;
const PASSWORD = process.env.SPOONFLOWER_PASSWORD || envFile.SPOONFLOWER_PASSWORD;
const STATE = process.env.SF_STATE || path.join(os.homedir(), '.config/pattern-vault/sf-state.json');
const HEADFUL = process.argv.includes('--headful');
-const MANUAL = process.argv.includes('--manual');
-
-// --manual: escalation fallback when Cloudflare bounces even the Playwright real-Chrome path.
-// Hands off to sf_login_manual.sh, which opens the SHARED profile in plain real Chrome (zero
-// automation flags) so you log in + clear the human-check by hand. No env creds needed.
-if (MANUAL) {
- const { spawnSync } = require('child_process');
- const r = spawnSync('bash', [path.join(__dirname, 'sf_login_manual.sh')], { stdio: 'inherit' });
- process.exit(r.status || 0);
-}
if (!EMAIL || !PASSWORD) { console.error('❌ missing SPOONFLOWER_EMAIL/PASSWORD (env or resize-it/.env)'); process.exit(2); }
console.log(`🔐 capturing session for ${EMAIL} → ${STATE}`);
(async () => {
fs.mkdirSync(path.dirname(STATE), { recursive: true });
- // REAL Google Chrome (channel:'chrome'), NOT Playwright's bundled Chromium. Cloudflare
- // fingerprints bundled Chromium and loops the "verify you are human" check forever even after
- // you solve it. A persistent profile keeps the cf_clearance cookie + login together so the
- // clearance you earn once survives into upload_sf.js. NO userAgent override — a spoofed UA that
- // mismatches the real Chrome binary is itself a CF red flag and voids cf_clearance.
- const PROFILE = process.env.SF_PROFILE || path.join(os.homedir(), '.config/pattern-vault/sf-chrome-profile');
+ // Isolated bundled Chromium (a separate Chromium app), NOT Steve's real Google Chrome — no
+ // channel:'chrome', so this never hijacks his browser or profile. NOTE: bundled Chromium is more
+ // CF-detectable, so the primary/default path is now Browserbase (upload_sf.js, cloud) which logs
+ // in fresh and needs no local capture at all. This local capture stays for the SF_LOCAL fallback.
+ const PROFILE = process.env.SF_PROFILE || path.join(os.homedir(), '.config/pattern-vault/sf-chromium-profile');
fs.mkdirSync(PROFILE, { recursive: true });
const ctx = await chromium.launchPersistentContext(PROFILE, {
- headless: !HEADFUL, channel: 'chrome', viewport: null,
+ headless: !HEADFUL, viewport: null,
ignoreDefaultArgs: ['--enable-automation'], // drop the automation banner
args: ['--disable-blink-features=AutomationControlled'], // hide navigator.webdriver from CF
});
diff --git a/whimsical-compare/daily/scripts/sf_login_manual.sh b/whimsical-compare/daily/scripts/sf_login_manual.sh
deleted file mode 100755
index a3f1576..0000000
--- a/whimsical-compare/daily/scripts/sf_login_manual.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env bash
-# ---------------------------------------------------------------------------
-# Spoonflower login FALLBACK — the most-human, least-detectable path.
-#
-# Opens the SHARED persistent profile (the same --user-data-dir upload_sf.js and
-# capture_sf_session.js use) in REAL Google Chrome with ZERO automation flags —
-# no Playwright, no CDP, no --enable-automation. This is the openclaw principle:
-# a genuine human Chrome that Cloudflare waves straight through.
-#
-# You log in + solve any "verify you are human" / Cloudflare check BY HAND, then
-# CLOSE the window. The login (and the valid cf_clearance cookie) persist inside
-# the profile on disk, so upload_sf.js reuses it with no challenge.
-#
-# Rule-safe: nothing is extracted. The session stays inside the browser profile —
-# no cookie/token dump (which the safety classifier blocks, correctly).
-#
-# Use this when the Playwright `channel:'chrome'` capture still lands on /login
-# (Cloudflare still bounced the automated fingerprint). Escalation ladder:
-# 1. node capture_sf_session.js --headful (Playwright real-Chrome)
-# 2. THIS script (plain real-Chrome, no automation)
-# 3. browserbase (proxies + solveCaptchas) (cloud, clears CF natively)
-# ---------------------------------------------------------------------------
-set -euo pipefail
-
-PROFILE="${SF_PROFILE:-$HOME/.config/pattern-vault/sf-chrome-profile}"
-CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
-
-[ -x "$CHROME" ] || { echo "❌ Google Chrome not found at: $CHROME"; exit 1; }
-mkdir -p "$PROFILE"
-
-cat <<EOF
-🔐 Opening Spoonflower in REAL Chrome (no automation) — profile: $PROFILE
-
- Account: info@designerwallcoverings.com
- 1) Log in.
- 2) Solve any "verify you are human" / Cloudflare check.
- 3) When you're signed in, CLOSE this Chrome window.
-
- Waiting until you close it…
-EOF
-
-# Foreground the binary against the DEDICATED profile dir so this blocks until the
-# window is closed. A dedicated data-dir means closing its only window quits this
-# instance (and won't disturb your everyday Chrome).
-"$CHROME" \
- --user-data-dir="$PROFILE" \
- --no-first-run \
- --no-default-browser-check \
- "https://www.spoonflower.com/login" >/dev/null 2>&1 || true
-
-echo "✅ Chrome closed — profile primed."
-echo " Verify + upload: node upload_sf.js <manifest.json> --armed"
diff --git a/whimsical-compare/daily/scripts/upload_sf.js b/whimsical-compare/daily/scripts/upload_sf.js
index 7304780..64b506f 100755
--- a/whimsical-compare/daily/scripts/upload_sf.js
+++ b/whimsical-compare/daily/scripts/upload_sf.js
@@ -26,9 +26,11 @@ const os = require('os');
const MANIFEST = process.argv[2];
const ARMED = process.argv.includes('--armed');
-// RUNG 3: cloud Chrome (residential proxy + native Cloudflare/captcha solving) when the local
-// browser is fingerprint-blocked. SF_BROWSERBASE=1 selects it. Logs in FRESH (no cloud profile).
-const BROWSERBASE = process.env.SF_BROWSERBASE === '1';
+// DEFAULT TRANSPORT = Browserbase cloud Chrome (residential proxy + native Cloudflare/captcha
+// solving). It runs entirely in the cloud — NO local browser window ever opens, and it never
+// touches Steve's real Chrome. Logs in FRESH (no cloud profile). Opt into the local isolated
+// Chromium fallback with SF_LOCAL=1 (only if you specifically want a local run).
+const BROWSERBASE = process.env.SF_LOCAL !== '1';
// minimal KEY=value .env parser (no dotenv dep) — same shape capture_sf_session.js uses
function loadEnvFile(p) { const o = {}; try { for (const l of fs.readFileSync(p, 'utf8').split('\n')) { const m = l.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/); if (m) o[m[1]] = m[2].replace(/^"(.*)"$/, '$1'); } } catch {} return o; }
const rzEnv = loadEnvFile(path.join(os.homedir(), '.claude/skills/resize-it/.env'));
@@ -98,19 +100,18 @@ async function messyType(el, text) {
browser = await chromium.connectOverCDP(bbSession.connectUrl);
ctx = browser.contexts()[0];
} else {
- // ---- RUNGS 1-2: local REAL Google Chrome + the SAME persistent profile the capture step
- // cleared Cloudflare in. Bundled Chromium (the old chromium.launch) was what CF blocked;
- // the spoofed Chrome/126 UA made it worse. channel:'chrome' + no UA override = one honest
- // fingerprint, and the on-disk profile carries a valid cf_clearance.
- if (!fs.existsSync(STATE)) { result.sessionExpired = true; result.error = 'no session file (run capture_sf_session.js --headful, or use SF_BROWSERBASE=1)'; console.log(JSON.stringify(result)); return; }
- const PROFILE = process.env.SF_PROFILE || path.join(os.homedir(), '.config/pattern-vault/sf-chrome-profile');
+ // ---- LOCAL FALLBACK (SF_LOCAL=1 only): isolated bundled Chromium — a separate Chromium app,
+ // NOT Steve's real Google Chrome (no channel:'chrome'), so it can't hijack his browser/profile.
+ // Uses its own persistent profile for the login. Note: bundled Chromium is more CF-detectable
+ // than the cloud path, so Browserbase (the default) remains the reliable route past Cloudflare.
+ if (!fs.existsSync(STATE)) { result.sessionExpired = true; result.error = 'no session file for local fallback (default path is Browserbase — just run without SF_LOCAL)'; console.log(JSON.stringify(result)); return; }
+ const PROFILE = process.env.SF_PROFILE || path.join(os.homedir(), '.config/pattern-vault/sf-chromium-profile');
fs.mkdirSync(PROFILE, { recursive: true });
ctx = await chromium.launchPersistentContext(PROFILE, {
headless: (process.env.SF_HEADLESS === '1') ? true : !ARMED,
- channel: 'chrome',
viewport: ARMED ? null : { width: 1400, height: 900 },
ignoreDefaultArgs: ['--enable-automation'], // drop the automation banner
- args: ['--start-maximized', '--disable-blink-features=AutomationControlled'], // hide navigator.webdriver
+ args: ['--disable-blink-features=AutomationControlled'], // hide navigator.webdriver
});
// Bridge the existing Spoonflower login from the legacy storageState file (portable auth cookies)
// in case this profile is fresh. cf_clearance is fingerprint-bound and intentionally NOT imported.
← c528dae spoonflower: add rung-3 Browserbase upload path (SF_BROWSERB
·
back to Pattern Vault
·
chore: lint, refactor, v0.2.3 (session close) a337213 →