Extract authenticated coulomb.social design language via designlang
Session probe lands on /vw_pages (Research). Use main designlang extract with --cookie-file — pack ignores auth. 39 artifacts under docs/design-extract; tolerate designlang late summary crash when cores exist.
This commit is contained in:
parent
319dd00465
commit
6fe263444a
71 changed files with 4939 additions and 797 deletions
|
|
@ -142,39 +142,33 @@ async function main() {
|
|||
const lsKeys = (state.origins || []).flatMap((o) =>
|
||||
(o.localStorage || []).map((e) => e.name),
|
||||
);
|
||||
// Bubble always sets coulomb_* session cookies for anonymous visitors.
|
||||
// A real login usually adds more localStorage keys and/or more cookies.
|
||||
const onlyDefaultBubbleCookies =
|
||||
cookieCount <= 3 &&
|
||||
(state.cookies || []).every((c) =>
|
||||
String(c.name || "").startsWith("coulomb_"),
|
||||
);
|
||||
const thinLocalStorage =
|
||||
lsKeys.length === 0 ||
|
||||
(lsKeys.length === 1 && lsKeys[0] === "algoliasearch-client-js");
|
||||
|
||||
if (onlyDefaultBubbleCookies && thinLocalStorage) {
|
||||
// Bubble often keeps the same coulomb_* cookie *names* for guests and
|
||||
// members — names alone are not a login signal. Probe the live page:
|
||||
// authenticated app usually leaves the bare landing path.
|
||||
let probeUrl = page.url();
|
||||
let probeTitle = await page.title().catch(() => "");
|
||||
const path = (() => {
|
||||
try {
|
||||
return new URL(probeUrl).pathname;
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
})();
|
||||
const looksLikeLanding = path === "/" || path === "";
|
||||
|
||||
if (looksLikeLanding && !fromPasswordFiles) {
|
||||
console.error("");
|
||||
console.error(
|
||||
"WARNING: This looks like an anonymous Bubble session, not a logged-in user.",
|
||||
"WARNING: Still on the site root after capture — login may not have completed.",
|
||||
);
|
||||
console.error(` url: ${probeUrl}`);
|
||||
console.error(` title: ${probeTitle}`);
|
||||
console.error(
|
||||
` cookies=${cookieCount} (only default coulomb_* names)`,
|
||||
"Log in fully, open an app page (e.g. Research / Pages), then press Enter.",
|
||||
);
|
||||
console.error(` localStorage keys: ${lsKeys.join(", ") || "(none)"}`);
|
||||
console.error("");
|
||||
console.error("Do not use this for authenticated design extract.");
|
||||
console.error("Re-run, fully log in, wait until the app UI is loaded,");
|
||||
console.error("then press Enter. If login uses a popup, complete it first.");
|
||||
process.exitCode = 2;
|
||||
// Still write so you can inspect, but mark filename
|
||||
const weakPath = STATE_PATH.replace(/\.json$/, ".anonymous.json");
|
||||
writeFileSync(weakPath, JSON.stringify(state, null, 2) + "\n", {
|
||||
mode: 0o600,
|
||||
});
|
||||
chmodSync(weakPath, 0o600);
|
||||
console.error(`Wrote weak session for inspection only: ${weakPath}`);
|
||||
return;
|
||||
// Continue to save anyway — Bubble guest+member share cookie names; user
|
||||
// may still have a valid session that only reveals itself after navigation.
|
||||
}
|
||||
|
||||
writeFileSync(STATE_PATH, JSON.stringify(state, null, 2) + "\n", {
|
||||
|
|
@ -186,6 +180,7 @@ async function main() {
|
|||
console.log(
|
||||
`Saved storageState (${cookieCount} cookies, ${originCount} origins, localStorage keys: ${lsKeys.length}).`,
|
||||
);
|
||||
console.log(` page at save: ${probeUrl} — ${probeTitle}`);
|
||||
console.log(`File: ${STATE_PATH}`);
|
||||
console.log("Next: ./scripts/run-design-extract.sh");
|
||||
} finally {
|
||||
|
|
|
|||
21
scripts/probe-auth-session.mjs
Executable file
21
scripts/probe-auth-session.mjs
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env node
|
||||
/** Print final URL after loading coulomb.social with storageState (no secrets). */
|
||||
import { chromium } from "playwright";
|
||||
import { homedir } from "os";
|
||||
import { join } from "path";
|
||||
|
||||
const statePath =
|
||||
process.env.COULOMB_SOCIAL_STORAGE_STATE ||
|
||||
join(homedir(), ".config/coulomb-social/auth/storage-state.json");
|
||||
const url = process.env.COULOMB_SOCIAL_URL || "https://coulomb.social";
|
||||
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
try {
|
||||
const context = await browser.newContext({ storageState: statePath });
|
||||
const page = await context.newPage();
|
||||
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 45000 });
|
||||
await page.waitForTimeout(3000);
|
||||
console.log(page.url());
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
# Run designlang against coulomb.social using a captured Playwright storageState.
|
||||
# Does not print secrets. Requires: ./scripts/capture-auth-state.mjs first.
|
||||
# Does not print secrets. Requires: ./scripts/capture-auth-state.sh first.
|
||||
#
|
||||
# NOTE: designlang's `pack` subcommand does NOT pass --cookie-file into the
|
||||
# crawler (it calls extractDesignLanguage(url) with no auth options). Use the
|
||||
# main extract command, which does apply cookies from storageState.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
|
@ -8,6 +12,7 @@ AUTH_DIR="${COULOMB_SOCIAL_AUTH_DIR:-$HOME/.config/coulomb-social/auth}"
|
|||
STATE_PATH="${COULOMB_SOCIAL_STORAGE_STATE:-$AUTH_DIR/storage-state.json}"
|
||||
OUT_DIR="${COULOMB_SOCIAL_EXTRACT_OUT:-$ROOT/docs/design-extract}"
|
||||
URL="${COULOMB_SOCIAL_URL:-https://coulomb.social}"
|
||||
WAIT_MS="${COULOMB_SOCIAL_EXTRACT_WAIT:-5000}"
|
||||
|
||||
if [[ ! -f "$STATE_PATH" ]]; then
|
||||
echo "ERROR: No auth session at $STATE_PATH" >&2
|
||||
|
|
@ -22,21 +27,78 @@ if [[ "$mode" != "600" && "$mode" != "0600" ]]; then
|
|||
echo "warning: $STATE_PATH mode is $mode (prefer 600)" >&2
|
||||
fi
|
||||
|
||||
echo "==> probing session (no secrets printed)…"
|
||||
PROBE_URL="$(
|
||||
cd "$ROOT/scripts" && \
|
||||
COULOMB_SOCIAL_STORAGE_STATE="$STATE_PATH" \
|
||||
COULOMB_SOCIAL_URL="$URL" \
|
||||
node ./probe-auth-session.mjs
|
||||
)" || PROBE_URL=""
|
||||
if [[ -n "$PROBE_URL" ]]; then
|
||||
echo " session lands on: $PROBE_URL"
|
||||
if [[ "$PROBE_URL" == "https://coulomb.social/" || "$PROBE_URL" == "https://coulomb.social" ]]; then
|
||||
echo "warning: session still on site root — may be guest; re-run capture-auth-state.sh if extract looks empty" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
echo "==> designlang extract"
|
||||
echo "==> designlang extract (main command — cookies applied)"
|
||||
echo " url: $URL"
|
||||
echo " auth: $STATE_PATH (session file present; not printed)"
|
||||
echo " out: $OUT_DIR"
|
||||
echo " wait: ${WAIT_MS}ms"
|
||||
echo " extra: $*"
|
||||
|
||||
# Global flags (auth, name) must precede the subcommand; pack only accepts -o/--with-clone/--open.
|
||||
# --cookie-file accepts Playwright storageState JSON.
|
||||
# Extra args after -- are appended to pack (e.g. --with-clone).
|
||||
mkdir -p "$(dirname "$OUT_DIR")"
|
||||
exec npx --yes designlang \
|
||||
# Main command supports --cookie-file. Prefer a rich capture of the live app UI.
|
||||
set +e
|
||||
npx --yes designlang "$URL" \
|
||||
--cookie-file "$STATE_PATH" \
|
||||
--name coulomb-social \
|
||||
pack "$URL" \
|
||||
-o "$OUT_DIR" \
|
||||
-n coulomb-social \
|
||||
--wait "$WAIT_MS" \
|
||||
--depth "${COULOMB_SOCIAL_EXTRACT_DEPTH:-2}" \
|
||||
--interactions \
|
||||
--verbose \
|
||||
"$@"
|
||||
dl_ec=$?
|
||||
set -e
|
||||
|
||||
# designlang can crash late while printing summary (Buffer.byteLength on undefined
|
||||
# content for optional emitters) after already writing the useful artifacts.
|
||||
if [[ $dl_ec -ne 0 ]]; then
|
||||
if [[ -f "$OUT_DIR/coulomb-social-design-language.md" && -f "$OUT_DIR/coulomb-social-design-tokens.json" ]]; then
|
||||
echo "warning: designlang exited $dl_ec after writing core artifacts (known late summary bug); treating as success" >&2
|
||||
else
|
||||
echo "ERROR: designlang failed (exit $dl_ec) and core artifacts are missing" >&2
|
||||
exit "$dl_ec"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Drop root-level pack leftovers from earlier mistaken `pack` runs (no cookies).
|
||||
if [[ -d "$ROOT/coulomb-social-design-system" ]]; then
|
||||
echo "==> removing unauthenticated pack leftover: coulomb-social-design-system/"
|
||||
rm -rf "$ROOT/coulomb-social-design-system"
|
||||
fi
|
||||
|
||||
# Provenance (no secrets)
|
||||
cat > "$OUT_DIR/PROVENANCE.md" <<EOF
|
||||
# Design extract provenance
|
||||
|
||||
| Field | Value |
|
||||
|-------|--------|
|
||||
| Source | $URL |
|
||||
| Tool | designlang (main extract, not pack) |
|
||||
| Captured | $(date -Iseconds) |
|
||||
| Auth | Playwright storageState via --cookie-file |
|
||||
| Session probe | ${PROBE_URL:-unknown} |
|
||||
| designlang exit | $dl_ec |
|
||||
|
||||
## Note
|
||||
|
||||
Use \`./scripts/run-design-extract.sh\` — do **not** use \`designlang pack\` for
|
||||
authenticated crawls; pack ignores cookies.
|
||||
EOF
|
||||
|
||||
echo "==> done. Inspect: $OUT_DIR"
|
||||
ls -la "$OUT_DIR" | head -50
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue