mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
## What Ground-work so the admin portal can build for the **SaaS flavor** alongside self-hosted, using the editor's existing **build-time file-override** mechanism — no runtime flavor flags. This PR demonstrates SaaS end-to-end (single-login + Usage page loading via the inherited Supabase session) without changing self-hosted behaviour. This is intentionally scoped as foundations, not the whole feature. ## How **Build hook** - `tsconfig.saas.vite.json`: `@portal/*` now cascades (`src/saas/portal/*` → `src/portal/*`); added `@portalCore/*` for the explicit base path. - New `src/portal-saas/` layer (sibling of `src/portal`) holds SaaS-only overrides, so `@app/*` resolves only editor layers and `@portal/*` only portal layers. Self-hosted builds never import it (tree-shaken). **Seams live in the api-client + composition layers — never in page components** - `saasApiBase` — base URL source (self-hosted: `VITE_SAAS_API_URL`; SaaS reuses the single `VITE_API_BASE_URL` backend). - `portalSaasSession` — flavor-agnostic token from the shared Supabase client. - `PortalAuthBoundary` — self-hosted: Spring `AuthProvider` + `AuthGate`; SaaS: Supabase `AuthProvider` + session-only gate (inherits the SaaS session, so no second login). **Link concept pulled out of the Usage page (one clean cut)** - `Usage` is now a link-free wallet renderer with generic `onWalletLoaded` / `onReauth` callbacks; it always loads the wallet and has zero flavor awareness. - `PortalBillingGate` is the single flavor seam: self-hosted gates on link (prompt when unlinked; wires the callbacks onto link/tier + re-auth), SaaS is a passthrough that renders `Usage` directly. - Keeps the flavor switch out of the page entirely (no per-flavor code in `Usage`). ## Testing Green locally and in CI (CI runs the umbrella `task frontend:check:all`): - `task frontend:typecheck:all` — clean across all 7 build variants - `task frontend:test` — vitest suites pass (portal + saas cover this change; 146 tests) - `task frontend:build:saas` and `task frontend:build:proprietary` — both green - `task frontend:lint` and `task frontend:format:check` — clean ## Also in this PR (added after the initial foundations) - **Tier from wallet + full link-layer excision on SaaS.** `TierContext` no longer reads `LinkContext` (via a `usePlanTier` seam: self-hosted from link state, SaaS from `wallet.status`), and the SaaS `PortalProviders` drops `LinkProvider` / `AccountLinkProvider` / `LinkModalHost` entirely — the link machinery is *absent* from the SaaS bundle, not mounted-but-inert. ## Deliberately out of scope (follow-ups) - SaaS-only read-only "connected servers" settings view. - Shared wallet source so the SaaS tier badge and the Usage page don't both fetch `/payg/wallet` (harmless double-fetch today).
152 lines
3.9 KiB
TypeScript
152 lines
3.9 KiB
TypeScript
import { defineConfig } from "vitest/config";
|
|
import react from "@vitejs/plugin-react-swc";
|
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
export default defineConfig({
|
|
test: {
|
|
globals: true,
|
|
environment: "jsdom",
|
|
setupFiles: ["./src/core/setupTests.ts"],
|
|
css: false,
|
|
exclude: [
|
|
"node_modules/",
|
|
"src/**/*.spec.ts", // Exclude Playwright E2E tests
|
|
"src/tests/test-fixtures/**",
|
|
],
|
|
testTimeout: 10000,
|
|
hookTimeout: 10000,
|
|
coverage: {
|
|
reporter: ["text", "json", "html"],
|
|
exclude: [
|
|
"node_modules/",
|
|
"src/core/setupTests.ts",
|
|
"src/proprietary/setupTests.ts",
|
|
"src/saas/setupTests.ts",
|
|
"**/*.d.ts",
|
|
"src/tests/test-fixtures/**",
|
|
"src/**/*.spec.ts",
|
|
],
|
|
},
|
|
projects: [
|
|
{
|
|
test: {
|
|
name: "core",
|
|
include: ["src/core/**/*.test.{ts,tsx}"],
|
|
environment: "jsdom",
|
|
globals: true,
|
|
setupFiles: ["./src/core/setupTests.ts"],
|
|
},
|
|
plugins: [
|
|
react(),
|
|
tsconfigPaths({
|
|
projects: ["./tsconfig.core.vite.json"],
|
|
}),
|
|
],
|
|
esbuild: {
|
|
target: "es2020",
|
|
},
|
|
},
|
|
{
|
|
test: {
|
|
name: "portal",
|
|
include: ["src/portal/**/*.test.{ts,tsx}"],
|
|
environment: "jsdom",
|
|
globals: true,
|
|
setupFiles: ["./src/portal/setupTests.ts"],
|
|
},
|
|
plugins: [
|
|
react(),
|
|
tsconfigPaths({
|
|
// Broad project so @app/@portal resolve in every editor file the
|
|
// portal tests pull in (core/ui, core, ...).
|
|
projects: ["./tsconfig.portal.vite.json"],
|
|
}),
|
|
],
|
|
esbuild: {
|
|
target: "es2020",
|
|
},
|
|
},
|
|
{
|
|
test: {
|
|
name: "proprietary",
|
|
include: ["src/proprietary/**/*.test.{ts,tsx}"],
|
|
environment: "jsdom",
|
|
globals: true,
|
|
setupFiles: ["./src/core/setupTests.ts"],
|
|
},
|
|
plugins: [
|
|
react(),
|
|
tsconfigPaths({
|
|
projects: ["./tsconfig.proprietary.vite.json"],
|
|
}),
|
|
],
|
|
esbuild: {
|
|
target: "es2020",
|
|
},
|
|
},
|
|
{
|
|
test: {
|
|
name: "desktop",
|
|
include: ["src/desktop/**/*.test.{ts,tsx}"],
|
|
environment: "jsdom",
|
|
globals: true,
|
|
setupFiles: ["./src/core/setupTests.ts"],
|
|
},
|
|
plugins: [
|
|
react(),
|
|
tsconfigPaths({
|
|
projects: ["./tsconfig.desktop.vite.json"],
|
|
}),
|
|
],
|
|
esbuild: {
|
|
target: "es2020",
|
|
},
|
|
},
|
|
{
|
|
test: {
|
|
name: "saas",
|
|
// src/saas = editor-saas layer; src/portal-saas = the portal's saas
|
|
// overrides (sibling to src/portal). Both build under the saas flavor,
|
|
// so both resolve @portal via the saas cascade (tsconfig.saas.vite.json).
|
|
include: [
|
|
"src/saas/**/*.test.{ts,tsx}",
|
|
"src/portal-saas/**/*.test.{ts,tsx}",
|
|
],
|
|
environment: "jsdom",
|
|
globals: true,
|
|
setupFiles: ["./src/saas/setupTests.ts"],
|
|
},
|
|
plugins: [
|
|
react(),
|
|
tsconfigPaths({
|
|
projects: ["./tsconfig.saas.vite.json"],
|
|
}),
|
|
],
|
|
esbuild: {
|
|
target: "es2020",
|
|
},
|
|
},
|
|
{
|
|
test: {
|
|
name: "prototypes",
|
|
include: ["src/prototypes/**/*.test.{ts,tsx}"],
|
|
environment: "jsdom",
|
|
globals: true,
|
|
setupFiles: ["./src/core/setupTests.ts"],
|
|
},
|
|
plugins: [
|
|
react(),
|
|
tsconfigPaths({
|
|
projects: ["./tsconfig.prototypes.vite.json"],
|
|
}),
|
|
],
|
|
esbuild: {
|
|
target: "es2020",
|
|
},
|
|
},
|
|
],
|
|
},
|
|
esbuild: {
|
|
target: "es2020",
|
|
},
|
|
});
|