@flight-framework/core 0.6.1 → 0.6.3

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.
@@ -0,0 +1,14 @@
1
+ // src/plugins/server-boundary-plugin.ts
2
+ function serverBoundaryPlugin(_options = {}) {
3
+ console.warn(
4
+ "[Flight] serverBoundaryPlugin is deprecated. Use runtime guards (assertServer, assertClient) instead."
5
+ );
6
+ return {
7
+ name: "flight:server-boundary-deprecated"
8
+ // No-op plugin - just shows warning
9
+ };
10
+ }
11
+
12
+ export { serverBoundaryPlugin };
13
+ //# sourceMappingURL=chunk-J7WEZXWH.js.map
14
+ //# sourceMappingURL=chunk-J7WEZXWH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/server-boundary-plugin.ts"],"names":[],"mappings":";AAsCO,SAAS,oBAAA,CACZ,QAAA,GAAwC,EAAC,EACnC;AACN,EAAA,OAAA,CAAQ,IAAA;AAAA,IACJ;AAAA,GAEJ;AAEA,EAAA,OAAO;AAAA,IACH,IAAA,EAAM;AAAA;AAAA,GAEV;AACJ","file":"chunk-J7WEZXWH.js","sourcesContent":["/**\r\n * @flight-framework/core - Server Boundary Plugin (DEPRECATED)\r\n * \r\n * This plugin has been deprecated due to conflicts with serverActionsPlugin.\r\n * \r\n * The intended functionality (detecting server-only imports in client bundles)\r\n * is difficult to implement correctly with Vite's plugin system because:\r\n * \r\n * 1. It conflicts with serverActionsPlugin which transforms 'use server' files\r\n * 2. The resolveId hook runs before transforms, making detection unreliable\r\n * 3. Vite 6+ has different environment APIs that need careful handling\r\n * \r\n * For now, use runtime guards instead:\r\n * \r\n * @example\r\n * ```typescript\r\n * import { assertServer } from '@flight-framework/core';\r\n * \r\n * export function getSecretData() {\r\n * assertServer('getSecretData'); // Throws if called on client\r\n * return process.env.SECRET_KEY;\r\n * }\r\n * ```\r\n * \r\n * @deprecated Use runtime guards (assertServer, assertClient) instead\r\n */\r\n\r\nimport type { Plugin } from 'vite';\r\n\r\nexport interface ServerBoundaryPluginOptions {\r\n /** @deprecated This plugin is deprecated */\r\n enabled?: boolean;\r\n}\r\n\r\n/**\r\n * @deprecated This plugin has been deprecated due to conflicts with serverActionsPlugin.\r\n * Use runtime guards (assertServer, assertClient) from '@flight-framework/core' instead.\r\n */\r\nexport function serverBoundaryPlugin(\r\n _options: ServerBoundaryPluginOptions = {}\r\n): Plugin {\r\n console.warn(\r\n '[Flight] serverBoundaryPlugin is deprecated. ' +\r\n 'Use runtime guards (assertServer, assertClient) instead.'\r\n );\r\n\r\n return {\r\n name: 'flight:server-boundary-deprecated',\r\n // No-op plugin - just shows warning\r\n };\r\n}\r\n"]}
@@ -0,0 +1,20 @@
1
+ // src/plugins/env-plugin.ts
2
+ function flightEnvPlugin(options = {}) {
3
+ const {
4
+ publicPrefix = "FLIGHT_PUBLIC_",
5
+ additionalPrefixes = ["VITE_"]
6
+ } = options;
7
+ const prefixes = [.../* @__PURE__ */ new Set([publicPrefix, ...additionalPrefixes])];
8
+ return {
9
+ name: "flight:env",
10
+ config() {
11
+ return {
12
+ envPrefix: prefixes
13
+ };
14
+ }
15
+ };
16
+ }
17
+
18
+ export { flightEnvPlugin };
19
+ //# sourceMappingURL=chunk-MFUJN7RV.js.map
20
+ //# sourceMappingURL=chunk-MFUJN7RV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/env-plugin.ts"],"names":[],"mappings":";AA8CO,SAAS,eAAA,CAAgB,OAAA,GAAkC,EAAC,EAAW;AAC1E,EAAA,MAAM;AAAA,IACF,YAAA,GAAe,gBAAA;AAAA,IACf,kBAAA,GAAqB,CAAC,OAAO;AAAA,GACjC,GAAI,OAAA;AAGJ,EAAA,MAAM,QAAA,GAAW,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,YAAA,EAAc,GAAG,kBAAkB,CAAC,CAAC,CAAA;AAEnE,EAAA,OAAO;AAAA,IACH,IAAA,EAAM,YAAA;AAAA,IACN,MAAA,GAAS;AACL,MAAA,OAAO;AAAA,QACH,SAAA,EAAW;AAAA,OACf;AAAA,IACJ;AAAA,GACJ;AACJ","file":"chunk-MFUJN7RV.js","sourcesContent":["/**\r\n * @flight-framework/core - Environment Plugin\r\n * \r\n * Simple Vite plugin to configure environment variable prefixes.\r\n * \r\n * NOTE: This is mostly a convenience wrapper around Vite's native envPrefix.\r\n * You can achieve the same by adding this to your vite.config.ts:\r\n * \r\n * envPrefix: ['VITE_', 'FLIGHT_PUBLIC_']\r\n * \r\n * Use this plugin if you want a more explicit Flight integration.\r\n * \r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { flightEnvPlugin } from '@flight-framework/core/plugins';\r\n * \r\n * export default {\r\n * plugins: [flightEnvPlugin()],\r\n * };\r\n * ```\r\n */\r\n\r\nimport type { Plugin } from 'vite';\r\n\r\nexport interface FlightEnvPluginOptions {\r\n /**\r\n * Public environment variable prefix. Variables with this prefix\r\n * are exposed to client-side code via import.meta.env.\r\n * @default 'FLIGHT_PUBLIC_'\r\n */\r\n publicPrefix?: string;\r\n\r\n /**\r\n * Additional prefixes to expose (e.g., 'VITE_' is always included).\r\n * @default ['VITE_']\r\n */\r\n additionalPrefixes?: string[];\r\n}\r\n\r\n/**\r\n * Vite plugin to configure Flight's environment variable prefixes.\r\n * \r\n * This adds 'FLIGHT_PUBLIC_' as an additional env prefix alongside 'VITE_'.\r\n * Use FLIGHT_PUBLIC_* for variables you want exposed to the browser.\r\n */\r\nexport function flightEnvPlugin(options: FlightEnvPluginOptions = {}): Plugin {\r\n const {\r\n publicPrefix = 'FLIGHT_PUBLIC_',\r\n additionalPrefixes = ['VITE_'],\r\n } = options;\r\n\r\n // Build the list of prefixes\r\n const prefixes = [...new Set([publicPrefix, ...additionalPrefixes])];\r\n\r\n return {\r\n name: 'flight:env',\r\n config() {\r\n return {\r\n envPrefix: prefixes,\r\n };\r\n },\r\n };\r\n}\r\n"]}
@@ -1,15 +1,16 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
3
  /**
4
- * @flight-framework/core - Environment Variables Plugin
4
+ * @flight-framework/core - Environment Plugin
5
5
  *
6
- * Vite plugin for environment variable protection.
7
- * OPTIONAL - use if you want build-time protection.
6
+ * Simple Vite plugin to configure environment variable prefixes.
8
7
  *
9
- * Features:
10
- * - FLIGHT_PUBLIC_* and VITE_* accessible on client
11
- * - Other vars replaced with undefined on client
12
- * - Configurable behavior (warn, error, silent)
8
+ * NOTE: This is mostly a convenience wrapper around Vite's native envPrefix.
9
+ * You can achieve the same by adding this to your vite.config.ts:
10
+ *
11
+ * envPrefix: ['VITE_', 'FLIGHT_PUBLIC_']
12
+ *
13
+ * Use this plugin if you want a more explicit Flight integration.
13
14
  *
14
15
  * @example
15
16
  * ```typescript
@@ -24,41 +25,22 @@ import { Plugin } from 'vite';
24
25
 
25
26
  interface FlightEnvPluginOptions {
26
27
  /**
27
- * Prefix for public environment variables.
28
- * Variables with this prefix will be accessible on the client.
28
+ * Public environment variable prefix. Variables with this prefix
29
+ * are exposed to client-side code via import.meta.env.
29
30
  * @default 'FLIGHT_PUBLIC_'
30
31
  */
31
32
  publicPrefix?: string;
32
33
  /**
33
- * Additional prefixes to treat as public.
34
+ * Additional prefixes to expose (e.g., 'VITE_' is always included).
34
35
  * @default ['VITE_']
35
36
  */
36
- additionalPublicPrefixes?: string[];
37
- /**
38
- * How to handle private vars accessed in client code.
39
- * - 'warn': Log warning, replace with undefined
40
- * - 'error': Throw build error
41
- * - 'silent': Replace with undefined, no warning
42
- * @default 'warn'
43
- */
44
- privateVarBehavior?: 'warn' | 'error' | 'silent';
45
- /**
46
- * Specific variables to allow (bypass prefix check).
47
- * @default ['NODE_ENV', 'MODE']
48
- */
49
- allowList?: string[];
37
+ additionalPrefixes?: string[];
50
38
  }
51
39
  /**
52
- * Vite plugin to protect environment variables.
53
- *
54
- * This plugin is OPTIONAL. Use it if you want build-time
55
- * protection for your environment variables.
40
+ * Vite plugin to configure Flight's environment variable prefixes.
56
41
  *
57
- * By default, it will:
58
- * - Allow FLIGHT_PUBLIC_* and VITE_* on client
59
- * - Allow NODE_ENV and MODE
60
- * - Replace other process.env.* with undefined on client
61
- * - Show warnings in development
42
+ * This adds 'FLIGHT_PUBLIC_' as an additional env prefix alongside 'VITE_'.
43
+ * Use FLIGHT_PUBLIC_* for variables you want exposed to the browser.
62
44
  */
63
45
  declare function flightEnvPlugin(options?: FlightEnvPluginOptions): Plugin;
64
46
 
@@ -1,3 +1,3 @@
1
- export { flightEnvPlugin } from '../chunk-RFTE6JVG.js';
1
+ export { flightEnvPlugin } from '../chunk-MFUJN7RV.js';
2
2
  //# sourceMappingURL=env-plugin.js.map
3
3
  //# sourceMappingURL=env-plugin.js.map
@@ -1,8 +1,7 @@
1
- import { Plugin } from 'vite';
2
1
  import { FlightEnvPluginOptions } from './env-plugin.js';
3
2
  export { flightEnvPlugin } from './env-plugin.js';
4
- import { ServerBoundaryPluginOptions } from './server-boundary-plugin.js';
5
- export { serverBoundaryPlugin } from './server-boundary-plugin.js';
3
+ export { ServerBoundaryPluginOptions, serverBoundaryPlugin } from './server-boundary-plugin.js';
4
+ import { Plugin } from 'vite';
6
5
 
7
6
  /**
8
7
  * @flight-framework/core - Critical CSS Plugin
@@ -127,29 +126,34 @@ interface CriticalCSSOptions {
127
126
  declare function criticalCSS(options?: CriticalCSSOptions): Plugin;
128
127
 
129
128
  /**
130
- * @flight-framework/core - Build Plugins
129
+ * @flight-framework/core - Vite Plugins
131
130
  *
132
- * Optional Vite plugins for advanced optimizations.
133
- * These plugins are opt-in and require explicit configuration.
134
- *
135
- * Flight doesn't force you to use any of these - use them if you want.
131
+ * Optional Vite plugins for Flight Framework.
132
+ * All plugins are opt-in - use only what you need.
136
133
  */
137
134
 
135
+ interface FlightPluginsOptions {
136
+ env?: FlightEnvPluginOptions;
137
+ }
138
138
  /**
139
- * Recommended plugins for most apps.
140
- * Provides sensible defaults with warnings for violations.
139
+ * Recommended Flight plugins for most projects.
140
+ * Currently only includes the env plugin (serverBoundaryPlugin is deprecated).
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * // vite.config.ts
145
+ * import { flightRecommendedPlugins } from '@flight-framework/core/plugins';
146
+ *
147
+ * export default {
148
+ * plugins: [...flightRecommendedPlugins()],
149
+ * };
150
+ * ```
141
151
  */
142
- declare function flightRecommendedPlugins(options?: {
143
- env?: FlightEnvPluginOptions;
144
- serverBoundary?: ServerBoundaryPluginOptions;
145
- }): Plugin[];
152
+ declare function flightRecommendedPlugins(options?: FlightPluginsOptions): Plugin[];
146
153
  /**
147
- * Strict mode plugins - errors instead of warnings.
148
- * Recommended for production builds.
154
+ * @deprecated Use flightRecommendedPlugins instead.
155
+ * Strict plugins are no longer needed since serverBoundaryPlugin is deprecated.
149
156
  */
150
- declare function flightStrictPlugins(options?: {
151
- env?: FlightEnvPluginOptions;
152
- serverBoundary?: ServerBoundaryPluginOptions;
153
- }): Plugin[];
157
+ declare function flightStrictPlugins(options?: FlightPluginsOptions): Plugin[];
154
158
 
155
- export { type CriticalCSSOptions, FlightEnvPluginOptions, type PreloadStrategy, ServerBoundaryPluginOptions, criticalCSS, flightRecommendedPlugins, flightStrictPlugins };
159
+ export { FlightEnvPluginOptions, type FlightPluginsOptions, criticalCSS, flightRecommendedPlugins, flightStrictPlugins };
@@ -1,7 +1,6 @@
1
- import { serverBoundaryPlugin } from '../chunk-56ZZNOJD.js';
2
- export { serverBoundaryPlugin } from '../chunk-56ZZNOJD.js';
3
- import { flightEnvPlugin } from '../chunk-RFTE6JVG.js';
4
- export { flightEnvPlugin } from '../chunk-RFTE6JVG.js';
1
+ export { serverBoundaryPlugin } from '../chunk-J7WEZXWH.js';
2
+ import { flightEnvPlugin } from '../chunk-MFUJN7RV.js';
3
+ export { flightEnvPlugin } from '../chunk-MFUJN7RV.js';
5
4
 
6
5
  // src/plugins/critical-css.ts
7
6
  function criticalCSS(options = {}) {
@@ -120,29 +119,14 @@ function matchesPattern(path, pattern) {
120
119
  }
121
120
 
122
121
  // src/plugins/index.ts
123
- function flightRecommendedPlugins(options) {
122
+ function flightRecommendedPlugins(options = {}) {
124
123
  return [
125
- flightEnvPlugin({
126
- privateVarBehavior: "warn",
127
- ...options?.env
128
- }),
129
- serverBoundaryPlugin({
130
- violationBehavior: "warn",
131
- ...options?.serverBoundary
132
- })
124
+ flightEnvPlugin(options.env)
133
125
  ];
134
126
  }
135
- function flightStrictPlugins(options) {
136
- return [
137
- flightEnvPlugin({
138
- privateVarBehavior: "error",
139
- ...options?.env
140
- }),
141
- serverBoundaryPlugin({
142
- violationBehavior: "error",
143
- ...options?.serverBoundary
144
- })
145
- ];
127
+ function flightStrictPlugins(options = {}) {
128
+ console.warn("[Flight] flightStrictPlugins is deprecated. Use flightRecommendedPlugins instead.");
129
+ return flightRecommendedPlugins(options);
146
130
  }
147
131
 
148
132
  export { criticalCSS, flightRecommendedPlugins, flightStrictPlugins };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/plugins/critical-css.ts","../../src/plugins/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * @flight-framework/core - Critical CSS Plugin\r\n *\r\n * Extract and inline critical CSS for improved Core Web Vitals.\r\n * Uses Critters under the hood for CSS extraction.\r\n *\r\n * This is an OPTIONAL plugin. Install 'critters' only if you use it.\r\n *\r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { criticalCSS } from '@flight-framework/core/plugins';\r\n *\r\n * export default defineConfig({\r\n * plugins: [\r\n * criticalCSS({\r\n * preload: 'swap',\r\n * pruneSource: false,\r\n * }),\r\n * ],\r\n * });\r\n * ```\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from 'vite';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Preload strategy for non-critical CSS.\r\n *\r\n * - 'body': Move stylesheet links to end of body\r\n * - 'media': Use media=\"print\" and swap to \"all\" on load\r\n * - 'swap': Use link rel=\"preload\" and swap to stylesheet\r\n * - 'swap-high': Like swap, with fetchpriority=\"high\"\r\n * - 'js': Load via JavaScript\r\n * - 'js-lazy': Load via JavaScript when idle\r\n * - false: Don't preload\r\n */\r\nexport type PreloadStrategy =\r\n | 'body'\r\n | 'media'\r\n | 'swap'\r\n | 'swap-high'\r\n | 'js'\r\n | 'js-lazy'\r\n | false;\r\n\r\n/**\r\n * Critical CSS plugin options.\r\n */\r\nexport interface CriticalCSSOptions {\r\n /**\r\n * Enable critical CSS extraction.\r\n * @default true in production\r\n */\r\n enabled?: boolean;\r\n\r\n /**\r\n * Strategy for loading non-critical CSS.\r\n * @default 'swap'\r\n */\r\n preload?: PreloadStrategy;\r\n\r\n /**\r\n * Remove inlined CSS rules from the source stylesheet.\r\n * Reduces duplicate CSS but may cause issues with JS frameworks.\r\n * @default false\r\n */\r\n pruneSource?: boolean;\r\n\r\n /**\r\n * Remove unused CSS selectors from critical CSS.\r\n * @default true\r\n */\r\n reduceInlineStyles?: boolean;\r\n\r\n /**\r\n * Merge adjacent inline <style> tags.\r\n * @default true\r\n */\r\n mergeStylesheets?: boolean;\r\n\r\n /**\r\n * Additional CSS selectors to always include as critical.\r\n */\r\n additionalStylesheets?: string[];\r\n\r\n /**\r\n * CSS selectors to exclude from critical extraction.\r\n */\r\n excludeSelectors?: string[];\r\n\r\n /**\r\n * Routes to include (glob patterns).\r\n * @default ['**\\/*.html']\r\n */\r\n include?: string[];\r\n\r\n /**\r\n * Routes to exclude (glob patterns).\r\n * @default ['/api/**']\r\n */\r\n exclude?: string[];\r\n\r\n /**\r\n * Inline external fonts.\r\n * @default false\r\n */\r\n inlineFonts?: boolean;\r\n\r\n /**\r\n * Preload external fonts.\r\n * @default true\r\n */\r\n preloadFonts?: boolean;\r\n\r\n /**\r\n * Maximum size of inlined CSS (in bytes).\r\n * Larger stylesheets will be loaded normally.\r\n * @default 100000 (100KB)\r\n */\r\n maxInlinedSize?: number;\r\n\r\n /**\r\n * Log extraction stats.\r\n * @default true\r\n */\r\n verbose?: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// Critters Integration\r\n// ============================================================================\r\n\r\n/**\r\n * Critters options interface (subset of full Critters options).\r\n * Full options available at: https://github.com/GoogleChromeLabs/critters\r\n */\r\ninterface CrittersOptions {\r\n preload?: PreloadStrategy;\r\n pruneSource?: boolean;\r\n reduceInlineStyles?: boolean;\r\n mergeStylesheets?: boolean;\r\n external?: boolean;\r\n inlineFonts?: boolean;\r\n preloadFonts?: boolean;\r\n additionalStylesheets?: string[];\r\n noscriptFallback?: boolean;\r\n path?: string;\r\n publicPath?: string;\r\n logLevel?: 'info' | 'warn' | 'error' | 'trace' | 'debug' | 'silent';\r\n}\r\n\r\n// ============================================================================\r\n// Vite Plugin\r\n// ============================================================================\r\n\r\n/**\r\n * Vite plugin for critical CSS extraction.\r\n *\r\n * This plugin extracts critical (above-the-fold) CSS and inlines it\r\n * in the HTML, deferring non-critical CSS for better performance.\r\n *\r\n * Requires 'critters' as a peer dependency:\r\n * ```bash\r\n * npm install critters\r\n * ```\r\n *\r\n * @param options - Plugin configuration\r\n * @returns Vite plugin\r\n */\r\nexport function criticalCSS(options: CriticalCSSOptions = {}): Plugin {\r\n const {\r\n preload = 'swap',\r\n pruneSource = false,\r\n reduceInlineStyles = true,\r\n mergeStylesheets = true,\r\n additionalStylesheets = [],\r\n inlineFonts = false,\r\n preloadFonts = true,\r\n maxInlinedSize = 100000,\r\n include = ['**/*.html'],\r\n exclude = ['/api/**'],\r\n verbose = true,\r\n } = options;\r\n\r\n let config: ResolvedConfig;\r\n let isProduction = false;\r\n let enabled = options.enabled;\r\n let critters: {\r\n process: (html: string) => Promise<string>;\r\n } | null = null;\r\n\r\n return {\r\n name: 'flight-critical-css',\r\n enforce: 'post',\r\n apply: 'build',\r\n\r\n configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n isProduction = resolvedConfig.command === 'build';\r\n\r\n // Enable by default only in production\r\n if (enabled === undefined) {\r\n enabled = isProduction;\r\n }\r\n },\r\n\r\n async buildStart() {\r\n if (!enabled) return;\r\n\r\n try {\r\n // Dynamic import of Critters (optional peer dependency)\r\n // @ts-expect-error - critters has broken type exports in its package.json\r\n const CrittersModule = await import('critters');\r\n const Critters = CrittersModule.default || CrittersModule;\r\n\r\n const crittersOptions: CrittersOptions = {\r\n preload,\r\n pruneSource,\r\n reduceInlineStyles,\r\n mergeStylesheets,\r\n inlineFonts,\r\n preloadFonts,\r\n additionalStylesheets,\r\n external: true,\r\n noscriptFallback: true,\r\n path: config.build.outDir,\r\n publicPath: config.base || '/',\r\n logLevel: verbose ? 'info' : 'silent',\r\n };\r\n\r\n critters = new Critters(crittersOptions);\r\n\r\n if (verbose) {\r\n console.log('[flight-critical-css] Critical CSS extraction enabled');\r\n }\r\n } catch (error) {\r\n console.warn(\r\n '[flight-critical-css] Critters not installed. Install with: npm install critters'\r\n );\r\n critters = null;\r\n }\r\n },\r\n\r\n async transformIndexHtml(html, ctx) {\r\n if (!enabled || !critters) {\r\n return html;\r\n }\r\n\r\n // Check if this route should be processed\r\n const path = ctx.path || '';\r\n\r\n // Check exclusions\r\n for (const pattern of exclude) {\r\n if (matchesPattern(path, pattern)) {\r\n return html;\r\n }\r\n }\r\n\r\n // Check inclusions\r\n let shouldProcess = false;\r\n for (const pattern of include) {\r\n if (matchesPattern(path, pattern)) {\r\n shouldProcess = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!shouldProcess) {\r\n return html;\r\n }\r\n\r\n try {\r\n const processedHtml = await critters.process(html);\r\n\r\n // Check if critical CSS is too large\r\n const inlineStyleMatch = processedHtml.match(/<style[^>]*>([\\s\\S]*?)<\\/style>/gi);\r\n if (inlineStyleMatch) {\r\n const totalInlineSize = inlineStyleMatch.reduce(\r\n (sum, style) => sum + style.length, 0\r\n );\r\n\r\n if (totalInlineSize > maxInlinedSize) {\r\n console.warn(\r\n `[flight-critical-css] Inline CSS (${totalInlineSize} bytes) exceeds max (${maxInlinedSize} bytes) for ${path}`\r\n );\r\n }\r\n }\r\n\r\n if (verbose) {\r\n console.log(`[flight-critical-css] Processed: ${path}`);\r\n }\r\n\r\n return processedHtml;\r\n } catch (error) {\r\n console.error(`[flight-critical-css] Error processing ${path}:`, error);\r\n return html;\r\n }\r\n },\r\n\r\n async closeBundle() {\r\n if (verbose && critters) {\r\n console.log('[flight-critical-css] Critical CSS extraction complete');\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Helper Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Simple glob pattern matching.\r\n */\r\nfunction matchesPattern(path: string, pattern: string): boolean {\r\n // Convert glob to regex\r\n const regexPattern = pattern\r\n .replace(/\\*\\*/g, '{{DOUBLE_STAR}}')\r\n .replace(/\\*/g, '[^/]*')\r\n .replace(/\\{\\{DOUBLE_STAR\\}\\}/g, '.*')\r\n .replace(/\\?/g, '.');\r\n\r\n const regex = new RegExp(`^${regexPattern}$`);\r\n return regex.test(path);\r\n}\r\n\r\n// ============================================================================\r\n// CSS Optimization Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Extract inline styles from HTML.\r\n * Utility for manual critical CSS handling.\r\n */\r\nexport function extractInlineStyles(html: string): {\r\n html: string;\r\n styles: string[];\r\n} {\r\n const styles: string[] = [];\r\n const cleanedHtml = html.replace(\r\n /<style[^>]*>([\\s\\S]*?)<\\/style>/gi,\r\n (match, content) => {\r\n styles.push(content);\r\n return '';\r\n }\r\n );\r\n\r\n return { html: cleanedHtml, styles };\r\n}\r\n\r\n/**\r\n * Merge multiple CSS strings into one.\r\n */\r\nexport function mergeCSS(styles: string[]): string {\r\n return styles\r\n .map(s => s.trim())\r\n .filter(Boolean)\r\n .join('\\n');\r\n}\r\n\r\n/**\r\n * Generate a preload link for a stylesheet.\r\n */\r\nexport function generatePreloadLink(\r\n href: string,\r\n strategy: PreloadStrategy\r\n): string {\r\n switch (strategy) {\r\n case 'swap':\r\n return `<link rel=\"preload\" href=\"${href}\" as=\"style\" onload=\"this.onload=null;this.rel='stylesheet'\">`;\r\n case 'swap-high':\r\n return `<link rel=\"preload\" href=\"${href}\" as=\"style\" fetchpriority=\"high\" onload=\"this.onload=null;this.rel='stylesheet'\">`;\r\n case 'media':\r\n return `<link rel=\"stylesheet\" href=\"${href}\" media=\"print\" onload=\"this.media='all'\">`;\r\n case 'js':\r\n return `<script>\r\n (function(){var l=document.createElement('link');l.rel='stylesheet';l.href='${href}';document.head.appendChild(l);})();\r\n </script>`;\r\n case 'js-lazy':\r\n return `<script>\r\n requestIdleCallback(function(){var l=document.createElement('link');l.rel='stylesheet';l.href='${href}';document.head.appendChild(l);});\r\n </script>`;\r\n default:\r\n return '';\r\n }\r\n}\r\n\r\n/**\r\n * Generate noscript fallback for preloaded stylesheet.\r\n */\r\nexport function generateNoscriptFallback(href: string): string {\r\n return `<noscript><link rel=\"stylesheet\" href=\"${href}\"></noscript>`;\r\n}\r\n\r\n// ============================================================================\r\n// Exports\r\n// ============================================================================\r\n\r\nexport default criticalCSS;\r\n","/**\r\n * @flight-framework/core - Build Plugins\r\n *\r\n * Optional Vite plugins for advanced optimizations.\r\n * These plugins are opt-in and require explicit configuration.\r\n * \r\n * Flight doesn't force you to use any of these - use them if you want.\r\n */\r\n\r\n// Critical CSS Plugin (existing)\r\nexport { criticalCSS } from './critical-css.js';\r\nexport type {\r\n CriticalCSSOptions,\r\n PreloadStrategy,\r\n} from './critical-css.js';\r\n\r\n// Environment Variables Plugin (NEW)\r\nexport {\r\n flightEnvPlugin,\r\n type FlightEnvPluginOptions,\r\n} from './env-plugin.js';\r\n\r\n// Server Boundary Plugin (NEW)\r\nexport {\r\n serverBoundaryPlugin,\r\n type ServerBoundaryPluginOptions,\r\n} from './server-boundary-plugin.js';\r\n\r\n// ============================================================================\r\n// Convenience Presets\r\n// ============================================================================\r\n\r\nimport type { Plugin } from 'vite';\r\nimport { flightEnvPlugin, type FlightEnvPluginOptions } from './env-plugin.js';\r\nimport { serverBoundaryPlugin, type ServerBoundaryPluginOptions } from './server-boundary-plugin.js';\r\n\r\n/**\r\n * Recommended plugins for most apps.\r\n * Provides sensible defaults with warnings for violations.\r\n */\r\nexport function flightRecommendedPlugins(options?: {\r\n env?: FlightEnvPluginOptions;\r\n serverBoundary?: ServerBoundaryPluginOptions;\r\n}): Plugin[] {\r\n return [\r\n flightEnvPlugin({\r\n privateVarBehavior: 'warn',\r\n ...options?.env,\r\n }),\r\n serverBoundaryPlugin({\r\n violationBehavior: 'warn',\r\n ...options?.serverBoundary,\r\n }),\r\n ];\r\n}\r\n\r\n/**\r\n * Strict mode plugins - errors instead of warnings.\r\n * Recommended for production builds.\r\n */\r\nexport function flightStrictPlugins(options?: {\r\n env?: FlightEnvPluginOptions;\r\n serverBoundary?: ServerBoundaryPluginOptions;\r\n}): Plugin[] {\r\n return [\r\n flightEnvPlugin({\r\n privateVarBehavior: 'error',\r\n ...options?.env,\r\n }),\r\n serverBoundaryPlugin({\r\n violationBehavior: 'error',\r\n ...options?.serverBoundary,\r\n }),\r\n ];\r\n}\r\n"]}
1
+ {"version":3,"sources":["../../src/plugins/critical-css.ts","../../src/plugins/index.ts"],"names":[],"mappings":";;;;;AA8KO,SAAS,WAAA,CAAY,OAAA,GAA8B,EAAC,EAAW;AAClE,EAAA,MAAM;AAAA,IACF,OAAA,GAAU,MAAA;AAAA,IACV,WAAA,GAAc,KAAA;AAAA,IACd,kBAAA,GAAqB,IAAA;AAAA,IACrB,gBAAA,GAAmB,IAAA;AAAA,IACnB,wBAAwB,EAAC;AAAA,IACzB,WAAA,GAAc,KAAA;AAAA,IACd,YAAA,GAAe,IAAA;AAAA,IACf,cAAA,GAAiB,GAAA;AAAA,IACjB,OAAA,GAAU,CAAC,WAAW,CAAA;AAAA,IACtB,OAAA,GAAU,CAAC,SAAS,CAAA;AAAA,IACpB,OAAA,GAAU;AAAA,GACd,GAAI,OAAA;AAEJ,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,YAAA,GAAe,KAAA;AACnB,EAAA,IAAI,UAAU,OAAA,CAAQ,OAAA;AACtB,EAAA,IAAI,QAAA,GAEO,IAAA;AAEX,EAAA,OAAO;AAAA,IACH,IAAA,EAAM,qBAAA;AAAA,IACN,OAAA,EAAS,MAAA;AAAA,IACT,KAAA,EAAO,OAAA;AAAA,IAEP,eAAe,cAAA,EAAgB;AAC3B,MAAA,MAAA,GAAS,cAAA;AACT,MAAA,YAAA,GAAe,eAAe,OAAA,KAAY,OAAA;AAG1C,MAAA,IAAI,YAAY,MAAA,EAAW;AACvB,QAAA,OAAA,GAAU,YAAA;AAAA,MACd;AAAA,IACJ,CAAA;AAAA,IAEA,MAAM,UAAA,GAAa;AACf,MAAA,IAAI,CAAC,OAAA,EAAS;AAEd,MAAA,IAAI;AAGA,QAAA,MAAM,cAAA,GAAiB,MAAM,OAAO,UAAU,CAAA;AAC9C,QAAA,MAAM,QAAA,GAAW,eAAe,OAAA,IAAW,cAAA;AAE3C,QAAA,MAAM,eAAA,GAAmC;AAAA,UACrC,OAAA;AAAA,UACA,WAAA;AAAA,UACA,kBAAA;AAAA,UACA,gBAAA;AAAA,UACA,WAAA;AAAA,UACA,YAAA;AAAA,UACA,qBAAA;AAAA,UACA,QAAA,EAAU,IAAA;AAAA,UACV,gBAAA,EAAkB,IAAA;AAAA,UAClB,IAAA,EAAM,OAAO,KAAA,CAAM,MAAA;AAAA,UACnB,UAAA,EAAY,OAAO,IAAA,IAAQ,GAAA;AAAA,UAC3B,QAAA,EAAU,UAAU,MAAA,GAAS;AAAA,SACjC;AAEA,QAAA,QAAA,GAAW,IAAI,SAAS,eAAe,CAAA;AAEvC,QAAA,IAAI,OAAA,EAAS;AACT,UAAA,OAAA,CAAQ,IAAI,uDAAuD,CAAA;AAAA,QACvE;AAAA,MACJ,SAAS,KAAA,EAAO;AACZ,QAAA,OAAA,CAAQ,IAAA;AAAA,UACJ;AAAA,SACJ;AACA,QAAA,QAAA,GAAW,IAAA;AAAA,MACf;AAAA,IACJ,CAAA;AAAA,IAEA,MAAM,kBAAA,CAAmB,IAAA,EAAM,GAAA,EAAK;AAChC,MAAA,IAAI,CAAC,OAAA,IAAW,CAAC,QAAA,EAAU;AACvB,QAAA,OAAO,IAAA;AAAA,MACX;AAGA,MAAA,MAAM,IAAA,GAAO,IAAI,IAAA,IAAQ,EAAA;AAGzB,MAAA,KAAA,MAAW,WAAW,OAAA,EAAS;AAC3B,QAAA,IAAI,cAAA,CAAe,IAAA,EAAM,OAAO,CAAA,EAAG;AAC/B,UAAA,OAAO,IAAA;AAAA,QACX;AAAA,MACJ;AAGA,MAAA,IAAI,aAAA,GAAgB,KAAA;AACpB,MAAA,KAAA,MAAW,WAAW,OAAA,EAAS;AAC3B,QAAA,IAAI,cAAA,CAAe,IAAA,EAAM,OAAO,CAAA,EAAG;AAC/B,UAAA,aAAA,GAAgB,IAAA;AAChB,UAAA;AAAA,QACJ;AAAA,MACJ;AAEA,MAAA,IAAI,CAAC,aAAA,EAAe;AAChB,QAAA,OAAO,IAAA;AAAA,MACX;AAEA,MAAA,IAAI;AACA,QAAA,MAAM,aAAA,GAAgB,MAAM,QAAA,CAAS,OAAA,CAAQ,IAAI,CAAA;AAGjD,QAAA,MAAM,gBAAA,GAAmB,aAAA,CAAc,KAAA,CAAM,mCAAmC,CAAA;AAChF,QAAA,IAAI,gBAAA,EAAkB;AAClB,UAAA,MAAM,kBAAkB,gBAAA,CAAiB,MAAA;AAAA,YACrC,CAAC,GAAA,EAAK,KAAA,KAAU,GAAA,GAAM,KAAA,CAAM,MAAA;AAAA,YAAQ;AAAA,WACxC;AAEA,UAAA,IAAI,kBAAkB,cAAA,EAAgB;AAClC,YAAA,OAAA,CAAQ,IAAA;AAAA,cACJ,CAAA,kCAAA,EAAqC,eAAe,CAAA,qBAAA,EAAwB,cAAc,eAAe,IAAI,CAAA;AAAA,aACjH;AAAA,UACJ;AAAA,QACJ;AAEA,QAAA,IAAI,OAAA,EAAS;AACT,UAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,iCAAA,EAAoC,IAAI,CAAA,CAAE,CAAA;AAAA,QAC1D;AAEA,QAAA,OAAO,aAAA;AAAA,MACX,SAAS,KAAA,EAAO;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,uCAAA,EAA0C,IAAI,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AACtE,QAAA,OAAO,IAAA;AAAA,MACX;AAAA,IACJ,CAAA;AAAA,IAEA,MAAM,WAAA,GAAc;AAChB,MAAA,IAAI,WAAW,QAAA,EAAU;AACrB,QAAA,OAAA,CAAQ,IAAI,wDAAwD,CAAA;AAAA,MACxE;AAAA,IACJ;AAAA,GACJ;AACJ;AASA,SAAS,cAAA,CAAe,MAAc,OAAA,EAA0B;AAE5D,EAAA,MAAM,eAAe,OAAA,CAChB,OAAA,CAAQ,OAAA,EAAS,iBAAiB,EAClC,OAAA,CAAQ,KAAA,EAAO,OAAO,CAAA,CACtB,QAAQ,sBAAA,EAAwB,IAAI,CAAA,CACpC,OAAA,CAAQ,OAAO,GAAG,CAAA;AAEvB,EAAA,MAAM,KAAA,GAAQ,IAAI,MAAA,CAAO,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA,CAAG,CAAA;AAC5C,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AAC1B;;;AC7RO,SAAS,wBAAA,CAAyB,OAAA,GAAgC,EAAC,EAAa;AACnF,EAAA,OAAO;AAAA,IACH,eAAA,CAAgB,QAAQ,GAAG;AAAA,GAC/B;AACJ;AAMO,SAAS,mBAAA,CAAoB,OAAA,GAAgC,EAAC,EAAa;AAC9E,EAAA,OAAA,CAAQ,KAAK,mFAAmF,CAAA;AAChG,EAAA,OAAO,yBAAyB,OAAO,CAAA;AAC3C","file":"index.js","sourcesContent":["/**\r\n * @flight-framework/core - Critical CSS Plugin\r\n *\r\n * Extract and inline critical CSS for improved Core Web Vitals.\r\n * Uses Critters under the hood for CSS extraction.\r\n *\r\n * This is an OPTIONAL plugin. Install 'critters' only if you use it.\r\n *\r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { criticalCSS } from '@flight-framework/core/plugins';\r\n *\r\n * export default defineConfig({\r\n * plugins: [\r\n * criticalCSS({\r\n * preload: 'swap',\r\n * pruneSource: false,\r\n * }),\r\n * ],\r\n * });\r\n * ```\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from 'vite';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Preload strategy for non-critical CSS.\r\n *\r\n * - 'body': Move stylesheet links to end of body\r\n * - 'media': Use media=\"print\" and swap to \"all\" on load\r\n * - 'swap': Use link rel=\"preload\" and swap to stylesheet\r\n * - 'swap-high': Like swap, with fetchpriority=\"high\"\r\n * - 'js': Load via JavaScript\r\n * - 'js-lazy': Load via JavaScript when idle\r\n * - false: Don't preload\r\n */\r\nexport type PreloadStrategy =\r\n | 'body'\r\n | 'media'\r\n | 'swap'\r\n | 'swap-high'\r\n | 'js'\r\n | 'js-lazy'\r\n | false;\r\n\r\n/**\r\n * Critical CSS plugin options.\r\n */\r\nexport interface CriticalCSSOptions {\r\n /**\r\n * Enable critical CSS extraction.\r\n * @default true in production\r\n */\r\n enabled?: boolean;\r\n\r\n /**\r\n * Strategy for loading non-critical CSS.\r\n * @default 'swap'\r\n */\r\n preload?: PreloadStrategy;\r\n\r\n /**\r\n * Remove inlined CSS rules from the source stylesheet.\r\n * Reduces duplicate CSS but may cause issues with JS frameworks.\r\n * @default false\r\n */\r\n pruneSource?: boolean;\r\n\r\n /**\r\n * Remove unused CSS selectors from critical CSS.\r\n * @default true\r\n */\r\n reduceInlineStyles?: boolean;\r\n\r\n /**\r\n * Merge adjacent inline <style> tags.\r\n * @default true\r\n */\r\n mergeStylesheets?: boolean;\r\n\r\n /**\r\n * Additional CSS selectors to always include as critical.\r\n */\r\n additionalStylesheets?: string[];\r\n\r\n /**\r\n * CSS selectors to exclude from critical extraction.\r\n */\r\n excludeSelectors?: string[];\r\n\r\n /**\r\n * Routes to include (glob patterns).\r\n * @default ['**\\/*.html']\r\n */\r\n include?: string[];\r\n\r\n /**\r\n * Routes to exclude (glob patterns).\r\n * @default ['/api/**']\r\n */\r\n exclude?: string[];\r\n\r\n /**\r\n * Inline external fonts.\r\n * @default false\r\n */\r\n inlineFonts?: boolean;\r\n\r\n /**\r\n * Preload external fonts.\r\n * @default true\r\n */\r\n preloadFonts?: boolean;\r\n\r\n /**\r\n * Maximum size of inlined CSS (in bytes).\r\n * Larger stylesheets will be loaded normally.\r\n * @default 100000 (100KB)\r\n */\r\n maxInlinedSize?: number;\r\n\r\n /**\r\n * Log extraction stats.\r\n * @default true\r\n */\r\n verbose?: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// Critters Integration\r\n// ============================================================================\r\n\r\n/**\r\n * Critters options interface (subset of full Critters options).\r\n * Full options available at: https://github.com/GoogleChromeLabs/critters\r\n */\r\ninterface CrittersOptions {\r\n preload?: PreloadStrategy;\r\n pruneSource?: boolean;\r\n reduceInlineStyles?: boolean;\r\n mergeStylesheets?: boolean;\r\n external?: boolean;\r\n inlineFonts?: boolean;\r\n preloadFonts?: boolean;\r\n additionalStylesheets?: string[];\r\n noscriptFallback?: boolean;\r\n path?: string;\r\n publicPath?: string;\r\n logLevel?: 'info' | 'warn' | 'error' | 'trace' | 'debug' | 'silent';\r\n}\r\n\r\n// ============================================================================\r\n// Vite Plugin\r\n// ============================================================================\r\n\r\n/**\r\n * Vite plugin for critical CSS extraction.\r\n *\r\n * This plugin extracts critical (above-the-fold) CSS and inlines it\r\n * in the HTML, deferring non-critical CSS for better performance.\r\n *\r\n * Requires 'critters' as a peer dependency:\r\n * ```bash\r\n * npm install critters\r\n * ```\r\n *\r\n * @param options - Plugin configuration\r\n * @returns Vite plugin\r\n */\r\nexport function criticalCSS(options: CriticalCSSOptions = {}): Plugin {\r\n const {\r\n preload = 'swap',\r\n pruneSource = false,\r\n reduceInlineStyles = true,\r\n mergeStylesheets = true,\r\n additionalStylesheets = [],\r\n inlineFonts = false,\r\n preloadFonts = true,\r\n maxInlinedSize = 100000,\r\n include = ['**/*.html'],\r\n exclude = ['/api/**'],\r\n verbose = true,\r\n } = options;\r\n\r\n let config: ResolvedConfig;\r\n let isProduction = false;\r\n let enabled = options.enabled;\r\n let critters: {\r\n process: (html: string) => Promise<string>;\r\n } | null = null;\r\n\r\n return {\r\n name: 'flight-critical-css',\r\n enforce: 'post',\r\n apply: 'build',\r\n\r\n configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n isProduction = resolvedConfig.command === 'build';\r\n\r\n // Enable by default only in production\r\n if (enabled === undefined) {\r\n enabled = isProduction;\r\n }\r\n },\r\n\r\n async buildStart() {\r\n if (!enabled) return;\r\n\r\n try {\r\n // Dynamic import of Critters (optional peer dependency)\r\n // @ts-expect-error - critters has broken type exports in its package.json\r\n const CrittersModule = await import('critters');\r\n const Critters = CrittersModule.default || CrittersModule;\r\n\r\n const crittersOptions: CrittersOptions = {\r\n preload,\r\n pruneSource,\r\n reduceInlineStyles,\r\n mergeStylesheets,\r\n inlineFonts,\r\n preloadFonts,\r\n additionalStylesheets,\r\n external: true,\r\n noscriptFallback: true,\r\n path: config.build.outDir,\r\n publicPath: config.base || '/',\r\n logLevel: verbose ? 'info' : 'silent',\r\n };\r\n\r\n critters = new Critters(crittersOptions);\r\n\r\n if (verbose) {\r\n console.log('[flight-critical-css] Critical CSS extraction enabled');\r\n }\r\n } catch (error) {\r\n console.warn(\r\n '[flight-critical-css] Critters not installed. Install with: npm install critters'\r\n );\r\n critters = null;\r\n }\r\n },\r\n\r\n async transformIndexHtml(html, ctx) {\r\n if (!enabled || !critters) {\r\n return html;\r\n }\r\n\r\n // Check if this route should be processed\r\n const path = ctx.path || '';\r\n\r\n // Check exclusions\r\n for (const pattern of exclude) {\r\n if (matchesPattern(path, pattern)) {\r\n return html;\r\n }\r\n }\r\n\r\n // Check inclusions\r\n let shouldProcess = false;\r\n for (const pattern of include) {\r\n if (matchesPattern(path, pattern)) {\r\n shouldProcess = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!shouldProcess) {\r\n return html;\r\n }\r\n\r\n try {\r\n const processedHtml = await critters.process(html);\r\n\r\n // Check if critical CSS is too large\r\n const inlineStyleMatch = processedHtml.match(/<style[^>]*>([\\s\\S]*?)<\\/style>/gi);\r\n if (inlineStyleMatch) {\r\n const totalInlineSize = inlineStyleMatch.reduce(\r\n (sum, style) => sum + style.length, 0\r\n );\r\n\r\n if (totalInlineSize > maxInlinedSize) {\r\n console.warn(\r\n `[flight-critical-css] Inline CSS (${totalInlineSize} bytes) exceeds max (${maxInlinedSize} bytes) for ${path}`\r\n );\r\n }\r\n }\r\n\r\n if (verbose) {\r\n console.log(`[flight-critical-css] Processed: ${path}`);\r\n }\r\n\r\n return processedHtml;\r\n } catch (error) {\r\n console.error(`[flight-critical-css] Error processing ${path}:`, error);\r\n return html;\r\n }\r\n },\r\n\r\n async closeBundle() {\r\n if (verbose && critters) {\r\n console.log('[flight-critical-css] Critical CSS extraction complete');\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Helper Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Simple glob pattern matching.\r\n */\r\nfunction matchesPattern(path: string, pattern: string): boolean {\r\n // Convert glob to regex\r\n const regexPattern = pattern\r\n .replace(/\\*\\*/g, '{{DOUBLE_STAR}}')\r\n .replace(/\\*/g, '[^/]*')\r\n .replace(/\\{\\{DOUBLE_STAR\\}\\}/g, '.*')\r\n .replace(/\\?/g, '.');\r\n\r\n const regex = new RegExp(`^${regexPattern}$`);\r\n return regex.test(path);\r\n}\r\n\r\n// ============================================================================\r\n// CSS Optimization Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Extract inline styles from HTML.\r\n * Utility for manual critical CSS handling.\r\n */\r\nexport function extractInlineStyles(html: string): {\r\n html: string;\r\n styles: string[];\r\n} {\r\n const styles: string[] = [];\r\n const cleanedHtml = html.replace(\r\n /<style[^>]*>([\\s\\S]*?)<\\/style>/gi,\r\n (match, content) => {\r\n styles.push(content);\r\n return '';\r\n }\r\n );\r\n\r\n return { html: cleanedHtml, styles };\r\n}\r\n\r\n/**\r\n * Merge multiple CSS strings into one.\r\n */\r\nexport function mergeCSS(styles: string[]): string {\r\n return styles\r\n .map(s => s.trim())\r\n .filter(Boolean)\r\n .join('\\n');\r\n}\r\n\r\n/**\r\n * Generate a preload link for a stylesheet.\r\n */\r\nexport function generatePreloadLink(\r\n href: string,\r\n strategy: PreloadStrategy\r\n): string {\r\n switch (strategy) {\r\n case 'swap':\r\n return `<link rel=\"preload\" href=\"${href}\" as=\"style\" onload=\"this.onload=null;this.rel='stylesheet'\">`;\r\n case 'swap-high':\r\n return `<link rel=\"preload\" href=\"${href}\" as=\"style\" fetchpriority=\"high\" onload=\"this.onload=null;this.rel='stylesheet'\">`;\r\n case 'media':\r\n return `<link rel=\"stylesheet\" href=\"${href}\" media=\"print\" onload=\"this.media='all'\">`;\r\n case 'js':\r\n return `<script>\r\n (function(){var l=document.createElement('link');l.rel='stylesheet';l.href='${href}';document.head.appendChild(l);})();\r\n </script>`;\r\n case 'js-lazy':\r\n return `<script>\r\n requestIdleCallback(function(){var l=document.createElement('link');l.rel='stylesheet';l.href='${href}';document.head.appendChild(l);});\r\n </script>`;\r\n default:\r\n return '';\r\n }\r\n}\r\n\r\n/**\r\n * Generate noscript fallback for preloaded stylesheet.\r\n */\r\nexport function generateNoscriptFallback(href: string): string {\r\n return `<noscript><link rel=\"stylesheet\" href=\"${href}\"></noscript>`;\r\n}\r\n\r\n// ============================================================================\r\n// Exports\r\n// ============================================================================\r\n\r\nexport default criticalCSS;\r\n","/**\r\n * @flight-framework/core - Vite Plugins\r\n * \r\n * Optional Vite plugins for Flight Framework.\r\n * All plugins are opt-in - use only what you need.\r\n */\r\n\r\n// Environment Variables Plugin\r\nexport { flightEnvPlugin, type FlightEnvPluginOptions } from './env-plugin.js';\r\n\r\n// Server Boundary Plugin (DEPRECATED)\r\nexport {\r\n serverBoundaryPlugin,\r\n type ServerBoundaryPluginOptions\r\n} from './server-boundary-plugin.js';\r\n\r\n// Critical CSS (existing)\r\nexport { criticalCSS } from './critical-css.js';\r\n\r\n// ============================================================================\r\n// Convenience Presets\r\n// ============================================================================\r\n\r\nimport type { Plugin } from 'vite';\r\nimport { flightEnvPlugin, type FlightEnvPluginOptions } from './env-plugin.js';\r\n\r\nexport interface FlightPluginsOptions {\r\n env?: FlightEnvPluginOptions;\r\n}\r\n\r\n/**\r\n * Recommended Flight plugins for most projects.\r\n * Currently only includes the env plugin (serverBoundaryPlugin is deprecated).\r\n * \r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { flightRecommendedPlugins } from '@flight-framework/core/plugins';\r\n * \r\n * export default {\r\n * plugins: [...flightRecommendedPlugins()],\r\n * };\r\n * ```\r\n */\r\nexport function flightRecommendedPlugins(options: FlightPluginsOptions = {}): Plugin[] {\r\n return [\r\n flightEnvPlugin(options.env),\r\n ];\r\n}\r\n\r\n/**\r\n * @deprecated Use flightRecommendedPlugins instead.\r\n * Strict plugins are no longer needed since serverBoundaryPlugin is deprecated.\r\n */\r\nexport function flightStrictPlugins(options: FlightPluginsOptions = {}): Plugin[] {\r\n console.warn('[Flight] flightStrictPlugins is deprecated. Use flightRecommendedPlugins instead.');\r\n return flightRecommendedPlugins(options);\r\n}\r\n"]}
@@ -1,67 +1,40 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
3
  /**
4
- * @flight-framework/core - Server Boundary Plugin
4
+ * @flight-framework/core - Server Boundary Plugin (DEPRECATED)
5
5
  *
6
- * Vite plugin to detect server-only code imported in client bundles.
7
- * OPTIONAL - use if you want build-time protection.
6
+ * This plugin has been deprecated due to conflicts with serverActionsPlugin.
8
7
  *
9
- * Features:
10
- * - Detects *.server.ts files imported in client code
11
- * - Detects /server/ and /api/ directory imports
12
- * - Configurable behavior (warn, error)
13
- * - Clear error messages with solutions
8
+ * The intended functionality (detecting server-only imports in client bundles)
9
+ * is difficult to implement correctly with Vite's plugin system because:
10
+ *
11
+ * 1. It conflicts with serverActionsPlugin which transforms 'use server' files
12
+ * 2. The resolveId hook runs before transforms, making detection unreliable
13
+ * 3. Vite 6+ has different environment APIs that need careful handling
14
+ *
15
+ * For now, use runtime guards instead:
14
16
  *
15
17
  * @example
16
18
  * ```typescript
17
- * // vite.config.ts
18
- * import { serverBoundaryPlugin } from '@flight-framework/core/plugins';
19
+ * import { assertServer } from '@flight-framework/core';
19
20
  *
20
- * export default {
21
- * plugins: [serverBoundaryPlugin()],
22
- * };
21
+ * export function getSecretData() {
22
+ * assertServer('getSecretData'); // Throws if called on client
23
+ * return process.env.SECRET_KEY;
24
+ * }
23
25
  * ```
26
+ *
27
+ * @deprecated Use runtime guards (assertServer, assertClient) instead
24
28
  */
25
29
 
26
30
  interface ServerBoundaryPluginOptions {
27
- /**
28
- * File patterns that are server-only.
29
- * @default ['.server.ts', '.server.tsx', '.server.js', '.server.jsx']
30
- */
31
- serverFilePatterns?: string[];
32
- /**
33
- * Directory patterns that are server-only.
34
- * @default ['/server/', '/api/']
35
- */
36
- serverDirPatterns?: string[];
37
- /**
38
- * How to handle violations.
39
- * - 'error': Build error (recommended for production)
40
- * - 'warn': Warning only (for migration)
41
- * @default 'error'
42
- */
43
- violationBehavior?: 'error' | 'warn';
44
- /**
45
- * Custom error message template.
46
- */
47
- customErrorMessage?: (module: string, importer: string) => string;
48
- /**
49
- * Files to exclude from checking (e.g., tests).
50
- * @default ['**\/*.test.*', '**\/*.spec.*']
51
- */
52
- exclude?: string[];
31
+ /** @deprecated This plugin is deprecated */
32
+ enabled?: boolean;
53
33
  }
54
34
  /**
55
- * Vite plugin to detect server-only imports in client code.
56
- *
57
- * This plugin is OPTIONAL. Use it if you want build-time
58
- * detection of server code leaking to the client.
59
- *
60
- * By default, it will:
61
- * - Block imports of *.server.ts files in client code
62
- * - Block imports from /server/ and /api/ directories
63
- * - Throw build errors with clear solutions
35
+ * @deprecated This plugin has been deprecated due to conflicts with serverActionsPlugin.
36
+ * Use runtime guards (assertServer, assertClient) from '@flight-framework/core' instead.
64
37
  */
65
- declare function serverBoundaryPlugin(options?: ServerBoundaryPluginOptions): Plugin;
38
+ declare function serverBoundaryPlugin(_options?: ServerBoundaryPluginOptions): Plugin;
66
39
 
67
40
  export { type ServerBoundaryPluginOptions, serverBoundaryPlugin };
@@ -1,3 +1,3 @@
1
- export { serverBoundaryPlugin } from '../chunk-56ZZNOJD.js';
1
+ export { serverBoundaryPlugin } from '../chunk-J7WEZXWH.js';
2
2
  //# sourceMappingURL=server-boundary-plugin.js.map
3
3
  //# sourceMappingURL=server-boundary-plugin.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flight-framework/core",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "Core primitives for Flight Framework - routing, rendering, caching, server/client boundaries",
5
5
  "keywords": [
6
6
  "flight",
@@ -1,93 +0,0 @@
1
- // src/plugins/server-boundary-plugin.ts
2
- function serverBoundaryPlugin(options = {}) {
3
- const {
4
- serverFilePatterns = [".server.ts", ".server.tsx", ".server.js", ".server.jsx"],
5
- serverDirPatterns = ["/server/", "/api/"],
6
- violationBehavior = "error",
7
- customErrorMessage,
8
- exclude = ["**/*.test.*", "**/*.spec.*", "**/node_modules/**"]
9
- } = options;
10
- const filePatterns = serverFilePatterns.map(
11
- (p) => new RegExp(p.replace(/\./g, "\\.") + "$", "i")
12
- );
13
- const dirPatterns = serverDirPatterns.map(
14
- (p) => new RegExp(p.replace(/\//g, "[\\\\/]"), "i")
15
- );
16
- function isServerOnlyModule(id) {
17
- for (const pattern of filePatterns) {
18
- if (pattern.test(id)) return true;
19
- }
20
- for (const pattern of dirPatterns) {
21
- if (pattern.test(id)) return true;
22
- }
23
- return false;
24
- }
25
- function isExcluded(id) {
26
- for (const pattern of exclude) {
27
- const regex = new RegExp(
28
- pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/\\\\]*").replace(/\./g, "\\.")
29
- );
30
- if (regex.test(id)) return true;
31
- }
32
- return false;
33
- }
34
- function createErrorMessage(module, importer) {
35
- if (customErrorMessage) {
36
- return customErrorMessage(module, importer);
37
- }
38
- return `[Flight] Cannot import server-only module in client code.
39
-
40
- Module: ${module}
41
- Imported by: ${importer}
42
-
43
- Solutions:
44
- 1. Move the import to a 'use server' file
45
- 2. Use an API route instead
46
- 3. Use dynamic import with typeof window check
47
- 4. Rename the importing file to *.server.ts
48
-
49
- Learn more: https://flight-framework.dev/docs/server-client-boundaries`;
50
- }
51
- return {
52
- name: "flight:server-boundary",
53
- enforce: "pre",
54
- resolveId(source, importer, options2) {
55
- if (options2?.ssr) return null;
56
- if (!importer) return null;
57
- if (isExcluded(importer)) return null;
58
- if (isServerOnlyModule(importer)) return null;
59
- if (isServerOnlyModule(source)) {
60
- const message = createErrorMessage(source, importer);
61
- if (violationBehavior === "error") {
62
- this.error(message);
63
- } else {
64
- this.warn(message);
65
- }
66
- }
67
- return null;
68
- },
69
- transform(code, id, options2) {
70
- if (options2?.ssr) return null;
71
- if (isExcluded(id)) return null;
72
- if (isServerOnlyModule(id)) return null;
73
- const trimmed = code.trim();
74
- if (trimmed.startsWith("'use server'") || trimmed.startsWith('"use server"')) {
75
- const message = `[Flight] 'use server' file imported in client bundle.
76
-
77
- File: ${id}
78
-
79
- This file should only run on the server. Check your import graph to find where this is imported.`;
80
- if (violationBehavior === "error") {
81
- this.error(message);
82
- } else {
83
- this.warn(message);
84
- }
85
- }
86
- return null;
87
- }
88
- };
89
- }
90
-
91
- export { serverBoundaryPlugin };
92
- //# sourceMappingURL=chunk-56ZZNOJD.js.map
93
- //# sourceMappingURL=chunk-56ZZNOJD.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/plugins/server-boundary-plugin.ts"],"names":["options"],"mappings":"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","file":"chunk-56ZZNOJD.js","sourcesContent":["/**\r\n * @flight-framework/core - Server Boundary Plugin\r\n * \r\n * Vite plugin to detect server-only code imported in client bundles.\r\n * OPTIONAL - use if you want build-time protection.\r\n * \r\n * Features:\r\n * - Detects *.server.ts files imported in client code\r\n * - Detects /server/ and /api/ directory imports\r\n * - Configurable behavior (warn, error)\r\n * - Clear error messages with solutions\r\n * \r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { serverBoundaryPlugin } from '@flight-framework/core/plugins';\r\n * \r\n * export default {\r\n * plugins: [serverBoundaryPlugin()],\r\n * };\r\n * ```\r\n */\r\n\r\nimport type { Plugin } from 'vite';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface ServerBoundaryPluginOptions {\r\n /**\r\n * File patterns that are server-only.\r\n * @default ['.server.ts', '.server.tsx', '.server.js', '.server.jsx']\r\n */\r\n serverFilePatterns?: string[];\r\n\r\n /**\r\n * Directory patterns that are server-only.\r\n * @default ['/server/', '/api/']\r\n */\r\n serverDirPatterns?: string[];\r\n\r\n /**\r\n * How to handle violations.\r\n * - 'error': Build error (recommended for production)\r\n * - 'warn': Warning only (for migration)\r\n * @default 'error'\r\n */\r\n violationBehavior?: 'error' | 'warn';\r\n\r\n /**\r\n * Custom error message template.\r\n */\r\n customErrorMessage?: (module: string, importer: string) => string;\r\n\r\n /**\r\n * Files to exclude from checking (e.g., tests).\r\n * @default ['**\\/*.test.*', '**\\/*.spec.*']\r\n */\r\n exclude?: string[];\r\n}\r\n\r\n// ============================================================================\r\n// Plugin\r\n// ============================================================================\r\n\r\n/**\r\n * Vite plugin to detect server-only imports in client code.\r\n * \r\n * This plugin is OPTIONAL. Use it if you want build-time\r\n * detection of server code leaking to the client.\r\n * \r\n * By default, it will:\r\n * - Block imports of *.server.ts files in client code\r\n * - Block imports from /server/ and /api/ directories\r\n * - Throw build errors with clear solutions\r\n */\r\nexport function serverBoundaryPlugin(\r\n options: ServerBoundaryPluginOptions = {}\r\n): Plugin {\r\n const {\r\n serverFilePatterns = ['.server.ts', '.server.tsx', '.server.js', '.server.jsx'],\r\n serverDirPatterns = ['/server/', '/api/'],\r\n violationBehavior = 'error',\r\n customErrorMessage,\r\n exclude = ['**/*.test.*', '**/*.spec.*', '**/node_modules/**'],\r\n } = options;\r\n\r\n // Build regex patterns\r\n const filePatterns = serverFilePatterns.map(p =>\r\n new RegExp(p.replace(/\\./g, '\\\\.') + '$', 'i')\r\n );\r\n const dirPatterns = serverDirPatterns.map(p =>\r\n new RegExp(p.replace(/\\//g, '[\\\\\\\\/]'), 'i')\r\n );\r\n\r\n function isServerOnlyModule(id: string): boolean {\r\n // Check file patterns\r\n for (const pattern of filePatterns) {\r\n if (pattern.test(id)) return true;\r\n }\r\n\r\n // Check directory patterns\r\n for (const pattern of dirPatterns) {\r\n if (pattern.test(id)) return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n function isExcluded(id: string): boolean {\r\n for (const pattern of exclude) {\r\n // Simple glob matching\r\n const regex = new RegExp(\r\n pattern\r\n .replace(/\\*\\*/g, '.*')\r\n .replace(/\\*/g, '[^/\\\\\\\\]*')\r\n .replace(/\\./g, '\\\\.')\r\n );\r\n if (regex.test(id)) return true;\r\n }\r\n return false;\r\n }\r\n\r\n function createErrorMessage(module: string, importer: string): string {\r\n if (customErrorMessage) {\r\n return customErrorMessage(module, importer);\r\n }\r\n\r\n return (\r\n `[Flight] Cannot import server-only module in client code.\\n\\n` +\r\n ` Module: ${module}\\n` +\r\n ` Imported by: ${importer}\\n\\n` +\r\n `Solutions:\\n` +\r\n ` 1. Move the import to a 'use server' file\\n` +\r\n ` 2. Use an API route instead\\n` +\r\n ` 3. Use dynamic import with typeof window check\\n` +\r\n ` 4. Rename the importing file to *.server.ts\\n\\n` +\r\n `Learn more: https://flight-framework.dev/docs/server-client-boundaries`\r\n );\r\n }\r\n\r\n return {\r\n name: 'flight:server-boundary',\r\n enforce: 'pre',\r\n\r\n resolveId(source, importer, options) {\r\n // Skip SSR builds - server can import anything\r\n if (options?.ssr) return null;\r\n\r\n // Need an importer to check\r\n if (!importer) return null;\r\n\r\n // Skip excluded files\r\n if (isExcluded(importer)) return null;\r\n\r\n // Skip if importer is also server-only\r\n if (isServerOnlyModule(importer)) return null;\r\n\r\n // Check if the import target is server-only\r\n // This is a simplified check - the resolved ID would be more accurate\r\n if (isServerOnlyModule(source)) {\r\n const message = createErrorMessage(source, importer);\r\n\r\n if (violationBehavior === 'error') {\r\n this.error(message);\r\n } else {\r\n this.warn(message);\r\n }\r\n }\r\n\r\n return null;\r\n },\r\n\r\n transform(code, id, options) {\r\n // Skip SSR builds\r\n if (options?.ssr) return null;\r\n\r\n // Skip excluded files\r\n if (isExcluded(id)) return null;\r\n\r\n // Skip server-only files (they shouldn't be in client bundle anyway)\r\n if (isServerOnlyModule(id)) return null;\r\n\r\n // Check for 'use server' directive at file level\r\n const trimmed = code.trim();\r\n if (trimmed.startsWith(\"'use server'\") || trimmed.startsWith('\"use server\"')) {\r\n const message =\r\n `[Flight] 'use server' file imported in client bundle.\\n\\n` +\r\n ` File: ${id}\\n\\n` +\r\n `This file should only run on the server. ` +\r\n `Check your import graph to find where this is imported.`;\r\n\r\n if (violationBehavior === 'error') {\r\n this.error(message);\r\n } else {\r\n this.warn(message);\r\n }\r\n }\r\n\r\n return null;\r\n },\r\n };\r\n}\r\n"]}
@@ -1,88 +0,0 @@
1
- // src/plugins/env-plugin.ts
2
- function flightEnvPlugin(options = {}) {
3
- const {
4
- publicPrefix = "FLIGHT_PUBLIC_",
5
- additionalPublicPrefixes = ["VITE_"],
6
- privateVarBehavior = "warn",
7
- allowList = ["NODE_ENV", "MODE"]
8
- } = options;
9
- const allPublicPrefixes = [publicPrefix, ...additionalPublicPrefixes];
10
- return {
11
- name: "flight:env",
12
- enforce: "pre",
13
- configResolved(resolvedConfig) {
14
- },
15
- config(_, { isSsrBuild }) {
16
- if (isSsrBuild) return {};
17
- const publicEnvVars = {};
18
- for (const [key, value] of Object.entries(process.env)) {
19
- if (value !== void 0 && isPublicKey(key, allPublicPrefixes, allowList)) {
20
- publicEnvVars[`process.env.${key}`] = JSON.stringify(value);
21
- }
22
- }
23
- return {
24
- define: publicEnvVars
25
- };
26
- },
27
- transform(code, id, options2) {
28
- if (options2?.ssr) return null;
29
- if (id.includes("node_modules")) return null;
30
- if (!code.includes("process.env.")) return null;
31
- const envVarPattern = /process\.env\.([A-Z_][A-Z0-9_]*)/g;
32
- let hasModifications = false;
33
- let modifiedCode = code;
34
- let match;
35
- const issues = [];
36
- while ((match = envVarPattern.exec(code)) !== null) {
37
- const varName = match[1];
38
- if (isPublicKey(varName, allPublicPrefixes, allowList)) {
39
- continue;
40
- }
41
- hasModifications = true;
42
- if (privateVarBehavior === "error") {
43
- issues.push(
44
- `Private env var "${varName}" accessed in client code.
45
- File: ${id}
46
- Use FLIGHT_PUBLIC_${varName} if this should be public.`
47
- );
48
- } else if (privateVarBehavior === "warn") {
49
- console.warn(
50
- `[Flight] Private env var "process.env.${varName}" in ${id}
51
- \u2192 Replaced with undefined for security.
52
- \u2192 Use FLIGHT_PUBLIC_${varName} if this should be public.`
53
- );
54
- }
55
- modifiedCode = modifiedCode.replace(
56
- new RegExp(`process\\.env\\.${varName}`, "g"),
57
- "undefined"
58
- );
59
- }
60
- if (issues.length > 0 && privateVarBehavior === "error") {
61
- throw new Error(
62
- `[Flight] Environment variable security violations:
63
-
64
- ${issues.join("\n\n")}`
65
- );
66
- }
67
- if (hasModifications) {
68
- return {
69
- code: modifiedCode,
70
- map: null
71
- // TODO: source map
72
- };
73
- }
74
- return null;
75
- }
76
- };
77
- }
78
- function isPublicKey(key, prefixes, allowList) {
79
- if (allowList.includes(key)) return true;
80
- for (const prefix of prefixes) {
81
- if (key.startsWith(prefix)) return true;
82
- }
83
- return false;
84
- }
85
-
86
- export { flightEnvPlugin };
87
- //# sourceMappingURL=chunk-RFTE6JVG.js.map
88
- //# sourceMappingURL=chunk-RFTE6JVG.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/plugins/env-plugin.ts"],"names":["options"],"mappings":";AA0EO,SAAS,eAAA,CAAgB,OAAA,GAAkC,EAAC,EAAW;AAC1E,EAAA,MAAM;AAAA,IACF,YAAA,GAAe,gBAAA;AAAA,IACf,wBAAA,GAA2B,CAAC,OAAO,CAAA;AAAA,IACnC,kBAAA,GAAqB,MAAA;AAAA,IACrB,SAAA,GAAY,CAAC,UAAA,EAAY,MAAM;AAAA,GACnC,GAAI,OAAA;AAEJ,EAAA,MAAM,iBAAA,GAAoB,CAAC,YAAA,EAAc,GAAG,wBAAwB,CAAA;AAGpE,EAAA,OAAO;AAAA,IACH,IAAA,EAAM,YAAA;AAAA,IACN,OAAA,EAAS,KAAA;AAAA,IAET,eAAe,cAAA,EAAgB;AAClB,IACb,CAAA;AAAA,IAEA,MAAA,CAAO,CAAA,EAAG,EAAE,UAAA,EAAW,EAAG;AAEtB,MAAA,IAAI,UAAA,SAAmB,EAAC;AAGxB,MAAA,MAAM,gBAAwC,EAAC;AAE/C,MAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA,EAAG;AACpD,QAAA,IAAI,UAAU,MAAA,IAAa,WAAA,CAAY,GAAA,EAAK,iBAAA,EAAmB,SAAS,CAAA,EAAG;AACvE,UAAA,aAAA,CAAc,eAAe,GAAG,CAAA,CAAE,CAAA,GAAI,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,QAC9D;AAAA,MACJ;AAEA,MAAA,OAAO;AAAA,QACH,MAAA,EAAQ;AAAA,OACZ;AAAA,IACJ,CAAA;AAAA,IAEA,SAAA,CAAU,IAAA,EAAM,EAAA,EAAIA,QAAAA,EAAS;AAEzB,MAAA,IAAIA,QAAAA,EAAS,KAAK,OAAO,IAAA;AAGzB,MAAA,IAAI,EAAA,CAAG,QAAA,CAAS,cAAc,CAAA,EAAG,OAAO,IAAA;AAGxC,MAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,cAAc,GAAG,OAAO,IAAA;AAG3C,MAAA,MAAM,aAAA,GAAgB,mCAAA;AACtB,MAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,MAAA,IAAI,YAAA,GAAe,IAAA;AAEnB,MAAA,IAAI,KAAA;AACJ,MAAA,MAAM,SAAmB,EAAC;AAE1B,MAAA,OAAA,CAAQ,KAAA,GAAQ,aAAA,CAAc,IAAA,CAAK,IAAI,OAAO,IAAA,EAAM;AAChD,QAAA,MAAM,OAAA,GAAU,MAAM,CAAC,CAAA;AAGvB,QAAA,IAAI,WAAA,CAAY,OAAA,EAAS,iBAAA,EAAmB,SAAS,CAAA,EAAG;AACpD,UAAA;AAAA,QACJ;AAGA,QAAA,gBAAA,GAAmB,IAAA;AAEnB,QAAA,IAAI,uBAAuB,OAAA,EAAS;AAChC,UAAA,MAAA,CAAO,IAAA;AAAA,YACH,oBAAoB,OAAO,CAAA;AAAA,QAAA,EAChB,EAAE;AAAA,oBAAA,EACU,OAAO,CAAA,0BAAA;AAAA,WAClC;AAAA,QACJ,CAAA,MAAA,IAAW,uBAAuB,MAAA,EAAQ;AACtC,UAAA,OAAA,CAAQ,IAAA;AAAA,YACJ,CAAA,sCAAA,EAAyC,OAAO,CAAA,KAAA,EAAQ,EAAE;AAAA;AAAA,2BAAA,EAEjC,OAAO,CAAA,0BAAA;AAAA,WACpC;AAAA,QACJ;AAGA,QAAA,YAAA,GAAe,YAAA,CAAa,OAAA;AAAA,UACxB,IAAI,MAAA,CAAO,CAAA,gBAAA,EAAmB,OAAO,IAAI,GAAG,CAAA;AAAA,UAC5C;AAAA,SACJ;AAAA,MACJ;AAGA,MAAA,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,IAAK,kBAAA,KAAuB,OAAA,EAAS;AACrD,QAAA,MAAM,IAAI,KAAA;AAAA,UACN,CAAA;;AAAA,EAAyD,MAAA,CAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,SAChF;AAAA,MACJ;AAEA,MAAA,IAAI,gBAAA,EAAkB;AAClB,QAAA,OAAO;AAAA,UACH,IAAA,EAAM,YAAA;AAAA,UACN,GAAA,EAAK;AAAA;AAAA,SACT;AAAA,MACJ;AAEA,MAAA,OAAO,IAAA;AAAA,IACX;AAAA,GACJ;AACJ;AAMA,SAAS,WAAA,CACL,GAAA,EACA,QAAA,EACA,SAAA,EACO;AAEP,EAAA,IAAI,SAAA,CAAU,QAAA,CAAS,GAAG,CAAA,EAAG,OAAO,IAAA;AAGpC,EAAA,KAAA,MAAW,UAAU,QAAA,EAAU;AAC3B,IAAA,IAAI,GAAA,CAAI,UAAA,CAAW,MAAM,CAAA,EAAG,OAAO,IAAA;AAAA,EACvC;AAEA,EAAA,OAAO,KAAA;AACX","file":"chunk-RFTE6JVG.js","sourcesContent":["/**\r\n * @flight-framework/core - Environment Variables Plugin\r\n * \r\n * Vite plugin for environment variable protection.\r\n * OPTIONAL - use if you want build-time protection.\r\n * \r\n * Features:\r\n * - FLIGHT_PUBLIC_* and VITE_* accessible on client\r\n * - Other vars replaced with undefined on client\r\n * - Configurable behavior (warn, error, silent)\r\n * \r\n * @example\r\n * ```typescript\r\n * // vite.config.ts\r\n * import { flightEnvPlugin } from '@flight-framework/core/plugins';\r\n * \r\n * export default {\r\n * plugins: [flightEnvPlugin()],\r\n * };\r\n * ```\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from 'vite';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface FlightEnvPluginOptions {\r\n /**\r\n * Prefix for public environment variables.\r\n * Variables with this prefix will be accessible on the client.\r\n * @default 'FLIGHT_PUBLIC_'\r\n */\r\n publicPrefix?: string;\r\n\r\n /**\r\n * Additional prefixes to treat as public.\r\n * @default ['VITE_']\r\n */\r\n additionalPublicPrefixes?: string[];\r\n\r\n /**\r\n * How to handle private vars accessed in client code.\r\n * - 'warn': Log warning, replace with undefined\r\n * - 'error': Throw build error\r\n * - 'silent': Replace with undefined, no warning\r\n * @default 'warn'\r\n */\r\n privateVarBehavior?: 'warn' | 'error' | 'silent';\r\n\r\n /**\r\n * Specific variables to allow (bypass prefix check).\r\n * @default ['NODE_ENV', 'MODE']\r\n */\r\n allowList?: string[];\r\n}\r\n\r\n// ============================================================================\r\n// Plugin\r\n// ============================================================================\r\n\r\n/**\r\n * Vite plugin to protect environment variables.\r\n * \r\n * This plugin is OPTIONAL. Use it if you want build-time\r\n * protection for your environment variables.\r\n * \r\n * By default, it will:\r\n * - Allow FLIGHT_PUBLIC_* and VITE_* on client\r\n * - Allow NODE_ENV and MODE\r\n * - Replace other process.env.* with undefined on client\r\n * - Show warnings in development\r\n */\r\nexport function flightEnvPlugin(options: FlightEnvPluginOptions = {}): Plugin {\r\n const {\r\n publicPrefix = 'FLIGHT_PUBLIC_',\r\n additionalPublicPrefixes = ['VITE_'],\r\n privateVarBehavior = 'warn',\r\n allowList = ['NODE_ENV', 'MODE'],\r\n } = options;\r\n\r\n const allPublicPrefixes = [publicPrefix, ...additionalPublicPrefixes];\r\n let config: ResolvedConfig;\r\n\r\n return {\r\n name: 'flight:env',\r\n enforce: 'pre',\r\n\r\n configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n },\r\n\r\n config(_, { isSsrBuild }) {\r\n // For SSR builds, don't modify anything\r\n if (isSsrBuild) return {};\r\n\r\n // Collect public environment variables\r\n const publicEnvVars: Record<string, string> = {};\r\n\r\n for (const [key, value] of Object.entries(process.env)) {\r\n if (value !== undefined && isPublicKey(key, allPublicPrefixes, allowList)) {\r\n publicEnvVars[`process.env.${key}`] = JSON.stringify(value);\r\n }\r\n }\r\n\r\n return {\r\n define: publicEnvVars,\r\n };\r\n },\r\n\r\n transform(code, id, options) {\r\n // Skip SSR builds - server can access everything\r\n if (options?.ssr) return null;\r\n\r\n // Skip node_modules\r\n if (id.includes('node_modules')) return null;\r\n\r\n // Skip if no process.env references\r\n if (!code.includes('process.env.')) return null;\r\n\r\n // Find all process.env.VARIABLE_NAME patterns\r\n const envVarPattern = /process\\.env\\.([A-Z_][A-Z0-9_]*)/g;\r\n let hasModifications = false;\r\n let modifiedCode = code;\r\n\r\n let match;\r\n const issues: string[] = [];\r\n\r\n while ((match = envVarPattern.exec(code)) !== null) {\r\n const varName = match[1];\r\n\r\n // Skip public vars\r\n if (isPublicKey(varName, allPublicPrefixes, allowList)) {\r\n continue;\r\n }\r\n\r\n // Private var accessed in client code\r\n hasModifications = true;\r\n\r\n if (privateVarBehavior === 'error') {\r\n issues.push(\r\n `Private env var \"${varName}\" accessed in client code.\\n` +\r\n ` File: ${id}\\n` +\r\n ` Use FLIGHT_PUBLIC_${varName} if this should be public.`\r\n );\r\n } else if (privateVarBehavior === 'warn') {\r\n console.warn(\r\n `[Flight] Private env var \"process.env.${varName}\" in ${id}\\n` +\r\n ` → Replaced with undefined for security.\\n` +\r\n ` → Use FLIGHT_PUBLIC_${varName} if this should be public.`\r\n );\r\n }\r\n\r\n // Replace with undefined\r\n modifiedCode = modifiedCode.replace(\r\n new RegExp(`process\\\\.env\\\\.${varName}`, 'g'),\r\n 'undefined'\r\n );\r\n }\r\n\r\n // Throw if using error mode\r\n if (issues.length > 0 && privateVarBehavior === 'error') {\r\n throw new Error(\r\n `[Flight] Environment variable security violations:\\n\\n${issues.join('\\n\\n')}`\r\n );\r\n }\r\n\r\n if (hasModifications) {\r\n return {\r\n code: modifiedCode,\r\n map: null, // TODO: source map\r\n };\r\n }\r\n\r\n return null;\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\nfunction isPublicKey(\r\n key: string,\r\n prefixes: string[],\r\n allowList: string[]\r\n): boolean {\r\n // Check allow list\r\n if (allowList.includes(key)) return true;\r\n\r\n // Check prefixes\r\n for (const prefix of prefixes) {\r\n if (key.startsWith(prefix)) return true;\r\n }\r\n\r\n return false;\r\n}\r\n"]}