Lines 24-64javascript
24 * to the redeploy, in which a leaked link still works. If you ever need instant
25 * revocation, teams must move out of env vars into a per-request store
26 * (Edge Config / KV) and lib/access.ts must become async.
28 * `expires` is unaffected by all this: expired() is evaluated at request time
29 * against a value already baked into the running deployment.
31 * WHY WE ASK THE SITE, NOT VERCEL
33 * `vercel redeploy <url>` rebuilds THAT deployment's source snapshot. If the
34 * latest production deployment is behind origin/main — a push still building, a
35 * failed build — then redeploying to apply an env change also rolls the room's
36 * CONTENT back, silently. So every redeploy asserts the live commit matches
39 * Vercel cannot answer "what commit is serving?" (`vercel inspect` reports no
40 * sha, and Ready != aliased). So the app exposes it at /api/version, behind a
41 * team cookie, and we ask the running site.
44import { randomBytes } from "node:crypto";
45import { spawnSync } from "node:child_process";
46import { writeFileSync, readFileSync, mkdtempSync, rmSync } from "node:fs";
HighChild Process
Package source references child process execution.
template/scripts/portal.mjsView on unpkg · L44 47import { tmpdir } from "node:os";
48import { join } from "node:path";
50// Load .env.local (gitignored) so a secret like POSTHOG_PERSONAL_API_KEY can live
51// there instead of the shell. Anything already in the real env always wins.
53 for (const line of readFileSync(join(process.cwd(), ".env.local"), "utf8").split("\n")) {
54 const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/);
55 if (!m || process.env[m[1]] !== undefined) continue;
57 if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1);
58 process.env[m[1]] = v;
60} catch { /* no .env.local — fine */ }
62const VAR = "PORTAL_TEAMS";
63const ENVIRONMENT = "production";
64// Production URL of this portal, e.g. https://portal.example.com. Set it in