@flight-framework/core 0.6.1 → 0.6.2
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.
- package/dist/{chunk-56ZZNOJD.js → chunk-NU3HX5T7.js} +23 -36
- package/dist/chunk-NU3HX5T7.js.map +1 -0
- package/dist/plugins/index.js +2 -2
- package/dist/plugins/server-boundary-plugin.d.ts +11 -27
- package/dist/plugins/server-boundary-plugin.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-56ZZNOJD.js.map +0 -1
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
function serverBoundaryPlugin(options = {}) {
|
|
3
3
|
const {
|
|
4
4
|
serverFilePatterns = [".server.ts", ".server.tsx", ".server.js", ".server.jsx"],
|
|
5
|
-
serverDirPatterns = ["/server/"
|
|
6
|
-
violationBehavior = "
|
|
5
|
+
serverDirPatterns = ["/server/"],
|
|
6
|
+
violationBehavior = "warn",
|
|
7
7
|
customErrorMessage,
|
|
8
|
-
exclude = [
|
|
8
|
+
exclude = [],
|
|
9
|
+
skipServerActions = true
|
|
9
10
|
} = options;
|
|
10
11
|
const filePatterns = serverFilePatterns.map(
|
|
11
12
|
(p) => new RegExp(p.replace(/\./g, "\\.") + "$", "i")
|
|
@@ -13,6 +14,7 @@ function serverBoundaryPlugin(options = {}) {
|
|
|
13
14
|
const dirPatterns = serverDirPatterns.map(
|
|
14
15
|
(p) => new RegExp(p.replace(/\//g, "[\\\\/]"), "i")
|
|
15
16
|
);
|
|
17
|
+
const serverActionFiles = /* @__PURE__ */ new Set();
|
|
16
18
|
function isServerOnlyModule(id) {
|
|
17
19
|
for (const pattern of filePatterns) {
|
|
18
20
|
if (pattern.test(id)) return true;
|
|
@@ -23,6 +25,7 @@ function serverBoundaryPlugin(options = {}) {
|
|
|
23
25
|
return false;
|
|
24
26
|
}
|
|
25
27
|
function isExcluded(id) {
|
|
28
|
+
if (id.includes("node_modules")) return true;
|
|
26
29
|
for (const pattern of exclude) {
|
|
27
30
|
const regex = new RegExp(
|
|
28
31
|
pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/\\\\]*").replace(/\./g, "\\.")
|
|
@@ -35,52 +38,36 @@ function serverBoundaryPlugin(options = {}) {
|
|
|
35
38
|
if (customErrorMessage) {
|
|
36
39
|
return customErrorMessage(module, importer);
|
|
37
40
|
}
|
|
38
|
-
return `[Flight]
|
|
39
|
-
|
|
41
|
+
return `[Flight] Server-only module imported in client code.
|
|
40
42
|
Module: ${module}
|
|
41
43
|
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`;
|
|
44
|
+
Solutions: Rename to *.server.ts, add 'use server', or use dynamic import.`;
|
|
50
45
|
}
|
|
51
46
|
return {
|
|
52
47
|
name: "flight:server-boundary",
|
|
53
|
-
enforce: "
|
|
48
|
+
enforce: "post",
|
|
49
|
+
transform(code, id, options2) {
|
|
50
|
+
if (options2?.ssr) return null;
|
|
51
|
+
if (skipServerActions) {
|
|
52
|
+
const trimmed = code.trim();
|
|
53
|
+
if (trimmed.startsWith("'use server'") || trimmed.startsWith('"use server"')) {
|
|
54
|
+
serverActionFiles.add(id);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
},
|
|
54
59
|
resolveId(source, importer, options2) {
|
|
55
60
|
if (options2?.ssr) return null;
|
|
56
61
|
if (!importer) return null;
|
|
57
62
|
if (isExcluded(importer)) return null;
|
|
63
|
+
if (skipServerActions && serverActionFiles.has(importer)) return null;
|
|
58
64
|
if (isServerOnlyModule(importer)) return null;
|
|
59
65
|
if (isServerOnlyModule(source)) {
|
|
60
66
|
const message = createErrorMessage(source, importer);
|
|
61
67
|
if (violationBehavior === "error") {
|
|
62
68
|
this.error(message);
|
|
63
69
|
} else {
|
|
64
|
-
|
|
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);
|
|
70
|
+
console.warn(message);
|
|
84
71
|
}
|
|
85
72
|
}
|
|
86
73
|
return null;
|
|
@@ -89,5 +76,5 @@ This file should only run on the server. Check your import graph to find where t
|
|
|
89
76
|
}
|
|
90
77
|
|
|
91
78
|
export { serverBoundaryPlugin };
|
|
92
|
-
//# sourceMappingURL=chunk-
|
|
93
|
-
//# sourceMappingURL=chunk-
|
|
79
|
+
//# sourceMappingURL=chunk-NU3HX5T7.js.map
|
|
80
|
+
//# sourceMappingURL=chunk-NU3HX5T7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/server-boundary-plugin.ts"],"names":["options"],"mappings":";AA8DO,SAAS,oBAAA,CACZ,OAAA,GAAuC,EAAC,EAClC;AACN,EAAA,MAAM;AAAA,IACF,kBAAA,GAAqB,CAAC,YAAA,EAAc,aAAA,EAAe,cAAc,aAAa,CAAA;AAAA,IAC9E,iBAAA,GAAoB,CAAC,UAAU,CAAA;AAAA,IAC/B,iBAAA,GAAoB,MAAA;AAAA,IACpB,kBAAA;AAAA,IACA,UAAU,EAAC;AAAA,IACX,iBAAA,GAAoB;AAAA,GACxB,GAAI,OAAA;AAGJ,EAAA,MAAM,eAAe,kBAAA,CAAmB,GAAA;AAAA,IAAI,CAAA,CAAA,KACxC,IAAI,MAAA,CAAO,CAAA,CAAE,QAAQ,KAAA,EAAO,KAAK,CAAA,GAAI,GAAA,EAAK,GAAG;AAAA,GACjD;AACA,EAAA,MAAM,cAAc,iBAAA,CAAkB,GAAA;AAAA,IAAI,CAAA,CAAA,KACtC,IAAI,MAAA,CAAO,CAAA,CAAE,QAAQ,KAAA,EAAO,SAAS,GAAG,GAAG;AAAA,GAC/C;AAGA,EAAA,MAAM,iBAAA,uBAAwB,GAAA,EAAY;AAE1C,EAAA,SAAS,mBAAmB,EAAA,EAAqB;AAC7C,IAAA,KAAA,MAAW,WAAW,YAAA,EAAc;AAChC,MAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,IAAA;AAAA,IACjC;AACA,IAAA,KAAA,MAAW,WAAW,WAAA,EAAa;AAC/B,MAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,IAAA;AAAA,IACjC;AACA,IAAA,OAAO,KAAA;AAAA,EACX;AAEA,EAAA,SAAS,WAAW,EAAA,EAAqB;AACrC,IAAA,IAAI,EAAA,CAAG,QAAA,CAAS,cAAc,CAAA,EAAG,OAAO,IAAA;AACxC,IAAA,KAAA,MAAW,WAAW,OAAA,EAAS;AAC3B,MAAA,MAAM,QAAQ,IAAI,MAAA;AAAA,QACd,OAAA,CAAQ,OAAA,CAAQ,OAAA,EAAS,IAAI,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,WAAW,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,KAAK;AAAA,OACnF;AACA,MAAA,IAAI,KAAA,CAAM,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,IAAA;AAAA,IAC/B;AACA,IAAA,OAAO,KAAA;AAAA,EACX;AAEA,EAAA,SAAS,kBAAA,CAAmB,QAAgB,QAAA,EAA0B;AAClE,IAAA,IAAI,kBAAA,EAAoB;AACpB,MAAA,OAAO,kBAAA,CAAmB,QAAQ,QAAQ,CAAA;AAAA,IAC9C;AACA,IAAA,OACI,CAAA;AAAA,UAAA,EACa,MAAM;AAAA,eAAA,EACD,QAAQ;AAAA,0EAAA,CAAA;AAAA,EAGlC;AAEA,EAAA,OAAO;AAAA,IACH,IAAA,EAAM,wBAAA;AAAA,IACN,OAAA,EAAS,MAAA;AAAA,IAET,SAAA,CAAU,IAAA,EAAM,EAAA,EAAIA,QAAAA,EAAS;AACzB,MAAA,IAAIA,QAAAA,EAAS,KAAK,OAAO,IAAA;AAGzB,MAAA,IAAI,iBAAA,EAAmB;AACnB,QAAA,MAAM,OAAA,GAAU,KAAK,IAAA,EAAK;AAC1B,QAAA,IAAI,QAAQ,UAAA,CAAW,cAAc,KAAK,OAAA,CAAQ,UAAA,CAAW,cAAc,CAAA,EAAG;AAC1E,UAAA,iBAAA,CAAkB,IAAI,EAAE,CAAA;AAAA,QAC5B;AAAA,MACJ;AACA,MAAA,OAAO,IAAA;AAAA,IACX,CAAA;AAAA,IAEA,SAAA,CAAU,MAAA,EAAQ,QAAA,EAAUA,QAAAA,EAAS;AACjC,MAAA,IAAIA,QAAAA,EAAS,KAAK,OAAO,IAAA;AACzB,MAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AACtB,MAAA,IAAI,UAAA,CAAW,QAAQ,CAAA,EAAG,OAAO,IAAA;AACjC,MAAA,IAAI,iBAAA,IAAqB,iBAAA,CAAkB,GAAA,CAAI,QAAQ,GAAG,OAAO,IAAA;AACjE,MAAA,IAAI,kBAAA,CAAmB,QAAQ,CAAA,EAAG,OAAO,IAAA;AAEzC,MAAA,IAAI,kBAAA,CAAmB,MAAM,CAAA,EAAG;AAC5B,QAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,MAAA,EAAQ,QAAQ,CAAA;AACnD,QAAA,IAAI,sBAAsB,OAAA,EAAS;AAC/B,UAAA,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,QACtB,CAAA,MAAO;AACH,UAAA,OAAA,CAAQ,KAAK,OAAO,CAAA;AAAA,QACxB;AAAA,MACJ;AACA,MAAA,OAAO,IAAA;AAAA,IACX;AAAA,GACJ;AACJ","file":"chunk-NU3HX5T7.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 * NOTE: This plugin is designed to work WITH serverActionsPlugin.\r\n * It will NOT flag 'use server' files because those are handled\r\n * by the Server Actions transformation.\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/']\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 'warn'\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.\r\n */\r\n exclude?: string[];\r\n\r\n /**\r\n * Skip checking 'use server' files. These are handled by serverActionsPlugin.\r\n * @default true\r\n */\r\n skipServerActions?: boolean;\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\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/'],\r\n violationBehavior = 'warn',\r\n customErrorMessage,\r\n exclude = [],\r\n skipServerActions = true,\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 // Track files with 'use server' to skip them\r\n const serverActionFiles = new Set<string>();\r\n\r\n function isServerOnlyModule(id: string): boolean {\r\n for (const pattern of filePatterns) {\r\n if (pattern.test(id)) return true;\r\n }\r\n for (const pattern of dirPatterns) {\r\n if (pattern.test(id)) return true;\r\n }\r\n return false;\r\n }\r\n\r\n function isExcluded(id: string): boolean {\r\n if (id.includes('node_modules')) return true;\r\n for (const pattern of exclude) {\r\n const regex = new RegExp(\r\n pattern.replace(/\\*\\*/g, '.*').replace(/\\*/g, '[^/\\\\\\\\]*').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 return (\r\n `[Flight] Server-only module imported in client code.\\n` +\r\n ` Module: ${module}\\n` +\r\n ` Imported by: ${importer}\\n` +\r\n `Solutions: Rename to *.server.ts, add 'use server', or use dynamic import.`\r\n );\r\n }\r\n\r\n return {\r\n name: 'flight:server-boundary',\r\n enforce: 'post',\r\n\r\n transform(code, id, options) {\r\n if (options?.ssr) return null;\r\n\r\n // Track 'use server' files\r\n if (skipServerActions) {\r\n const trimmed = code.trim();\r\n if (trimmed.startsWith(\"'use server'\") || trimmed.startsWith('\"use server\"')) {\r\n serverActionFiles.add(id);\r\n }\r\n }\r\n return null;\r\n },\r\n\r\n resolveId(source, importer, options) {\r\n if (options?.ssr) return null;\r\n if (!importer) return null;\r\n if (isExcluded(importer)) return null;\r\n if (skipServerActions && serverActionFiles.has(importer)) return null;\r\n if (isServerOnlyModule(importer)) return null;\r\n\r\n if (isServerOnlyModule(source)) {\r\n const message = createErrorMessage(source, importer);\r\n if (violationBehavior === 'error') {\r\n this.error(message);\r\n } else {\r\n console.warn(message);\r\n }\r\n }\r\n return null;\r\n },\r\n };\r\n}\r\n"]}
|
package/dist/plugins/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { serverBoundaryPlugin } from '../chunk-
|
|
2
|
-
export { serverBoundaryPlugin } from '../chunk-
|
|
1
|
+
import { serverBoundaryPlugin } from '../chunk-NU3HX5T7.js';
|
|
2
|
+
export { serverBoundaryPlugin } from '../chunk-NU3HX5T7.js';
|
|
3
3
|
import { flightEnvPlugin } from '../chunk-RFTE6JVG.js';
|
|
4
4
|
export { flightEnvPlugin } from '../chunk-RFTE6JVG.js';
|
|
5
5
|
|
|
@@ -6,21 +6,9 @@ import { Plugin } from 'vite';
|
|
|
6
6
|
* Vite plugin to detect server-only code imported in client bundles.
|
|
7
7
|
* OPTIONAL - use if you want build-time protection.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* - Configurable behavior (warn, error)
|
|
13
|
-
* - Clear error messages with solutions
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```typescript
|
|
17
|
-
* // vite.config.ts
|
|
18
|
-
* import { serverBoundaryPlugin } from '@flight-framework/core/plugins';
|
|
19
|
-
*
|
|
20
|
-
* export default {
|
|
21
|
-
* plugins: [serverBoundaryPlugin()],
|
|
22
|
-
* };
|
|
23
|
-
* ```
|
|
9
|
+
* NOTE: This plugin is designed to work WITH serverActionsPlugin.
|
|
10
|
+
* It will NOT flag 'use server' files because those are handled
|
|
11
|
+
* by the Server Actions transformation.
|
|
24
12
|
*/
|
|
25
13
|
|
|
26
14
|
interface ServerBoundaryPluginOptions {
|
|
@@ -31,14 +19,14 @@ interface ServerBoundaryPluginOptions {
|
|
|
31
19
|
serverFilePatterns?: string[];
|
|
32
20
|
/**
|
|
33
21
|
* Directory patterns that are server-only.
|
|
34
|
-
* @default ['/server/'
|
|
22
|
+
* @default ['/server/']
|
|
35
23
|
*/
|
|
36
24
|
serverDirPatterns?: string[];
|
|
37
25
|
/**
|
|
38
26
|
* How to handle violations.
|
|
39
27
|
* - 'error': Build error (recommended for production)
|
|
40
28
|
* - 'warn': Warning only (for migration)
|
|
41
|
-
* @default '
|
|
29
|
+
* @default 'warn'
|
|
42
30
|
*/
|
|
43
31
|
violationBehavior?: 'error' | 'warn';
|
|
44
32
|
/**
|
|
@@ -46,21 +34,17 @@ interface ServerBoundaryPluginOptions {
|
|
|
46
34
|
*/
|
|
47
35
|
customErrorMessage?: (module: string, importer: string) => string;
|
|
48
36
|
/**
|
|
49
|
-
* Files to exclude from checking
|
|
50
|
-
* @default ['**\/*.test.*', '**\/*.spec.*']
|
|
37
|
+
* Files to exclude from checking.
|
|
51
38
|
*/
|
|
52
39
|
exclude?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* Skip checking 'use server' files. These are handled by serverActionsPlugin.
|
|
42
|
+
* @default true
|
|
43
|
+
*/
|
|
44
|
+
skipServerActions?: boolean;
|
|
53
45
|
}
|
|
54
46
|
/**
|
|
55
47
|
* 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
|
|
64
48
|
*/
|
|
65
49
|
declare function serverBoundaryPlugin(options?: ServerBoundaryPluginOptions): Plugin;
|
|
66
50
|
|
package/package.json
CHANGED
|
@@ -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"]}
|