stack/apps/dashboard/src/lib/version-check.ts
BilalG1 501ae9fe61
PR 4: Rename Stack -> Hexclave: examples config module, app-internal symbols, crypto docs (#1534)
## What

Continues the **Stack Auth → Hexclave** rename for a set of safe,
internal-only surfaces. This intentionally avoids public-contract names.

### Changes
- **Examples** — renamed the user-facing config module
`stack.ts`/`stack.tsx` (and the `convex` / `lovable` `stack/`
directories) to `hexclave`, and updated every importer across
`.ts`/`.tsx`/`.jsx`. The public `app/handler/[...stack]/` route segment
is left unchanged.
- **apps/{dashboard,backend,internal-tool}** — renamed app-local
SDK-init symbols `stackClientApp → hexclaveClientApp` and
`getStackServerApp → getHexclaveServerApp`, and the dashboard
`StackCompanion` component → `HexclaveCompanion` (incl.
`useStackCompanion`, context types). The public
`StackClientApp`/`StackServerApp` SDK classes are **unchanged**.
- **packages/stack-shared** — added comments to the crypto / JWT / vault
`stack-*` literals documenting that they must **not** be renamed (key
derivation / JWKS / KMS-alias stability). The literals are
byte-identical.

### Deliberately excluded
- **`STACK_*` → `HEXCLAVE_*` env-var rename** — `HEXCLAVE_*` already
resolves via the dual-read layers (SDK env, dashboard `_inlineEnvVars`,
`getEnvVariable`). The remaining holdout is the docker post-build
sentinel path, which the codebase authors explicitly deferred and which
is tightly coupled to `entrypoint.sh` + untestable here. A blind rename
there risks silently breaking self-host/emulator bootstrap for ~zero
functional gain.
- **All public-contract names** — SDK class names, env vars, HTTP
headers (`x-stack-*`), and the `/handler` route convention.

## Verification
- `pnpm lint` — **29/29 passing**.
- `pnpm typecheck` — **28/29 passing**; the only failure is
`@hexclave/docs` (pre-existing missing fumadocs `.source` codegen,
untouched by this PR).
- Two rounds of adversarial multi-agent review; findings fixed:
string-literal collateral from the symbol sweep (CLI test fixtures + an
AI-prompt template) reverted, and a missed `.jsx` importer in
`examples/cjs-test` corrected.

## Notes
- Based on a `dev` snapshot from when the branch was cut (a couple
commits behind tip); the diff contains only the changes above.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Complete the internal “Stack” → “Hexclave” rename across examples,
app-local code, config tooling, and setup docs, and standardize env
output to HEXCLAVE_* with correct default API URL handling. Public SDK
classes, handler routes, and legacy env names keep working.

- **Refactors**
- Examples/config: `stack.*` files and `stack/` dirs →
`hexclave.*`/`hexclave/`; imports updated; keep `app/handler/[...stack]`
route.
- Apps: backend/dashboard/internal-tool now use `getHexclaveServerApp`
and `hexclaveClientApp`; dashboard `StackCompanion` →
`HexclaveCompanion`. Public `StackClientApp`/`StackServerApp` unchanged.
- Env/setup: Next.js and CLI generators write HEXCLAVE_* and omit API
URL when using https://api.stack-auth.com; CLI `doctor` and auth
resolution prefer HEXCLAVE_* (e.g. `HEXCLAVE_SECRET_SERVER_KEY`,
`HEXCLAVE_PROJECT_ID`) with `STACK_*` fallback.
- Config tooling: `stack-config-file` → `hexclave-config-file`, emitting
`HexclaveConfig`; imports updated across backend/dashboard/tooling.
- Shared/docs: added “do not rename” notes for crypto/JWT/vault
`stack-*` literals; regenerated setup prompt/docs to use
`hexclave.config.ts`, `hexclave dev`, and `src/hexclave/`.
- Tests: updated snapshots/assertions to expect `HexclaveConfig` and
HEXCLAVE_* env names.

- **Migration**
  - No action required. SDK and CLI read both HEXCLAVE_* and STACK_*.

<sup>Written for commit 8a891b4f6c.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1534?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Renamed internal app/client/server instances and companion/provider
components to the new product name across backend, dashboard, examples,
and tooling; imports updated accordingly.
* Updated generated environment variable names and CLI init/doctor
outputs to prefer the new product prefix.

* **Documentation**
* Added clarifying notes about vault/encryption and JWT/key labels to
avoid breaking existing encrypted data.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-03 12:09:20 -07:00

113 lines
3.3 KiB
TypeScript

import { getPublicEnvVar } from '@/lib/env';
import { runAsynchronously, wait } from "@hexclave/shared/dist/utils/promises";
import packageJson from "../../package.json";
export type VersionCheckResult = {
severe: boolean,
error: string,
} | null;
export type VersionCheckOptions = {
/** Delay before making the request (in milliseconds) */
delay?: number,
/** Whether to silently fail or throw errors */
silentFailure?: boolean,
/** Custom error message prefix for logging */
errorPrefix?: string,
};
/**
* Hook to check if non-severe version alerts should be shown
* Based on NEXT_PUBLIC_VERSION_ALERTER_SEVERE_ONLY environment variable
*/
export function shouldShowNonSevereVersionCheck(): boolean {
// IMPORTANT: THIS ENVIRONMENT VARIABLE IS UNDOCUMENTED AND NOT MEANT FOR PRODUCTION USAGE
// AND YOU SHOULD ALWAYS KEEP STACK AUTH UP TO DATE. WE CAN'T APPLY SECURITY UPDATES IF
// YOU DON'T UPDATE STACK AUTH REGULARLY.
return getPublicEnvVar('NEXT_PUBLIC_VERSION_ALERTER_SEVERE_ONLY') !== "true";
}
/**
* Utility to determine if a version check result should be displayed
*/
export function shouldDisplayVersionResult(
result: VersionCheckResult,
enableNonSevereCheck: boolean = shouldShowNonSevereVersionCheck()
): boolean {
return result !== null && (enableNonSevereCheck || result.severe);
}
/**
* Common utility function for checking version against Hexclave API
* Used by both VersionAlerter and HexclaveCompanion components
*/
export function checkVersion(
onResult: (result: VersionCheckResult) => void,
options: VersionCheckOptions = {}
) {
const {
delay = 1000,
silentFailure = false,
errorPrefix = "Version check failed"
} = options;
// Skip check for managed hosting
if (typeof window !== "undefined" && window.location.origin === "https://app.hexclave.com") {
return () => {}; // Return cleanup function
}
let cancelled = false;
runAsynchronously(async () => {
try {
await wait(delay);
if (cancelled) return;
const res = await fetch(`https://api.hexclave.com/api/v1/check-version`, {
method: "POST",
body: JSON.stringify({
clientPackageName: packageJson.name,
clientVersion: packageJson.version,
}),
headers: {
"Content-Type": "application/json",
},
});
if (res.status !== 200) {
if (silentFailure) {
return; // Silently fail
} else {
throw new Error(`Version check API call failed with status ${res.status}: ${await res.text()}`);
}
}
const data = await res.json();
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (cancelled) return;
onResult(data.upToDate ? null : data);
} catch (e) {
if (silentFailure) {
console.warn(`${errorPrefix}:`, e);
return;
}
// Wait a little bit because the error may have been caused by a page reload
await wait(5000);
if (cancelled) return;
console.error(`${errorPrefix}`, e);
onResult({
severe: true,
error: `Error checking version, please make sure you're connected to the internet. See the console for more details. \n${e}`
});
}
});
// Return cleanup function
return () => {
cancelled = true;
};
}