stack/examples/demo/cli-sim.mjs
Bilal Godil 178b5c5a8c chore: rename STACK_* env vars to HEXCLAVE_* in env templates, with legacy dual-read
Renames every STACK_*-prefixed variable (including NEXT_PUBLIC_STACK_*) to
HEXCLAVE_* across all checked-in .env, .env.development, and .env.example
files, completing the env-var side of the Hexclave rebrand. Legacy STACK_*
names keep working everywhere so existing deployments, .env.local files, and
self-hosted setups don't need immediate migration:

- getEnvVariable already prefers HEXCLAVE_* with STACK_* fallback; fix it to
  treat empty-string values as unset so the empty HEXCLAVE_* placeholders in
  the checked-in templates can't shadow a real value under the legacy name.
- Apply the same empty-as-unset rule (|| instead of ??) to all literal
  process.env dual-reads (dashboard inline env, docs, examples, CLI) and to
  the generated SDK env getter chains via packages/template generate-env.ts.
- Add explicit HEXCLAVE_* || STACK_* dual-reads to direct process.env readers
  fed by the renamed files: prisma seed, e2e tests/helpers, internal-tool
  scripts and app, demo/convex examples.
- docker/server/entrypoint.sh: add a generic two-way HEXCLAVE_/STACK_ env
  mirror (run at startup and again before sentinel replacement), replacing the
  previous URL-trio-only mirror; accept legacy NEXT_PUBLIC_STACK_PORT_PREFIX;
  rotate-secrets.sh falls back to HEXCLAVE_DATABASE_CONNECTION_STRING.
- e2e cross-domain-auth and the internal-feedback-emails in-source test now
  override the canonical HEXCLAVE_* names (the legacy override would be
  shadowed by the renamed env files).
- docs/code-examples snippets renamed outright to the canonical names.
2026-06-11 16:23:50 -07:00

90 lines
2.7 KiB
JavaScript

#!/usr/bin/env node
/** Minimal `stack login` flow for local demos. Usage: `node cli-sim.mjs` */
const API_URL = (process.env.HEXCLAVE_API_URL || process.env.STACK_API_URL) || "http://localhost:8102";
const APP_URL = (process.env.HEXCLAVE_APP_URL || process.env.STACK_APP_URL) || "http://localhost:8103";
const PROJECT_ID = "internal";
const PUBLISHABLE_KEY = "this-publishable-client-key-is-for-local-development-only";
const headers = {
"Content-Type": "application/json",
"x-stack-access-type": "client",
"x-stack-project-id": PROJECT_ID,
"x-stack-publishable-client-key": PUBLISHABLE_KEY,
};
async function main() {
console.log("=== Hexclave CLI Simulator ===\n");
console.log(`API: ${API_URL}`);
console.log(`App: ${APP_URL}\n`);
console.log("Initiating CLI auth...");
const initRes = await fetch(`${API_URL}/api/v1/auth/cli`, {
method: "POST",
headers,
body: JSON.stringify({
expires_in_millis: 1000 * 60 * 10,
}),
});
if (!initRes.ok) {
console.error(`Failed to initiate: ${initRes.status} ${await initRes.text()}`);
process.exit(1);
}
const { polling_code, login_code, expires_at } = await initRes.json();
console.log(`\n${"=".repeat(40)}`);
console.log(` Verification Code: ${login_code}`);
console.log(`${"=".repeat(40)}\n`);
console.log(`Open this URL in your browser:\n`);
console.log(` ${APP_URL}/handler/cli-auth-confirm?login_code=${encodeURIComponent(login_code)}\n`);
console.log(`Expires: ${new Date(expires_at).toLocaleTimeString()}`);
console.log(`\nWaiting for browser authorization...`);
const POLL_INTERVAL = 2000;
let attempts = 0;
while (true) {
attempts++;
const pollRes = await fetch(`${API_URL}/api/v1/auth/cli/poll`, {
method: "POST",
headers,
body: JSON.stringify({ polling_code }),
});
if (!pollRes.ok) {
console.error(`Poll failed: ${pollRes.status} ${await pollRes.text()}`);
process.exit(1);
}
const result = await pollRes.json();
if (result.status === "success") {
console.log(`\nLogin successful! (after ${attempts} poll attempts)`);
console.log(`Refresh token: ${result.refresh_token.slice(0, 20)}...`);
console.log("\nIn a real CLI, this token would be saved to ~/.config/hexclave/credentials.json");
break;
}
if (result.status === "expired") {
console.error("\nAuth session expired. Please try again.");
process.exit(1);
}
if (result.status === "used") {
console.error("\nThis auth token was already used.");
process.exit(1);
}
process.stdout.write(".");
await new Promise((r) => setTimeout(r, POLL_INTERVAL));
}
}
main().catch((err) => {
console.error("Error:", err);
process.exit(1);
});