Improve FAQ & video rendering, tighten homepage and CSS
This commit is contained in:
parent
05a1f316e1
commit
c69bb0d614
48 changed files with 4689 additions and 1077 deletions
97
video/src/auth.ts
Normal file
97
video/src/auth.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { chromium } from 'playwright';
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { APP_URL, AUTH_STATE_PATH } from './config.js';
|
||||
|
||||
/**
|
||||
* Auth setup. Two modes:
|
||||
*
|
||||
* 1. Programmatic (preferred for CI / non-interactive runs): set
|
||||
* PB_URL, PB_EMAIL, PB_PASSWORD env vars. We hit the PocketBase REST
|
||||
* auth-with-password endpoint, then hand-write a Playwright storageState
|
||||
* file with the resulting token in localStorage["pb_auth"]. The PocketBase
|
||||
* JS SDK reads that key on boot and treats us as logged in — bit-equivalent
|
||||
* to a real UI login.
|
||||
*
|
||||
* 2. Interactive: no env vars, we open a headed browser, you log in by hand,
|
||||
* press Enter, and we serialize the resulting cookies + localStorage.
|
||||
* Works on a developer laptop; doesn't work in headless environments.
|
||||
*/
|
||||
|
||||
interface PbAuthResponse {
|
||||
token: string;
|
||||
record: Record<string, unknown>;
|
||||
}
|
||||
|
||||
async function programmatic() {
|
||||
const email = process.env.PB_EMAIL!;
|
||||
const password = process.env.PB_PASSWORD!;
|
||||
|
||||
// Driving the login through the app itself ensures the PocketBase SDK's
|
||||
// LocalAuthStore sees the token via its own write path. Hand-writing
|
||||
// localStorage["pb_auth"] sometimes races with the SDK's module-time read.
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext({ viewport: { width: 1280, height: 800 } });
|
||||
const page = await context.newPage();
|
||||
await page.goto(APP_URL);
|
||||
|
||||
await page.evaluate(
|
||||
async ({ email, password }) => {
|
||||
const res = await fetch('/pb/api/collections/users/auth-with-password', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ identity: email, password }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`login ${res.status} ${await res.text()}`);
|
||||
const data = await res.json();
|
||||
// The SDK's LocalAuthStore default storageKey is "pocketbase_auth",
|
||||
// not "pb_auth" (which is just the cookie name in BaseAuthStore).
|
||||
localStorage.setItem(
|
||||
'pocketbase_auth',
|
||||
JSON.stringify({ token: data.token, record: data.record })
|
||||
);
|
||||
// Skip the react-joyride product tour — its spotlight overlay
|
||||
// intercepts pointer events and breaks the recording.
|
||||
localStorage.setItem('tutorial_completed', '1');
|
||||
},
|
||||
{ email, password }
|
||||
);
|
||||
|
||||
await context.storageState({ path: AUTH_STATE_PATH });
|
||||
await browser.close();
|
||||
console.log(`Saved ${AUTH_STATE_PATH} via in-app PocketBase login (user: ${email}).`);
|
||||
}
|
||||
|
||||
async function interactive() {
|
||||
const browser = await chromium.launch({ headless: false });
|
||||
const context = await browser.newContext({ viewport: { width: 1280, height: 800 } });
|
||||
const page = await context.newPage();
|
||||
await page.goto(APP_URL);
|
||||
|
||||
console.log('');
|
||||
console.log(' → Log in via the UI in the opened browser window.');
|
||||
console.log(' → Once you see the dashboard, press Enter in this terminal.');
|
||||
console.log('');
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
process.stdin.resume();
|
||||
process.stdin.once('data', () => resolve());
|
||||
});
|
||||
|
||||
await context.storageState({ path: AUTH_STATE_PATH });
|
||||
console.log(`Saved storage state to ${AUTH_STATE_PATH}`);
|
||||
await browser.close();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (process.env.PB_URL && process.env.PB_EMAIL && process.env.PB_PASSWORD) {
|
||||
await programmatic();
|
||||
process.exit(0);
|
||||
}
|
||||
await interactive();
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue