@spring-systems/server 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/LICENSE +8 -0
  3. package/README.md +94 -0
  4. package/dist/api-route-handler.d.ts +49 -0
  5. package/dist/api-route-handler.js +19 -0
  6. package/dist/api-route-handler.js.map +1 -0
  7. package/dist/chunk-7IUSTA5W.js +113 -0
  8. package/dist/chunk-7IUSTA5W.js.map +1 -0
  9. package/dist/chunk-CLZU34DG.js +465 -0
  10. package/dist/chunk-CLZU34DG.js.map +1 -0
  11. package/dist/chunk-CP33WQ5Q.js +47 -0
  12. package/dist/chunk-CP33WQ5Q.js.map +1 -0
  13. package/dist/chunk-FEB3UZEG.js +407 -0
  14. package/dist/chunk-FEB3UZEG.js.map +1 -0
  15. package/dist/chunk-KA7RJCWA.js +24 -0
  16. package/dist/chunk-KA7RJCWA.js.map +1 -0
  17. package/dist/chunk-OYTV4D7E.js +159 -0
  18. package/dist/chunk-OYTV4D7E.js.map +1 -0
  19. package/dist/chunk-YV6DZVPI.js +43 -0
  20. package/dist/chunk-YV6DZVPI.js.map +1 -0
  21. package/dist/client.d.ts +6 -0
  22. package/dist/client.js +14 -0
  23. package/dist/client.js.map +1 -0
  24. package/dist/handlers/index.d.ts +81 -0
  25. package/dist/handlers/index.js +48 -0
  26. package/dist/handlers/index.js.map +1 -0
  27. package/dist/index.d.ts +10 -0
  28. package/dist/index.js +44 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/next-adapters.d.ts +25 -0
  31. package/dist/next-adapters.js +14 -0
  32. package/dist/next-adapters.js.map +1 -0
  33. package/dist/proxy-middleware.d.ts +8 -0
  34. package/dist/proxy-middleware.js +10 -0
  35. package/dist/proxy-middleware.js.map +1 -0
  36. package/dist/rate-limiter.d.ts +67 -0
  37. package/dist/rate-limiter.js +15 -0
  38. package/dist/rate-limiter.js.map +1 -0
  39. package/dist/runtime-env.d.ts +15 -0
  40. package/dist/runtime-env.js +9 -0
  41. package/dist/runtime-env.js.map +1 -0
  42. package/dist/security-headers.d.ts +8 -0
  43. package/dist/security-headers.js +11 -0
  44. package/dist/security-headers.js.map +1 -0
  45. package/package.json +114 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/proxy-middleware.ts"],"sourcesContent":["import { getFrameworkConfig } from \"@spring-systems/core/config\";\nimport { type NextRequest, NextResponse } from \"next/server.js\";\n\nimport { BASE_SECURITY_HEADER_VALUES } from \"./security-headers\";\n\nfunction toOriginSource(value: string): string[] {\n const raw = value.trim();\n if (!raw) return [];\n\n try {\n const parsed = new URL(raw);\n const out = [parsed.origin];\n\n if (parsed.protocol === \"https:\") {\n out.push(`wss://${parsed.host}`);\n } else if (parsed.protocol === \"http:\") {\n out.push(`ws://${parsed.host}`);\n }\n\n return out;\n } catch {\n return [];\n }\n}\n\nconst BLOCKED_CSP_SCHEMES = new Set([\"javascript:\", \"data:\", \"blob:\", \"vbscript:\", \"filesystem:\"]);\n\nfunction parseCspSource(token: string): string | null {\n const value = token.trim();\n if (!value) return null;\n\n // Prevent header/CSP injection via env values.\n if (/[\\s;,\\r\\n]/.test(value)) return null;\n\n // Allow safe scheme sources (e.g. https:, wss:). Block dangerous schemes\n // that enable XSS or data exfiltration when used in CSP directives.\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:$/.test(value)) {\n const lower = value.toLowerCase();\n if (BLOCKED_CSP_SCHEMES.has(lower)) return null;\n return lower;\n }\n\n try {\n const parsed = new URL(value);\n if (![\"http:\", \"https:\", \"ws:\", \"wss:\"].includes(parsed.protocol)) return null;\n if (parsed.username || parsed.password) return null;\n if (parsed.pathname !== \"/\" || parsed.search || parsed.hash) return null;\n return `${parsed.protocol}//${parsed.host}`;\n } catch {\n return null;\n }\n}\n\nfunction parseReportUri(value: string): string | null {\n const trimmed = value.trim();\n if (!trimmed) return null;\n // Block header injection characters and double-quotes (used in Reporting-Endpoints structured header).\n if (/[\\s;,\\r\\n\"]/.test(trimmed)) return null;\n try {\n const parsed = new URL(trimmed);\n if (![\"http:\", \"https:\"].includes(parsed.protocol)) return null;\n if (parsed.username || parsed.password) return null;\n return parsed.toString();\n } catch {\n return null;\n }\n}\n\nfunction parseCspList(value: string): string[] {\n const parsed = value\n .split(\",\")\n .map((s) => parseCspSource(s))\n .filter((s): s is string => !!s);\n return [...new Set(parsed)];\n}\n\nexport function proxy(req: NextRequest) {\n const url = req.nextUrl.clone();\n\n const TARGET_ENV = process.env.TARGET_ENV || \"test\";\n const isProdRuntime = TARGET_ENV === \"prod\" || process.env.NODE_ENV === \"production\";\n const isTargetProd = TARGET_ENV === \"prod\";\n\n const isLocalHost = url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\";\n\n const nonce = crypto.randomUUID().replace(/-/g, \"\");\n const allowUnsafeStyleAttr = process.env.CSP_ALLOW_UNSAFE_STYLE_ATTR === \"true\";\n const denyStyleAttr = isTargetProd && !allowUnsafeStyleAttr;\n const allowUnsafeInlineStyle = !isTargetProd;\n\n const connectHostsEnv = parseCspList(process.env.CSP_CONNECT_HOSTS || \"\");\n const apiConnectSources = toOriginSource(process.env.API_URL || \"\");\n const imgHostsEnv = parseCspList(process.env.CSP_IMG_HOSTS || \"\");\n const scriptHostsEnv = parseCspList(process.env.CSP_SCRIPT_HOSTS || \"\");\n const frameHostsEnv = parseCspList(process.env.CSP_FRAME_HOSTS || \"\");\n\n const cspConfig = getFrameworkConfig().csp;\n\n // Validate framework config CSP sources through parseCspSource to prevent injection\n const validatedConnectSources = cspConfig.thirdPartyConnectSources.map((s) => parseCspSource(s)).filter((s): s is string => !!s);\n const validatedImgSources = cspConfig.thirdPartyImageSources.map((s) => parseCspSource(s)).filter((s): s is string => !!s);\n const validatedScriptSources = cspConfig.thirdPartyScriptSources.map((s) => parseCspSource(s)).filter((s): s is string => !!s);\n const validatedFrameSources = cspConfig.thirdPartyFrameSources.map((s) => parseCspSource(s)).filter((s): s is string => !!s);\n\n const connectSrc = [\n \"'self'\",\n ...validatedConnectSources,\n ...apiConnectSources,\n ...connectHostsEnv,\n ...(!isProdRuntime ? [\"http://localhost:*\", \"http://127.0.0.1:*\", \"ws://localhost:*\", \"ws://127.0.0.1:*\"] : []),\n ].join(\" \");\n\n const imgSrc = [\"'self'\", \"data:\", \"blob:\", ...validatedImgSources, ...imgHostsEnv].join(\" \");\n\n const scriptSrcHosts = [...validatedScriptSources, ...scriptHostsEnv].join(\" \");\n const frameSrcHosts = [...validatedFrameSources, ...frameHostsEnv].join(\" \");\n\n const reportUri = parseReportUri(process.env.CSP_REPORT_URI || \"\");\n\n const cspDirectives = [\n \"default-src 'self'\",\n \"base-uri 'self'\",\n \"object-src 'none'\",\n `script-src 'self' 'nonce-${nonce}' 'strict-dynamic' ${scriptSrcHosts}`,\n `script-src-elem 'self' 'nonce-${nonce}' 'strict-dynamic' ${scriptSrcHosts}`,\n \"script-src-attr 'none'\",\n allowUnsafeInlineStyle ? \"style-src 'self' 'unsafe-inline'\" : `style-src 'self' 'nonce-${nonce}'`,\n denyStyleAttr ? \"style-src-attr 'none'\" : \"style-src-attr 'unsafe-inline'\",\n `img-src ${imgSrc}`,\n \"media-src 'self' blob: data:\",\n \"manifest-src 'self'\",\n `connect-src ${connectSrc}`,\n `frame-src ${frameSrcHosts || \"'none'\"}`,\n \"frame-ancestors 'none'\",\n \"form-action 'self'\",\n ...(isTargetProd ? [\"upgrade-insecure-requests\"] : []),\n ...(reportUri ? [`report-uri ${reportUri}`, \"report-to csp-violations\"] : []),\n ];\n const csp = cspDirectives.join(\"; \");\n\n const blockedPrefixes = getFrameworkConfig().proxy.blockedPathPrefixesInProd ?? [];\n if (isProdRuntime) {\n for (const prefix of blockedPrefixes) {\n if (url.pathname.startsWith(prefix)) {\n const res = new NextResponse(\"Not Found\", { status: 404 });\n return setSecurity(res, { isLocalHost, isTargetProd, csp, nonce, reportUri });\n }\n }\n }\n\n if (url.pathname === \"/\") {\n const dest = new URL(url.toString());\n if (!isLocalHost) dest.protocol = \"https:\";\n dest.pathname = getFrameworkConfig().app.defaultRoute;\n dest.search = \"\";\n\n const res = makeRedirect(dest, 308);\n return setSecurity(res, { isLocalHost, isTargetProd, csp, nonce, reportUri });\n }\n\n const requestHeaders = new Headers(req.headers);\n requestHeaders.set(\"x-nonce\", nonce);\n\n const res = NextResponse.next({ request: { headers: requestHeaders } });\n return setSecurity(res, { isLocalHost, isTargetProd, csp, nonce, reportUri });\n}\n\nfunction setSecurity(\n res: NextResponse,\n opts: { isLocalHost: boolean; isTargetProd: boolean; csp?: string; nonce?: string; reportUri?: string | null }\n) {\n const { isLocalHost, csp, nonce, reportUri } = opts;\n if (csp) res.headers.set(\"Content-Security-Policy\", csp);\n for (const [key, value] of Object.entries(BASE_SECURITY_HEADER_VALUES)) {\n res.headers.set(key, value);\n }\n if (opts.isTargetProd && !isLocalHost)\n res.headers.set(\"Strict-Transport-Security\", \"max-age=63072000; includeSubDomains; preload\");\n if (reportUri) res.headers.set(\"Reporting-Endpoints\", `csp-violations=\"${reportUri}\"`);\n if (nonce) res.headers.set(\"x-nonce\", nonce);\n return res;\n}\n\nfunction makeRedirect(to: URL | string, status = 308) {\n const res = new NextResponse(null, { status });\n res.headers.set(\"Location\", typeof to === \"string\" ? to : to.toString());\n return res;\n}\n\nexport const proxyConfig = {\n matcher: [\"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|api/health).*)\"],\n};\n"],"mappings":"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","names":["res"]}
@@ -0,0 +1,43 @@
1
+ // src/runtime-env-route.ts
2
+ import { getRuntimeEnvKeys } from "@spring-systems/core/config";
3
+ import { NextResponse } from "next/server.js";
4
+ async function GET() {
5
+ const isProd = (process.env.NODE_ENV || "") === "production" || (process.env.TARGET_ENV || "") === "prod";
6
+ const allowInProd = (process.env.RUNTIME_ENV_PUBLIC_IN_PROD || "").toLowerCase() === "true";
7
+ if (isProd && !allowInProd) {
8
+ return NextResponse.json({ error: "Not found" }, { status: 404 });
9
+ }
10
+ const filtered = Object.fromEntries(
11
+ getRuntimeEnvKeys().map((key) => [key, process.env[key]]).filter(([, value]) => typeof value === "string")
12
+ );
13
+ return NextResponse.json(filtered, {
14
+ status: 200,
15
+ headers: {
16
+ "Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate",
17
+ Pragma: "no-cache",
18
+ Expires: "0"
19
+ }
20
+ });
21
+ }
22
+
23
+ // src/RuntimeEnvScript.tsx
24
+ import { getRuntimeEnvKeys as getRuntimeEnvKeys2 } from "@spring-systems/core/config";
25
+ import { jsx } from "react/jsx-runtime";
26
+ function serializeForInlineScript(value) {
27
+ return JSON.stringify(value).replace(/</g, "\\u003C").replace(/>/g, "\\u003E").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
28
+ }
29
+ function RuntimeEnvScript({ nonce }) {
30
+ const runtimeEnv = {};
31
+ for (const k of getRuntimeEnvKeys2()) {
32
+ const v = process.env[k];
33
+ if (typeof v === "string") runtimeEnv[k] = v;
34
+ }
35
+ const inline = `window.__RUNTIME_ENV__ = ${serializeForInlineScript(runtimeEnv)};`;
36
+ return /* @__PURE__ */ jsx("script", { id: "runtime-env", nonce, suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: inline } });
37
+ }
38
+
39
+ export {
40
+ GET,
41
+ RuntimeEnvScript
42
+ };
43
+ //# sourceMappingURL=chunk-YV6DZVPI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime-env-route.ts","../src/RuntimeEnvScript.tsx"],"sourcesContent":["import { getRuntimeEnvKeys } from \"@spring-systems/core/config\";\nimport { NextResponse } from \"next/server.js\";\n\nexport async function GET() {\n const isProd = (process.env.NODE_ENV || \"\") === \"production\" || (process.env.TARGET_ENV || \"\") === \"prod\";\n const allowInProd = (process.env.RUNTIME_ENV_PUBLIC_IN_PROD || \"\").toLowerCase() === \"true\";\n if (isProd && !allowInProd) {\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n const filtered = Object.fromEntries(\n getRuntimeEnvKeys()\n .map((key) => [key, process.env[key]] as const)\n .filter(([, value]) => typeof value === \"string\")\n );\n\n return NextResponse.json(filtered, {\n status: 200,\n headers: {\n \"Cache-Control\": \"no-store, no-cache, must-revalidate, proxy-revalidate\",\n Pragma: \"no-cache\",\n Expires: \"0\",\n },\n });\n}\n","import { getRuntimeEnvKeys } from \"@spring-systems/core/config\";\n\nfunction serializeForInlineScript(value: unknown): string {\n return JSON.stringify(value)\n .replace(/</g, \"\\\\u003C\")\n .replace(/>/g, \"\\\\u003E\")\n .replace(/&/g, \"\\\\u0026\")\n .replace(/\\u2028/g, \"\\\\u2028\")\n .replace(/\\u2029/g, \"\\\\u2029\");\n}\n\nexport interface RuntimeEnvScriptProps {\n nonce?: string;\n}\n\nexport function RuntimeEnvScript({ nonce }: RuntimeEnvScriptProps) {\n const runtimeEnv: Record<string, string> = {};\n for (const k of getRuntimeEnvKeys()) {\n const v = process.env[k];\n if (typeof v === \"string\") runtimeEnv[k] = v;\n }\n\n const inline = `window.__RUNTIME_ENV__ = ${serializeForInlineScript(runtimeEnv)};`;\n\n return (\n <script id=\"runtime-env\" nonce={nonce} suppressHydrationWarning dangerouslySetInnerHTML={{ __html: inline }} />\n );\n}\n"],"mappings":";AAAA,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAE7B,eAAsB,MAAM;AACxB,QAAM,UAAU,QAAQ,IAAI,YAAY,QAAQ,iBAAiB,QAAQ,IAAI,cAAc,QAAQ;AACnG,QAAM,eAAe,QAAQ,IAAI,8BAA8B,IAAI,YAAY,MAAM;AACrF,MAAI,UAAU,CAAC,aAAa;AACxB,WAAO,aAAa,KAAK,EAAE,OAAO,YAAY,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACpE;AAEA,QAAM,WAAW,OAAO;AAAA,IACpB,kBAAkB,EACb,IAAI,CAAC,QAAQ,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,CAAU,EAC7C,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,OAAO,UAAU,QAAQ;AAAA,EACxD;AAEA,SAAO,aAAa,KAAK,UAAU;AAAA,IAC/B,QAAQ;AAAA,IACR,SAAS;AAAA,MACL,iBAAiB;AAAA,MACjB,QAAQ;AAAA,MACR,SAAS;AAAA,IACb;AAAA,EACJ,CAAC;AACL;;;ACxBA,SAAS,qBAAAA,0BAAyB;AAyB1B;AAvBR,SAAS,yBAAyB,OAAwB;AACtD,SAAO,KAAK,UAAU,KAAK,EACtB,QAAQ,MAAM,SAAS,EACvB,QAAQ,MAAM,SAAS,EACvB,QAAQ,MAAM,SAAS,EACvB,QAAQ,WAAW,SAAS,EAC5B,QAAQ,WAAW,SAAS;AACrC;AAMO,SAAS,iBAAiB,EAAE,MAAM,GAA0B;AAC/D,QAAM,aAAqC,CAAC;AAC5C,aAAW,KAAKA,mBAAkB,GAAG;AACjC,UAAM,IAAI,QAAQ,IAAI,CAAC;AACvB,QAAI,OAAO,MAAM,SAAU,YAAW,CAAC,IAAI;AAAA,EAC/C;AAEA,QAAM,SAAS,4BAA4B,yBAAyB,UAAU,CAAC;AAE/E,SACI,oBAAC,YAAO,IAAG,eAAc,OAAc,0BAAwB,MAAC,yBAAyB,EAAE,QAAQ,OAAO,GAAG;AAErH;","names":["getRuntimeEnvKeys"]}
@@ -0,0 +1,6 @@
1
+ export { NextUIAdapterOptions, createClientOnlyNextUIAdapter, createNextRouteAdapter } from './next-adapters.js';
2
+ import '@spring-systems/ui/adapters';
3
+
4
+ declare const SPRING_SERVER_VERSION: string;
5
+
6
+ export { SPRING_SERVER_VERSION };
package/dist/client.js ADDED
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import {
3
+ createClientOnlyNextUIAdapter,
4
+ createNextRouteAdapter
5
+ } from "./chunk-CP33WQ5Q.js";
6
+
7
+ // src/client.ts
8
+ var SPRING_SERVER_VERSION = true ? "0.8.0" : "0.1.0";
9
+ export {
10
+ SPRING_SERVER_VERSION,
11
+ createClientOnlyNextUIAdapter,
12
+ createNextRouteAdapter
13
+ };
14
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["\"use client\";\n\ndeclare const __VERSION__: string;\nexport const SPRING_SERVER_VERSION: string = typeof __VERSION__ !== \"undefined\" ? __VERSION__ : \"0.1.0\";\n\nexport { createClientOnlyNextUIAdapter, createNextRouteAdapter, type NextUIAdapterOptions } from \"./next-adapters\";\n"],"mappings":";;;;;;;AAGO,IAAM,wBAAgC,OAAqC,UAAc;","names":[]}
@@ -0,0 +1,81 @@
1
+ import { NextResponse, NextRequest } from 'next/server';
2
+ export { RateLimitEntry } from '../rate-limiter.js';
3
+
4
+ /**
5
+ * Session/cookie management for the API proxy.
6
+ *
7
+ * Handles session token extraction from cookies, secure cookie setting/clearing,
8
+ * and session expiry detection from API responses.
9
+ *
10
+ * @module handlers/auth-session
11
+ */
12
+
13
+ /** Check if a request targets localhost. */
14
+ declare function isLocalHostRequest(req: NextRequest): boolean;
15
+ /** Whether to use Secure flag on cookies (HTTPS or TARGET_ENV=prod, excluding localhost). */
16
+ declare function useSecureCookies(req: NextRequest): boolean;
17
+ /** Resolve the correct session cookie name based on runtime context. */
18
+ declare function resolveSessionCookieName(req: NextRequest): string;
19
+ /** Set the session cookie with the given token. Clears the stale variant. */
20
+ declare function setSessionCookie(res: NextResponse, req: NextRequest, token: string): void;
21
+ /** Clear all session cookies (both regular and secure variants). */
22
+ declare function clearSessionCookie(res: NextResponse, req: NextRequest): void;
23
+ /** Extract session token from request cookies (tries both cookie names). */
24
+ declare function getSessionToken(req: NextRequest): string;
25
+ /** Check if a value is a session-expired error code. */
26
+ declare function isSessionExpiredCode(value: unknown): boolean;
27
+ /** Detect if a 403 response indicates session expiry (reads response body). */
28
+ declare function shouldClearSessionFromForbidden(response: Response): Promise<boolean>;
29
+
30
+ /**
31
+ * CSRF protection and CORS header management for the API proxy.
32
+ *
33
+ * Validates request origins against configured allowed origins,
34
+ * applies CORS headers to responses, and enforces CSRF protection
35
+ * for state-changing HTTP methods.
36
+ *
37
+ * @module handlers/csrf-cors
38
+ */
39
+
40
+ /** Normalize a URL string to its origin (scheme + host + port). */
41
+ declare function normalizeOrigin(value: string): string | null;
42
+ /** Check if the request comes from the configured FRONTEND_IP. */
43
+ declare function isInternalIpAccess(req: NextRequest): boolean;
44
+ /** Resolve the allowed origin for a request (checks FRONTEND_URL and FRONTEND_IP). */
45
+ declare function resolveAllowedOrigin(req: NextRequest): string | null;
46
+ /** Check if a request should be rejected by CSRF protection. */
47
+ declare function shouldRejectByCsrfProtection(req: NextRequest, method: string, pathKey: string): boolean;
48
+ /** Apply CORS headers to a response. */
49
+ declare function applyCorsHeaders(headers: Headers, req: NextRequest, isIpAccess: boolean): void;
50
+ /** Check if CSRF exempt paths are configured (disallowed in production). */
51
+ declare function hasCsrfExemptPaths(): boolean;
52
+ /** Validate production security config. Returns error string or null. */
53
+ declare function resolveProdSecurityConfigError(): string | null;
54
+
55
+ /**
56
+ * Login rate limiting logic for the API proxy.
57
+ *
58
+ * Uses the pluggable RateLimiterAdapter from rate-limiter.ts so multi-instance
59
+ * deployments can swap in a shared-storage adapter.
60
+ *
61
+ * @module handlers/rate-limit-handler
62
+ */
63
+
64
+ interface RateLimitKeys {
65
+ pairKey: string;
66
+ accountKey: string | null;
67
+ }
68
+ /** Get client IP address from request headers or connection. */
69
+ declare function getClientAddress(request: NextRequest): string;
70
+ /** Build rate limit keys from request and username. */
71
+ declare function getLoginRateLimitKeys(request: NextRequest, username: string): RateLimitKeys;
72
+ /** Remove expired rate limit entries from adapter stores. */
73
+ declare function cleanupExpiredLoginLimits(now: number): void;
74
+ /** Get remaining block time in ms (0 = not blocked). */
75
+ declare function getRateLimitRetryAfterMs(keys: RateLimitKeys, now: number): number;
76
+ /** Record a failed login attempt for rate limiting. */
77
+ declare function registerFailedLoginAttempt(keys: RateLimitKeys, _now: number): void;
78
+ /** Clear rate limit state for given keys (after successful login). */
79
+ declare function clearLoginAttemptState(keys: RateLimitKeys): void;
80
+
81
+ export { type RateLimitKeys, applyCorsHeaders, cleanupExpiredLoginLimits, clearLoginAttemptState, clearSessionCookie, getClientAddress, getLoginRateLimitKeys, getRateLimitRetryAfterMs, getSessionToken, hasCsrfExemptPaths, isInternalIpAccess, isLocalHostRequest, isSessionExpiredCode, normalizeOrigin, registerFailedLoginAttempt, resolveAllowedOrigin, resolveProdSecurityConfigError, resolveSessionCookieName, setSessionCookie, shouldClearSessionFromForbidden, shouldRejectByCsrfProtection, useSecureCookies };
@@ -0,0 +1,48 @@
1
+ import {
2
+ applyCorsHeaders,
3
+ cleanupExpiredLoginLimits,
4
+ clearLoginAttemptState,
5
+ clearSessionCookie,
6
+ getClientAddress,
7
+ getLoginRateLimitKeys,
8
+ getRateLimitRetryAfterMs,
9
+ getSessionToken,
10
+ hasCsrfExemptPaths,
11
+ isInternalIpAccess,
12
+ isLocalHostRequest,
13
+ isSessionExpiredCode,
14
+ normalizeOrigin,
15
+ registerFailedLoginAttempt,
16
+ resolveAllowedOrigin,
17
+ resolveProdSecurityConfigError,
18
+ resolveSessionCookieName,
19
+ setSessionCookie,
20
+ shouldClearSessionFromForbidden,
21
+ shouldRejectByCsrfProtection,
22
+ useSecureCookies
23
+ } from "../chunk-FEB3UZEG.js";
24
+ import "../chunk-7IUSTA5W.js";
25
+ export {
26
+ applyCorsHeaders,
27
+ cleanupExpiredLoginLimits,
28
+ clearLoginAttemptState,
29
+ clearSessionCookie,
30
+ getClientAddress,
31
+ getLoginRateLimitKeys,
32
+ getRateLimitRetryAfterMs,
33
+ getSessionToken,
34
+ hasCsrfExemptPaths,
35
+ isInternalIpAccess,
36
+ isLocalHostRequest,
37
+ isSessionExpiredCode,
38
+ normalizeOrigin,
39
+ registerFailedLoginAttempt,
40
+ resolveAllowedOrigin,
41
+ resolveProdSecurityConfigError,
42
+ resolveSessionCookieName,
43
+ setSessionCookie,
44
+ shouldClearSessionFromForbidden,
45
+ shouldRejectByCsrfProtection,
46
+ useSecureCookies
47
+ };
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,10 @@
1
+ export { DELETE, GET, OPTIONS, PATCH, POST, PUT } from './api-route-handler.js';
2
+ export { proxy, proxyConfig } from './proxy-middleware.js';
3
+ export { RuntimeEnvScript, runtimeEnvGET } from './runtime-env.js';
4
+ export { BASE_SECURITY_HEADERS, BASE_SECURITY_HEADER_VALUES, PERMISSIONS_POLICY_VALUE } from './security-headers.js';
5
+ import 'next/server.js';
6
+ import 'react/jsx-runtime';
7
+
8
+ declare const SPRING_SERVER_VERSION: string;
9
+
10
+ export { SPRING_SERVER_VERSION };
package/dist/index.js ADDED
@@ -0,0 +1,44 @@
1
+ import {
2
+ proxy,
3
+ proxyConfig
4
+ } from "./chunk-OYTV4D7E.js";
5
+ import {
6
+ DELETE,
7
+ GET,
8
+ OPTIONS,
9
+ PATCH,
10
+ POST,
11
+ PUT
12
+ } from "./chunk-CLZU34DG.js";
13
+ import "./chunk-FEB3UZEG.js";
14
+ import {
15
+ GET as GET2,
16
+ RuntimeEnvScript
17
+ } from "./chunk-YV6DZVPI.js";
18
+ import "./chunk-7IUSTA5W.js";
19
+ import {
20
+ BASE_SECURITY_HEADERS,
21
+ BASE_SECURITY_HEADER_VALUES,
22
+ PERMISSIONS_POLICY_VALUE
23
+ } from "./chunk-KA7RJCWA.js";
24
+
25
+ // src/index.ts
26
+ import "server-only";
27
+ var SPRING_SERVER_VERSION = true ? "0.8.0" : "0.0.0-dev";
28
+ export {
29
+ BASE_SECURITY_HEADERS,
30
+ BASE_SECURITY_HEADER_VALUES,
31
+ DELETE,
32
+ GET,
33
+ OPTIONS,
34
+ PATCH,
35
+ PERMISSIONS_POLICY_VALUE,
36
+ POST,
37
+ PUT,
38
+ RuntimeEnvScript,
39
+ SPRING_SERVER_VERSION,
40
+ proxy,
41
+ proxyConfig,
42
+ GET2 as runtimeEnvGET
43
+ };
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @spring-systems/server\n// Next.js server-only code: proxy middleware, API route handler, runtime env injection.\n// Use sub-path imports: @spring-systems/server/proxy, /api-handler, /runtime-env\nimport \"server-only\";\n\ndeclare const __VERSION__: string;\nexport const SPRING_SERVER_VERSION: string = typeof __VERSION__ !== \"undefined\" ? __VERSION__ : \"0.0.0-dev\";\n\nexport { DELETE, GET, OPTIONS, PATCH, POST, PUT } from \"./api-route-handler\";\nexport { proxy, proxyConfig } from \"./proxy-middleware\";\nexport { runtimeEnvGET, RuntimeEnvScript } from \"./runtime-env\";\nexport { BASE_SECURITY_HEADER_VALUES, BASE_SECURITY_HEADERS, PERMISSIONS_POLICY_VALUE } from \"./security-headers\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAGA,OAAO;AAGA,IAAM,wBAAgC,OAAqC,UAAc;","names":[]}
@@ -0,0 +1,25 @@
1
+ import { UIAdapter, RouteAdapter } from '@spring-systems/ui/adapters';
2
+
3
+ /**
4
+ * Next.js adapter presets for RouteAdapter and UIAdapter.
5
+ * Consumer app calls these in Root.tsx / layout.tsx to register the Next.js implementations.
6
+ * @module next-adapters
7
+ */
8
+
9
+ interface NextUIAdapterOptions {
10
+ /**
11
+ * Default SSR behavior for `dynamic` when call-site does not provide `{ ssr }`.
12
+ * Defaults to `true` for backward compatibility.
13
+ */
14
+ defaultDynamicSsr?: boolean;
15
+ }
16
+ /** Creates a RouteAdapter backed by Next.js App Router hooks. */
17
+ declare function createNextRouteAdapter(): RouteAdapter;
18
+ /** Creates a UIAdapter backed by Next.js Image, Link, and dynamic imports. */
19
+ declare function createNextUIAdapter(options?: NextUIAdapterOptions): UIAdapter;
20
+ /** Creates a UIAdapter preset optimized for client-only apps (dynamic imports default to `ssr: false`). */
21
+ declare function createClientOnlyNextUIAdapter(): UIAdapter;
22
+ /** Creates a UIAdapter preset with SSR-enabled dynamic imports by default. */
23
+ declare function createSsrNextUIAdapter(): UIAdapter;
24
+
25
+ export { type NextUIAdapterOptions, createClientOnlyNextUIAdapter, createNextRouteAdapter, createNextUIAdapter, createSsrNextUIAdapter };
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import {
3
+ createClientOnlyNextUIAdapter,
4
+ createNextRouteAdapter,
5
+ createNextUIAdapter,
6
+ createSsrNextUIAdapter
7
+ } from "./chunk-CP33WQ5Q.js";
8
+ export {
9
+ createClientOnlyNextUIAdapter,
10
+ createNextRouteAdapter,
11
+ createNextUIAdapter,
12
+ createSsrNextUIAdapter
13
+ };
14
+ //# sourceMappingURL=next-adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,8 @@
1
+ import { NextRequest, NextResponse } from 'next/server.js';
2
+
3
+ declare function proxy(req: NextRequest): NextResponse<unknown>;
4
+ declare const proxyConfig: {
5
+ matcher: string[];
6
+ };
7
+
8
+ export { proxy, proxyConfig };
@@ -0,0 +1,10 @@
1
+ import {
2
+ proxy,
3
+ proxyConfig
4
+ } from "./chunk-OYTV4D7E.js";
5
+ import "./chunk-KA7RJCWA.js";
6
+ export {
7
+ proxy,
8
+ proxyConfig
9
+ };
10
+ //# sourceMappingURL=proxy-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Pluggable rate limiter for API proxy authentication.
3
+ *
4
+ * The default implementation uses in-memory Maps (suitable for single-instance deployments).
5
+ * Multi-instance deployments can replace this with a custom adapter via `setRateLimiterAdapter()`.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { setRateLimiterAdapter } from "@spring-systems/server/rate-limiter";
10
+ * import { createCustomRateLimiter } from "./my-rate-limiter";
11
+ *
12
+ * setRateLimiterAdapter(createCustomRateLimiter());
13
+ * ```
14
+ *
15
+ * @module rate-limiter
16
+ */
17
+ interface RateLimitEntry {
18
+ count: number;
19
+ windowStartedAt: number;
20
+ blockedUntil: number;
21
+ }
22
+ interface RateLimitPolicy {
23
+ windowMs: number;
24
+ blockMs: number;
25
+ maxAttemptsByIpAndAccount: number;
26
+ maxAttemptsByAccount: number;
27
+ maxKeys: number;
28
+ }
29
+ /**
30
+ * Rate limiter adapter interface. Implementations must be async-safe.
31
+ */
32
+ interface RateLimiterAdapter {
33
+ /** Get the current rate limit entry for a key, or null if no entry exists. */
34
+ get(store: "ip" | "account", key: string): RateLimitEntry | null;
35
+ /** Set/update the rate limit entry for a key. */
36
+ set(store: "ip" | "account", key: string, entry: RateLimitEntry): void;
37
+ /** Delete an entry (e.g. on successful login). */
38
+ delete(store: "ip" | "account", key: string): void;
39
+ /** Get the total number of tracked keys (for eviction logic). */
40
+ size(store: "ip" | "account"): number;
41
+ /** Clear the oldest entries when maxKeys is exceeded. */
42
+ evictOldest(store: "ip" | "account", count: number): void;
43
+ /**
44
+ * Remove expired entries for a store.
45
+ * Optional to preserve compatibility with existing custom adapters.
46
+ */
47
+ sweepExpired?(store: "ip" | "account", now: number, windowMs: number): void;
48
+ }
49
+ /** Replace the default in-memory rate limiter with a custom adapter. */
50
+ declare function setRateLimiterAdapter(custom: RateLimiterAdapter): void;
51
+ /** Get the current rate limiter adapter. */
52
+ declare function getRateLimiterAdapter(): RateLimiterAdapter;
53
+ /**
54
+ * Check if a login attempt should be rate-limited.
55
+ * @returns A reason string if blocked, or null if allowed.
56
+ */
57
+ declare function checkRateLimit(ipKey: string, accountKey: string | null, policy: RateLimitPolicy): string | null;
58
+ /**
59
+ * Record a failed login attempt.
60
+ */
61
+ declare function recordFailedAttempt(ipKey: string, accountKey: string | null, policy: RateLimitPolicy): void;
62
+ /**
63
+ * Clear rate limit entries for a key (e.g. on successful login).
64
+ */
65
+ declare function clearRateLimitEntries(ipKey: string, accountKey: string | null): void;
66
+
67
+ export { type RateLimitEntry, type RateLimitPolicy, type RateLimiterAdapter, checkRateLimit, clearRateLimitEntries, getRateLimiterAdapter, recordFailedAttempt, setRateLimiterAdapter };
@@ -0,0 +1,15 @@
1
+ import {
2
+ checkRateLimit,
3
+ clearRateLimitEntries,
4
+ getRateLimiterAdapter,
5
+ recordFailedAttempt,
6
+ setRateLimiterAdapter
7
+ } from "./chunk-7IUSTA5W.js";
8
+ export {
9
+ checkRateLimit,
10
+ clearRateLimitEntries,
11
+ getRateLimiterAdapter,
12
+ recordFailedAttempt,
13
+ setRateLimiterAdapter
14
+ };
15
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,15 @@
1
+ import { NextResponse } from 'next/server.js';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+
4
+ declare function GET(): Promise<NextResponse<{
5
+ error: string;
6
+ }> | NextResponse<{
7
+ [k: string]: string | undefined;
8
+ }>>;
9
+
10
+ interface RuntimeEnvScriptProps {
11
+ nonce?: string;
12
+ }
13
+ declare function RuntimeEnvScript({ nonce }: RuntimeEnvScriptProps): react_jsx_runtime.JSX.Element;
14
+
15
+ export { RuntimeEnvScript, type RuntimeEnvScriptProps, GET as runtimeEnvGET };
@@ -0,0 +1,9 @@
1
+ import {
2
+ GET,
3
+ RuntimeEnvScript
4
+ } from "./chunk-YV6DZVPI.js";
5
+ export {
6
+ RuntimeEnvScript,
7
+ GET as runtimeEnvGET
8
+ };
9
+ //# sourceMappingURL=runtime-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,8 @@
1
+ declare const PERMISSIONS_POLICY_VALUE = "accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), browsing-topics=()";
2
+ declare const BASE_SECURITY_HEADER_VALUES: Readonly<Record<string, string>>;
3
+ declare const BASE_SECURITY_HEADERS: {
4
+ key: string;
5
+ value: string;
6
+ }[];
7
+
8
+ export { BASE_SECURITY_HEADERS, BASE_SECURITY_HEADER_VALUES, PERMISSIONS_POLICY_VALUE };
@@ -0,0 +1,11 @@
1
+ import {
2
+ BASE_SECURITY_HEADERS,
3
+ BASE_SECURITY_HEADER_VALUES,
4
+ PERMISSIONS_POLICY_VALUE
5
+ } from "./chunk-KA7RJCWA.js";
6
+ export {
7
+ BASE_SECURITY_HEADERS,
8
+ BASE_SECURITY_HEADER_VALUES,
9
+ PERMISSIONS_POLICY_VALUE
10
+ };
11
+ //# sourceMappingURL=security-headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,114 @@
1
+ {
2
+ "name": "@spring-systems/server",
3
+ "version": "0.8.0",
4
+ "description": "Next.js server-only code for Spring Systems SPRING (proxy, API routes, runtime env)",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "LICENSE",
12
+ "CHANGELOG.md"
13
+ ],
14
+ "license": "UNLICENSED",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://martin-zadak@bitbucket.org/springsystems-projects/spring-framework-frontend.git",
18
+ "directory": "packages/server"
19
+ },
20
+ "homepage": "https://bitbucket.org/springsystems-projects/spring-framework-frontend/src/main/packages/server#readme",
21
+ "bugs": {
22
+ "url": "https://bitbucket.org/springsystems-projects/spring-framework-frontend/issues"
23
+ },
24
+ "keywords": [
25
+ "spring",
26
+ "nextjs",
27
+ "server",
28
+ "proxy",
29
+ "api-routes",
30
+ "runtime-env",
31
+ "security"
32
+ ],
33
+ "engines": {
34
+ "node": ">=22.0.0"
35
+ },
36
+ "sideEffects": false,
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "import": "./dist/index.js",
41
+ "default": "./dist/index.js"
42
+ },
43
+ "./proxy": {
44
+ "types": "./dist/proxy-middleware.d.ts",
45
+ "import": "./dist/proxy-middleware.js",
46
+ "default": "./dist/proxy-middleware.js"
47
+ },
48
+ "./api-handler": {
49
+ "types": "./dist/api-route-handler.d.ts",
50
+ "import": "./dist/api-route-handler.js",
51
+ "default": "./dist/api-route-handler.js"
52
+ },
53
+ "./runtime-env": {
54
+ "types": "./dist/runtime-env.d.ts",
55
+ "import": "./dist/runtime-env.js",
56
+ "default": "./dist/runtime-env.js"
57
+ },
58
+ "./client": {
59
+ "types": "./dist/client.d.ts",
60
+ "import": "./dist/client.js",
61
+ "default": "./dist/client.js"
62
+ },
63
+ "./adapters": {
64
+ "types": "./dist/next-adapters.d.ts",
65
+ "import": "./dist/next-adapters.js",
66
+ "default": "./dist/next-adapters.js"
67
+ },
68
+ "./rate-limiter": {
69
+ "types": "./dist/rate-limiter.d.ts",
70
+ "import": "./dist/rate-limiter.js",
71
+ "default": "./dist/rate-limiter.js"
72
+ },
73
+ "./handlers": {
74
+ "types": "./dist/handlers/index.d.ts",
75
+ "import": "./dist/handlers/index.js",
76
+ "default": "./dist/handlers/index.js"
77
+ },
78
+ "./security-headers": {
79
+ "types": "./dist/security-headers.d.ts",
80
+ "import": "./dist/security-headers.js",
81
+ "default": "./dist/security-headers.js"
82
+ }
83
+ },
84
+ "scripts": {
85
+ "build": "tsup",
86
+ "dev": "tsup --watch",
87
+ "typecheck": "tsc --noEmit",
88
+ "test": "vitest run",
89
+ "check:exports": "node scripts/check-exports.mjs",
90
+ "prepack": "pnpm run build && pnpm check:exports",
91
+ "check:circular": "madge --circular --extensions ts,tsx --ts-config ../../tsconfig.base.json ./src",
92
+ "lint": "eslint src/"
93
+ },
94
+ "peerDependencies": {
95
+ "@spring-systems/core": "^0.8.0",
96
+ "@spring-systems/ui": "^0.8.0",
97
+ "next": "^16.0.0",
98
+ "react": "^19.0.0"
99
+ },
100
+ "dependencies": {
101
+ "server-only": "^0.0.1"
102
+ },
103
+ "devDependencies": {
104
+ "@spring-systems/core": "workspace:^",
105
+ "@spring-systems/ui": "workspace:^",
106
+ "@types/react": "^19.2.14",
107
+ "@vitest/coverage-v8": "^4.0.18",
108
+ "next": "^16.1.6",
109
+ "react": "^19.2.4",
110
+ "tsup": "^8.5.1",
111
+ "typescript": "^5.9.3",
112
+ "vitest": "^4.0.18"
113
+ }
114
+ }