forked from onecli/onecli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnext.config.js
More file actions
226 lines (210 loc) · 10.8 KB
/
Copy pathnext.config.js
File metadata and controls
226 lines (210 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
import { readdirSync, readFileSync } from "node:fs";
import path from "node:path";
const isCloud = process.env.NEXT_PUBLIC_EDITION === "cloud";
const isOnpremFull = process.env.NEXT_PUBLIC_EDITION === "onprem-full";
const isOnpremSlim = process.env.NEXT_PUBLIC_EDITION === "onprem-slim";
// Build-time app version, exposed to the app as NEXT_PUBLIC_APP_VERSION (client +
// server, inlined by Next). Cloud stamps APP_VERSION (semver + short git sha, e.g.
// "1.38.0+f6cca6e5") as a build arg; OSS / self-host / local falls back to the
// monorepo root package.json version, else "dev". process.cwd() is apps/web here.
const resolveAppVersion = () => {
if (process.env.APP_VERSION) return process.env.APP_VERSION;
try {
const pkg = JSON.parse(
readFileSync(
path.join(process.cwd(), "..", "..", "package.json"),
"utf8",
),
);
return pkg.version || "dev";
} catch {
return "dev";
}
};
const appVersion = resolveAppVersion();
// Dashboard paths that cloud intentionally serves at the SAME bare URL as OSS (shared).
// Empty today: cloud namespaces every dashboard feature under /p, /org, /account, so no
// bare (dashboard) path is shared. Escape hatch if OSS ever adds a dashboard route cloud
// also wants to keep bare — add it here and it won't be 404'd.
const CLOUD_SHARED_DASHBOARD_PATHS = new Set([]);
// Bare OSS dashboard route segments, read from the filesystem at build time so new OSS
// dashboard routes are covered automatically with no list to maintain. Excludes route
// groups "(x)", private "_x", dynamic "[x]", parallel "@x", and files via a positive
// name pattern. process.cwd() is apps/web during `next dev`/`next build`.
const getOssDashboardSegments = () => {
const dir = path.join(process.cwd(), "src", "app", "(dashboard)");
try {
return readdirSync(dir, { withFileTypes: true })
.filter((e) => e.isDirectory() && /^[a-z0-9][a-z0-9-]*$/.test(e.name))
.map((e) => `/${e.name}`)
.filter((p) => !CLOUD_SHARED_DASHBOARD_PATHS.has(p));
} catch {
return [];
}
};
// All EE editions (cloud + both onprems) resolve app credentials project →
// org → env; the RSC/server-action seed (`checkAppConfigExists`) must see the
// same org tier, so the action is swapped for an org-aware variant.
const ORG_APP_CONFIG_ALIASES = {
"@/lib/actions/app-config": "@/ee/actions/app-config",
};
// The boot-policy seam, swapped per edition. OSS converts a pre-cutover
// instance's LEGACY policy into v2, runs the read-only guard
// (`services/policy-legacy-migration/` — TEMPORARY, see its README), then the
// step-5 grant conversion (`services/policy-grant-conversion/` — also
// TEMPORARY). Every EE edition swaps to a NO-OP: cloud has nothing legacy to
// convert, its fleet is grant-converted (imports convert inline via
// migrate-import), and an onprem instance in either state should surface a
// report to an operator rather than be rewritten unattended.
const POLICY_MIGRATE_ALIASES = {
"@/lib/policy-migrate": "@/ee/policy-migrate",
};
// The shared policy editor with its EE-differentiating chrome behind seams: the
// staged publish surface + directory names, the org identity picker, and the
// granular resource-scope editor. Since attach-model step 6 the editor is
// reached ONLY from the ORG policy page, so these aliases are load-bearing for
// cloud and onprem-full and inert for the flat editions (oss, onprem-slim),
// which mount no org scope and therefore never import the tree. The mapping is
// kept for the flat editions anyway: it costs nothing, and dropping it would
// silently downgrade the seams if a flat edition ever gained the org UI.
const POLICY_EDITOR_ALIASES = {
"@/lib/policy-editor/editor-chrome": "@/ee/policy-editor/editor-chrome",
"@/lib/policy-editor/identity-picker": "@/ee/policy-editor/identity-picker",
"@/lib/policy-editor/resource-scope": "@/ee/policy-editor/resource-scope",
"@/lib/policy-editor/publish-mode": "@/ee/policy-editor/publish-mode",
// The behavioral-conditions builder rides with the editor seam: every EE
// edition is entitled (onprem now ENFORCES conditions via the EE
// condition_match arm, so it must author them too); the OSS module stays
// the locked upsell card. Cloud also carries this key in CLOUD_ALIASES;
// duplicating it here is how both onprem maps get it.
"@/lib/components/condition-builder": "@/ee/components/condition-builder",
};
// Cloud edition swaps these web import paths to cloud implementations (turbopack
// resolveAlias, applied only when isCloud). This config runs in plain Node, so the
// key→value map lives here directly. The onprem-full edition selects a curated
// subset below (ONPREM_FULL_ALIASES).
const CLOUD_ALIASES = {
...ORG_APP_CONFIG_ALIASES,
...POLICY_MIGRATE_ALIASES,
...POLICY_EDITOR_ALIASES,
"@/lib/auth/auth-provider": "@/ee/auth/cognito-provider",
"@/lib/auth/auth-server": "@/ee/auth/cognito-server",
"@/lib/actions/resolve-user": "@/ee/auth/resolve-user",
"@/lib/nav-config": "@/ee/nav-config",
"@dashboard/dashboard-sidebar": "@/ee/dashboard/dashboard-sidebar",
"@dashboard/dashboard-header": "@/ee/dashboard/dashboard-header",
"@/lib/gateway-auth": "@/ee/gateway-auth",
"@/lib/auth/login-content": "@/ee/auth/login-content",
"@/lib/user-plan": "@/ee/user-plan",
"@/lib/components/request-app-slot": "@/ee/apps/request-app-slot",
"@/lib/home-redirect": "@/ee/home-redirect",
"@/lib/components/pro-app-dialog": "@/ee/apps/pro-app-dialog",
"@/lib/components/condition-builder": "@/ee/components/condition-builder",
"@/lib/dashboard/session-redirect": "@/ee/dashboard/session-redirect",
"@/lib/granular-access": "@/ee/granular-access",
"@/lib/plan-gate": "@/ee/billing/plan-gate",
// Cloud initialization (api, server actions, client)
"@/lib/init/api": "@/ee/init/api",
"@/lib/init/server": "@/ee/init/server",
"@/lib/init/client": "@/ee/init/client",
// Cloud API fetch (Bearer token auth for external api-server)
"@/lib/api-fetch": "@/ee/api-fetch",
};
// Both onprem editions inject the real cloud app definitions via an onprem init seam
// (api/server/client) so the cloud-only apps are connectable with the customer's own
// OAuth credentials (BYO), while keeping local crypto/auth (no KMS/Cognito/cloud routes).
const ONPREM_INIT_ALIASES = {
"@/lib/init/api": "@/ee/onprem/init/api",
"@/lib/init/server": "@/ee/onprem/init/server",
"@/lib/init/client": "@/ee/onprem/init/client",
};
// Both onprem editions are the fully-entitled enterprise edition: report the top
// plan (so premium/teamOnly apps + features aren't shown as locked) and get the
// granular-access policy dialogs. The backend already allows everything for onprem.
const ONPREM_ENTITLEMENT_ALIASES = {
"@/lib/user-plan": "@/ee/onprem/user-plan",
"@/lib/granular-access": CLOUD_ALIASES["@/lib/granular-access"],
};
// The onprem-full edition reuses the cloud ORG-UI implementations + the org-aware home
// redirect (org routes, nav, dashboard chrome) but keeps the OSS defaults for auth
// (local), resolve-user (its project context already works for a single org), and billing
// (none). It adds the onprem init seam (cloud app defs) + one onprem-specific module:
// api-fetch (local cookie auth + project-scoped headers, no bearer token). The cloud
// org-context helpers are imported directly by the org pages and work as-is for onprem
// (members are "owner").
const ONPREM_FULL_ALIASES = {
...ONPREM_INIT_ALIASES,
...ONPREM_ENTITLEMENT_ALIASES,
...ORG_APP_CONFIG_ALIASES,
...POLICY_MIGRATE_ALIASES,
...POLICY_EDITOR_ALIASES,
// org-UI + org-aware redirect → cloud implementations (reuse the cloud mappings above)
"@/lib/nav-config": CLOUD_ALIASES["@/lib/nav-config"],
"@dashboard/dashboard-sidebar": CLOUD_ALIASES["@dashboard/dashboard-sidebar"],
"@dashboard/dashboard-header": CLOUD_ALIASES["@dashboard/dashboard-header"],
"@/lib/dashboard/session-redirect":
CLOUD_ALIASES["@/lib/dashboard/session-redirect"],
"@/lib/home-redirect": CLOUD_ALIASES["@/lib/home-redirect"],
// onprem-specific: local cookie auth + project-scoped headers
"@/lib/api-fetch": "@/ee/onprem/api-fetch",
};
// onprem-slim keeps the flat OSS surface (local auth, OSS api-fetch) + only adds the
// onprem init seam so cloud apps are connectable via BYO.
const ONPREM_SLIM_ALIASES = {
...ONPREM_INIT_ALIASES,
...ONPREM_ENTITLEMENT_ALIASES,
...ORG_APP_CONFIG_ALIASES,
...POLICY_MIGRATE_ALIASES,
...POLICY_EDITOR_ALIASES,
};
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
poweredByHeader: false,
compress: !isCloud, // Cloud: CloudFront handles compression at the edge; OSS: Next.js compresses
serverExternalPackages: ["@onecli/db", "@1password/sdk"],
env: {
NEXT_PUBLIC_EDITION: process.env.NEXT_PUBLIC_EDITION || "oss",
// Baked in at build time (like EDITION): the slim-demo image is built with
// this set to "1", inlining the demo caps into the bundle so a runtime
// `-e NEXT_PUBLIC_ONECLI_DEMO=…` cannot lift them. Every other build leaves
// it "0" and the demo asserts are no-ops.
NEXT_PUBLIC_ONECLI_DEMO: process.env.NEXT_PUBLIC_ONECLI_DEMO || "0",
NEXT_PUBLIC_APP_VERSION: appVersion,
NEXT_PUBLIC_API_URL: process.env.API_DOMAIN
? `${isCloud && process.env.NODE_ENV !== "development" ? "https" : "http"}://${process.env.API_DOMAIN}`
: "http://localhost:10255",
NEXT_PUBLIC_GATEWAY_API_URL: process.env.GATEWAY_API_DOMAIN
? `${isCloud && process.env.NODE_ENV !== "development" ? "https" : "http"}://${process.env.GATEWAY_API_DOMAIN}`
: "http://localhost:10255",
},
turbopack: {
resolveAlias: isCloud
? CLOUD_ALIASES
: isOnpremFull
? ONPREM_FULL_ALIASES
: isOnpremSlim
? ONPREM_SLIM_ALIASES
: {},
},
// No `redirects()`: the legacy Rules page and the policyMode toggle retired
// at step 10 and used to bounce to the project policy console — which itself
// retired at attach-model step 6. There is nowhere left to send those
// bookmarks, so they 404 like any other removed route; project access is
// authored on the agent and connection pages now.
async rewrites() {
// Cloud and onprem-full ship the OSS bare dashboard routes too (they may only add
// files), but only serve them namespaced under /p, /org, /account. Shadow each bare
// path (and its subpaths) before the filesystem route matches, rewriting to Next's
// built-in not-found route ("/_not-found") so the existing app/not-found.tsx renders
// with a real 404 and the requested URL is preserved. Flat editions (oss,
// onprem-slim): no-op.
if (!isCloud && !isOnpremFull) return [];
const beforeFiles = getOssDashboardSegments().flatMap((seg) => [
{ source: seg, destination: "/_not-found" },
{ source: `${seg}/:path*`, destination: "/_not-found" },
]);
return { beforeFiles };
},
};
export default nextConfig;