@empline/preflight 1.1.32 → 1.1.34

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 (49) hide show
  1. package/dist/checks/auth/client-only-protected-pages.d.ts +14 -0
  2. package/dist/checks/auth/client-only-protected-pages.d.ts.map +1 -0
  3. package/dist/checks/auth/client-only-protected-pages.js +182 -0
  4. package/dist/checks/auth/client-only-protected-pages.js.map +1 -0
  5. package/dist/checks/auth/empty-data-instead-of-redirect.d.ts +14 -0
  6. package/dist/checks/auth/empty-data-instead-of-redirect.d.ts.map +1 -0
  7. package/dist/checks/auth/empty-data-instead-of-redirect.js +200 -0
  8. package/dist/checks/auth/empty-data-instead-of-redirect.js.map +1 -0
  9. package/dist/checks/auth/store-id-fallback.d.ts +14 -0
  10. package/dist/checks/auth/store-id-fallback.d.ts.map +1 -0
  11. package/dist/checks/auth/store-id-fallback.js +217 -0
  12. package/dist/checks/auth/store-id-fallback.js.map +1 -0
  13. package/dist/checks/auth/store-page-auth-guard.d.ts +14 -0
  14. package/dist/checks/auth/store-page-auth-guard.d.ts.map +1 -0
  15. package/dist/checks/auth/store-page-auth-guard.js +207 -0
  16. package/dist/checks/auth/store-page-auth-guard.js.map +1 -0
  17. package/dist/checks/cart/cart-guest-merge.d.ts +14 -0
  18. package/dist/checks/cart/cart-guest-merge.d.ts.map +1 -0
  19. package/dist/checks/cart/cart-guest-merge.js +217 -0
  20. package/dist/checks/cart/cart-guest-merge.js.map +1 -0
  21. package/dist/checks/cart/cart-quantity-validation.d.ts +14 -0
  22. package/dist/checks/cart/cart-quantity-validation.d.ts.map +1 -0
  23. package/dist/checks/cart/cart-quantity-validation.js +211 -0
  24. package/dist/checks/cart/cart-quantity-validation.js.map +1 -0
  25. package/dist/checks/cart/cart-stock-validation.d.ts +14 -0
  26. package/dist/checks/cart/cart-stock-validation.d.ts.map +1 -0
  27. package/dist/checks/cart/cart-stock-validation.js +211 -0
  28. package/dist/checks/cart/cart-stock-validation.js.map +1 -0
  29. package/dist/checks/checkout/checkout-multi-store.d.ts +14 -0
  30. package/dist/checks/checkout/checkout-multi-store.d.ts.map +1 -0
  31. package/dist/checks/checkout/checkout-multi-store.js +209 -0
  32. package/dist/checks/checkout/checkout-multi-store.js.map +1 -0
  33. package/dist/checks/checkout/checkout-tax-consistency.d.ts +14 -0
  34. package/dist/checks/checkout/checkout-tax-consistency.d.ts.map +1 -0
  35. package/dist/checks/checkout/checkout-tax-consistency.js +212 -0
  36. package/dist/checks/checkout/checkout-tax-consistency.js.map +1 -0
  37. package/dist/checks/order/order-inventory-guard.d.ts +14 -0
  38. package/dist/checks/order/order-inventory-guard.d.ts.map +1 -0
  39. package/dist/checks/order/order-inventory-guard.js +212 -0
  40. package/dist/checks/order/order-inventory-guard.js.map +1 -0
  41. package/dist/checks/order/order-status-validation.d.ts +14 -0
  42. package/dist/checks/order/order-status-validation.d.ts.map +1 -0
  43. package/dist/checks/order/order-status-validation.js +218 -0
  44. package/dist/checks/order/order-status-validation.js.map +1 -0
  45. package/dist/checks/order/shipping-address-validation.d.ts +14 -0
  46. package/dist/checks/order/shipping-address-validation.d.ts.map +1 -0
  47. package/dist/checks/order/shipping-address-validation.js +213 -0
  48. package/dist/checks/order/shipping-address-validation.js.map +1 -0
  49. package/package.json +1 -1
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ export declare const id = "auth/client-only-protected-pages";
3
+ export declare const name = "Client Only Protected Pages";
4
+ export declare const description = "Detects protected pages marked 'use client' bypassing server auth";
5
+ export declare const category = "auth";
6
+ export declare const blocking = true;
7
+ export declare const tags: string[];
8
+ export declare const requires: string[];
9
+ export declare function run(): Promise<{
10
+ success: boolean;
11
+ errors: number;
12
+ warnings: number;
13
+ }>;
14
+ //# sourceMappingURL=client-only-protected-pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-only-protected-pages.d.ts","sourceRoot":"","sources":["../../../src/checks/auth/client-only-protected-pages.ts"],"names":[],"mappings":";AA2BA,eAAO,MAAM,EAAE,qCAAqC,CAAC;AACrD,eAAO,MAAM,IAAI,gCAAgC,CAAC;AAClD,eAAO,MAAM,WAAW,sEAAsE,CAAC;AAC/F,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,IAAI,UAA8D,CAAC;AAChF,eAAO,MAAM,QAAQ,UAA0B,CAAC;AAgDhD,wBAAsB,GAAG,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAmH3F"}
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.requires = exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
8
+ exports.run = run;
9
+ /**
10
+ * Client Only Protected Pages Preflight
11
+ *
12
+ * Detects when pages in protected routes are marked "use client" which
13
+ * bypasses server-side authentication. This is a CRITICAL security issue.
14
+ *
15
+ * The problem:
16
+ * - Server Components can check auth before rendering
17
+ * - Client Components render first, THEN check auth
18
+ * - This creates a flash of protected content before redirect
19
+ * - Attacker can intercept the initial HTML with sensitive data
20
+ *
21
+ * DANGEROUS: 'use client' in app/store/[storeId]/page.tsx
22
+ * DANGEROUS: 'use client' in app/admin/page.tsx
23
+ * DANGEROUS: 'use client' in app/(protected)/page.tsx
24
+ *
25
+ * SAFE: Server Component that checks auth, then renders client child
26
+ * SAFE: Layout does auth check, page can be client component
27
+ */
28
+ const fs_1 = __importDefault(require("fs"));
29
+ const path_1 = __importDefault(require("path"));
30
+ const glob_1 = require("glob");
31
+ const console_chars_1 = require("../../utils/console-chars");
32
+ // METADATA - Required for plugin loader discovery
33
+ exports.id = "auth/client-only-protected-pages";
34
+ exports.name = "Client Only Protected Pages";
35
+ exports.description = "Detects protected pages marked 'use client' bypassing server auth";
36
+ exports.category = "auth";
37
+ exports.blocking = true; // Critical security check
38
+ exports.tags = ["auth", "security", "client", "server", "rsc", "critical"];
39
+ exports.requires = ["trading-card-system"];
40
+ /**
41
+ * Protected route patterns that MUST have server-side auth
42
+ */
43
+ const PROTECTED_ROUTE_PATTERNS = [
44
+ "app/store/**/page.tsx",
45
+ "app/admin/**/page.tsx",
46
+ "app/(protected)/**/page.tsx",
47
+ "app/(authenticated)/**/page.tsx",
48
+ "app/dashboard/**/page.tsx",
49
+ "app/settings/**/page.tsx",
50
+ "app/account/**/page.tsx",
51
+ "app/seller/**/page.tsx",
52
+ ];
53
+ /**
54
+ * These files MUST check auth server-side in the route
55
+ */
56
+ const LAYOUT_FILES = [
57
+ "app/store/layout.tsx",
58
+ "app/store/[storeId]/layout.tsx",
59
+ "app/admin/layout.tsx",
60
+ "app/(protected)/layout.tsx",
61
+ "app/dashboard/layout.tsx",
62
+ ];
63
+ function hasUseClientDirective(content) {
64
+ // Check first 500 chars for 'use client' directive
65
+ const header = content.substring(0, 500);
66
+ return /['"]use client['"]/.test(header);
67
+ }
68
+ function hasServerAuthCheck(content) {
69
+ // Check for server-side auth patterns
70
+ return (/getServerSession|auth\s*\(\s*\)|requireAuth/.test(content) &&
71
+ /redirect|notFound|throw/.test(content));
72
+ }
73
+ async function run() {
74
+ console.log(`\n${console_chars_1.emoji.shield} CLIENT ONLY PROTECTED PAGES CHECK`);
75
+ console.log((0, console_chars_1.createDivider)(65, "heavy"));
76
+ const issues = [];
77
+ const filesChecked = [];
78
+ // First, check if protected route layouts have server auth
79
+ console.log(`\n${console_chars_1.emoji.search} Checking protected route layouts...`);
80
+ const layoutsWithAuth = new Set();
81
+ for (const layoutPattern of LAYOUT_FILES) {
82
+ const matches = await (0, glob_1.glob)(layoutPattern, { cwd: process.cwd() });
83
+ for (const relativePath of matches) {
84
+ const filePath = path_1.default.join(process.cwd(), relativePath);
85
+ if (!fs_1.default.existsSync(filePath))
86
+ continue;
87
+ const content = fs_1.default.readFileSync(filePath, "utf-8");
88
+ if (hasServerAuthCheck(content)) {
89
+ layoutsWithAuth.add(path_1.default.dirname(relativePath));
90
+ console.log(` ${console_chars_1.emoji.success} ${relativePath} has server-side auth`);
91
+ }
92
+ else if (!hasUseClientDirective(content)) {
93
+ // Server component layout without auth check
94
+ console.log(` ${console_chars_1.emoji.warning} ${relativePath} is server component but no auth check found`);
95
+ }
96
+ }
97
+ }
98
+ // Now check protected pages
99
+ console.log(`\n${console_chars_1.emoji.search} Checking protected pages...`);
100
+ const allFiles = [];
101
+ for (const pattern of PROTECTED_ROUTE_PATTERNS) {
102
+ const matches = await (0, glob_1.glob)(pattern, { cwd: process.cwd() });
103
+ allFiles.push(...matches);
104
+ }
105
+ const uniqueFiles = [...new Set(allFiles)];
106
+ for (const relativePath of uniqueFiles) {
107
+ const filePath = path_1.default.join(process.cwd(), relativePath);
108
+ if (!fs_1.default.existsSync(filePath))
109
+ continue;
110
+ const content = fs_1.default.readFileSync(filePath, "utf-8");
111
+ filesChecked.push(relativePath);
112
+ const isClientComponent = hasUseClientDirective(content);
113
+ const pageDir = path_1.default.dirname(relativePath);
114
+ // Check if this page's parent layout has auth
115
+ const hasParentLayoutAuth = [...layoutsWithAuth].some((layoutDir) => pageDir.startsWith(layoutDir));
116
+ if (isClientComponent) {
117
+ if (!hasParentLayoutAuth) {
118
+ issues.push({
119
+ file: relativePath,
120
+ type: "client-protected-page",
121
+ description: `Protected page uses 'use client' without server auth in parent layout`,
122
+ critical: true,
123
+ });
124
+ console.log(` ${console_chars_1.emoji.error} ${relativePath}: Client component in protected route without parent layout auth`);
125
+ }
126
+ else {
127
+ console.log(` ${console_chars_1.emoji.success} ${relativePath}: Client component but parent layout has auth`);
128
+ }
129
+ }
130
+ else {
131
+ // Server component - check if it has its own auth
132
+ if (hasServerAuthCheck(content)) {
133
+ console.log(` ${console_chars_1.emoji.success} ${relativePath}: Server component with auth check`);
134
+ }
135
+ else if (hasParentLayoutAuth) {
136
+ console.log(` ${console_chars_1.emoji.success} ${relativePath}: Server component, parent layout has auth`);
137
+ }
138
+ else {
139
+ console.log(` ${console_chars_1.emoji.warning} ${relativePath}: Server component but no visible auth check`);
140
+ }
141
+ }
142
+ }
143
+ // Summary
144
+ const criticalIssues = issues.filter((i) => i.critical);
145
+ console.log(`\n${console_chars_1.emoji.chart} Summary:`);
146
+ console.log(` Protected pages checked: ${filesChecked.length}`);
147
+ console.log(` Layouts with server auth: ${layoutsWithAuth.size}`);
148
+ console.log(` Security issues: ${criticalIssues.length}`);
149
+ if (issues.length === 0) {
150
+ console.log(`\n${console_chars_1.emoji.success} CLIENT ONLY PROTECTED PAGES CHECK PASSED`);
151
+ console.log(`\nAll protected pages have proper server-side authentication.`);
152
+ return { success: true, errors: 0, warnings: 0 };
153
+ }
154
+ console.log(`\n${console_chars_1.emoji.error} Security issues found:`);
155
+ for (const issue of issues) {
156
+ console.log(` ${issue.file}: ${issue.description}`);
157
+ }
158
+ console.log(`\n${console_chars_1.emoji.info} To fix client-only protected pages:`);
159
+ console.log(` Option 1: Remove 'use client' and do auth in the page itself`);
160
+ console.log(` Option 2: Add auth check to parent layout.tsx (recommended)`);
161
+ console.log(` Option 3: Create a Server Component wrapper that checks auth`);
162
+ console.log(`\n Layout auth pattern:`);
163
+ console.log(` export default async function Layout({children}) {`);
164
+ console.log(` const session = await auth();`);
165
+ console.log(` if (!session) redirect('/login');`);
166
+ console.log(` return children;`);
167
+ console.log(` }`);
168
+ console.log(`\n${console_chars_1.emoji.error} CLIENT ONLY PROTECTED PAGES CHECK FAILED`);
169
+ return { success: false, errors: criticalIssues.length, warnings: 0 };
170
+ }
171
+ // Allow direct execution
172
+ if (require.main === module) {
173
+ run()
174
+ .then((result) => {
175
+ process.exit(result.success ? 0 : 1);
176
+ })
177
+ .catch((err) => {
178
+ console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
179
+ process.exit(1);
180
+ });
181
+ }
182
+ //# sourceMappingURL=client-only-protected-pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-only-protected-pages.js","sourceRoot":"","sources":["../../../src/checks/auth/client-only-protected-pages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ export declare const id = "auth/empty-data-instead-of-redirect";
3
+ export declare const name = "Empty Data Instead of Redirect";
4
+ export declare const description = "Detects pages returning empty data instead of redirecting on access failure";
5
+ export declare const category = "auth";
6
+ export declare const blocking = true;
7
+ export declare const tags: string[];
8
+ export declare const requires: string[];
9
+ export declare function run(): Promise<{
10
+ success: boolean;
11
+ errors: number;
12
+ warnings: number;
13
+ }>;
14
+ //# sourceMappingURL=empty-data-instead-of-redirect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-data-instead-of-redirect.d.ts","sourceRoot":"","sources":["../../../src/checks/auth/empty-data-instead-of-redirect.ts"],"names":[],"mappings":";AA4BA,eAAO,MAAM,EAAE,wCAAwC,CAAC;AACxD,eAAO,MAAM,IAAI,mCAAmC,CAAC;AACrD,eAAO,MAAM,WAAW,gFAAgF,CAAC;AACzG,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,IAAI,UAAqD,CAAC;AACvE,eAAO,MAAM,QAAQ,UAA0B,CAAC;AAiFhD,wBAAsB,GAAG,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuG3F"}
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.requires = exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
8
+ exports.run = run;
9
+ /**
10
+ * Empty Data Instead of Redirect Preflight
11
+ *
12
+ * Detects when pages return empty arrays/objects instead of redirecting
13
+ * on access failure. This is a security anti-pattern because:
14
+ *
15
+ * BAD: if (!hasAccess) return { data: [] } // Hides access failure
16
+ * BAD: if (!session) return [] // Silent auth failure
17
+ * BAD: if (!store) return null // Doesn't tell user they need to login
18
+ *
19
+ * GOOD: if (!hasAccess) redirect('/unauthorized')
20
+ * GOOD: if (!session) redirect('/login')
21
+ * GOOD: if (!store) notFound()
22
+ *
23
+ * Problems with returning empty data:
24
+ * - User sees blank page with no explanation
25
+ * - Masks authorization failures
26
+ * - Makes debugging harder
27
+ * - May expose that resource exists (information leak)
28
+ */
29
+ const fs_1 = __importDefault(require("fs"));
30
+ const path_1 = __importDefault(require("path"));
31
+ const glob_1 = require("glob");
32
+ const console_chars_1 = require("../../utils/console-chars");
33
+ // METADATA - Required for plugin loader discovery
34
+ exports.id = "auth/empty-data-instead-of-redirect";
35
+ exports.name = "Empty Data Instead of Redirect";
36
+ exports.description = "Detects pages returning empty data instead of redirecting on access failure";
37
+ exports.category = "auth";
38
+ exports.blocking = true;
39
+ exports.tags = ["auth", "security", "redirect", "ux", "critical"];
40
+ exports.requires = ["trading-card-system"];
41
+ /**
42
+ * File patterns to check
43
+ */
44
+ const FILE_PATTERNS = [
45
+ "app/**/page.tsx",
46
+ "app/**/layout.tsx",
47
+ "app/api/**/route.ts",
48
+ ];
49
+ /**
50
+ * Dangerous patterns - returning empty on auth/access failure
51
+ */
52
+ const DANGEROUS_PATTERNS = {
53
+ // Return empty array on !session
54
+ emptyArrayNoSession: {
55
+ pattern: /if\s*\(\s*!session\s*\)[^{]*return\s*(?:\[\s*\]|\{\s*\}|null|undefined)/,
56
+ description: "Returns empty data when session missing (should redirect to login)",
57
+ critical: true,
58
+ },
59
+ // Return empty array on !hasAccess
60
+ emptyArrayNoAccess: {
61
+ pattern: /if\s*\(\s*!(?:hasAccess|canAccess|isAuthorized|hasPermission)\s*\)[^{]*return\s*(?:\[\s*\]|\{\s*\}|null)/,
62
+ description: "Returns empty data on access failure (should redirect or show error)",
63
+ critical: true,
64
+ },
65
+ // Return empty on !store
66
+ emptyArrayNoStore: {
67
+ pattern: /if\s*\(\s*!store\s*\)[^{]*return\s*(?:\[\s*\]|\{\s*\}|null)/,
68
+ description: "Returns empty data when store not found (should use notFound())",
69
+ critical: true,
70
+ },
71
+ // Return empty data prop
72
+ emptyDataProp: {
73
+ pattern: /return\s*\{[^}]*(?:data|items|results):\s*\[\s*\][^}]*\}(?:(?!redirect|notFound).)*$/m,
74
+ description: "Returns object with empty data array (may mask access failure)",
75
+ critical: false,
76
+ },
77
+ // Early return empty in RSC
78
+ earlyReturnEmpty: {
79
+ pattern: /(?:async\s+)?function\s+(?:Page|Layout)\s*\([^)]*\)[^{]*\{[^}]*if\s*\([^)]*\)\s*return\s*(?:null|\[\]|\{\})/s,
80
+ description: "Page/Layout returns empty early (should redirect instead)",
81
+ critical: false,
82
+ },
83
+ // Return NextResponse with empty body on auth failure
84
+ nextResponseEmpty: {
85
+ pattern: /if\s*\(\s*!(?:session|auth|user)\s*\)[^{]*return\s*NextResponse\.json\s*\(\s*(?:\[\]|\{\}|null)\s*\)/,
86
+ description: "API returns empty response on auth failure (should return 401)",
87
+ critical: true,
88
+ },
89
+ };
90
+ /**
91
+ * Safe patterns that indicate proper handling
92
+ */
93
+ const SAFE_PATTERNS = [
94
+ // Redirect on failure
95
+ /if\s*\(\s*!session\s*\)[^{]*redirect/,
96
+ /if\s*\(\s*!hasAccess\s*\)[^{]*redirect/,
97
+ // notFound() call
98
+ /if\s*\(\s*!(?:store|data|item)\s*\)[^{]*notFound\s*\(\)/,
99
+ // Proper error response
100
+ /if\s*\(\s*!session\s*\)[^{]*return\s*(?:NextResponse\.json\s*\([^)]*,\s*\{\s*status:\s*401|new\s*Response\s*\([^)]*,\s*\{\s*status:\s*401)/,
101
+ // Throw error
102
+ /if\s*\(\s*!(?:session|hasAccess)\s*\)[^{]*throw/,
103
+ ];
104
+ function getLineNumber(content, position) {
105
+ return content.substring(0, position).split("\n").length;
106
+ }
107
+ async function run() {
108
+ console.log(`\n${console_chars_1.emoji.shield} EMPTY DATA INSTEAD OF REDIRECT CHECK`);
109
+ console.log((0, console_chars_1.createDivider)(65, "heavy"));
110
+ const issues = [];
111
+ const filesChecked = [];
112
+ // Find files
113
+ const allFiles = [];
114
+ for (const pattern of FILE_PATTERNS) {
115
+ const matches = await (0, glob_1.glob)(pattern, { cwd: process.cwd() });
116
+ allFiles.push(...matches);
117
+ }
118
+ const uniqueFiles = [...new Set(allFiles)];
119
+ console.log(`\n${console_chars_1.emoji.search} Scanning ${uniqueFiles.length} page/route files...`);
120
+ for (const relativePath of uniqueFiles) {
121
+ const filePath = path_1.default.join(process.cwd(), relativePath);
122
+ if (!fs_1.default.existsSync(filePath))
123
+ continue;
124
+ const content = fs_1.default.readFileSync(filePath, "utf-8");
125
+ filesChecked.push(relativePath);
126
+ // Skip if file has proper redirect/notFound handling
127
+ const hasSafePattern = SAFE_PATTERNS.some((pattern) => pattern.test(content));
128
+ // Check for dangerous patterns
129
+ for (const [name, check] of Object.entries(DANGEROUS_PATTERNS)) {
130
+ const regex = new RegExp(check.pattern.source, "g");
131
+ let match;
132
+ while ((match = regex.exec(content)) !== null) {
133
+ // Check if there's a safe pattern nearby
134
+ const nearbyCode = content.substring(Math.max(0, match.index - 100), Math.min(content.length, match.index + 300));
135
+ if (SAFE_PATTERNS.some((pattern) => pattern.test(nearbyCode))) {
136
+ continue;
137
+ }
138
+ const lineNum = getLineNumber(content, match.index);
139
+ issues.push({
140
+ file: relativePath,
141
+ type: "empty-data-return",
142
+ pattern: name,
143
+ description: check.description,
144
+ critical: check.critical,
145
+ line: lineNum,
146
+ });
147
+ }
148
+ }
149
+ }
150
+ // Summary
151
+ const criticalIssues = issues.filter((i) => i.critical);
152
+ const warningIssues = issues.filter((i) => !i.critical);
153
+ console.log(`\n${console_chars_1.emoji.chart} Summary:`);
154
+ console.log(` Files checked: ${filesChecked.length}`);
155
+ console.log(` Critical issues: ${criticalIssues.length}`);
156
+ console.log(` Warning issues: ${warningIssues.length}`);
157
+ if (issues.length === 0) {
158
+ console.log(`\n${console_chars_1.emoji.success} EMPTY DATA INSTEAD OF REDIRECT CHECK PASSED`);
159
+ console.log(`\nAll pages properly redirect or show errors on access failure.`);
160
+ return { success: true, errors: 0, warnings: 0 };
161
+ }
162
+ // Group by file
163
+ const issuesByFile = new Map();
164
+ for (const issue of issues) {
165
+ const existing = issuesByFile.get(issue.file) || [];
166
+ existing.push(issue);
167
+ issuesByFile.set(issue.file, existing);
168
+ }
169
+ console.log(`\n${console_chars_1.emoji.error} Issues found:`);
170
+ for (const [file, fileIssues] of issuesByFile) {
171
+ console.log(`\n ${file}:`);
172
+ for (const issue of fileIssues) {
173
+ const icon = issue.critical ? console_chars_1.emoji.error : console_chars_1.emoji.warning;
174
+ console.log(` ${icon} Line ${issue.line}: ${issue.description}`);
175
+ }
176
+ }
177
+ console.log(`\n${console_chars_1.emoji.info} To fix empty data returns:`);
178
+ console.log(` 1. On missing session: redirect('/login') or redirect('/auth/signin')`);
179
+ console.log(` 2. On access denied: redirect('/unauthorized') or return 403`);
180
+ console.log(` 3. On missing resource: notFound() to show 404 page`);
181
+ console.log(` 4. API routes: return NextResponse.json({error}, {status: 401/403})`);
182
+ if (criticalIssues.length > 0) {
183
+ console.log(`\n${console_chars_1.emoji.error} EMPTY DATA INSTEAD OF REDIRECT CHECK FAILED`);
184
+ return { success: false, errors: criticalIssues.length, warnings: warningIssues.length };
185
+ }
186
+ console.log(`\n${console_chars_1.emoji.warning} EMPTY DATA INSTEAD OF REDIRECT CHECK PASSED WITH WARNINGS`);
187
+ return { success: true, errors: 0, warnings: warningIssues.length };
188
+ }
189
+ // Allow direct execution
190
+ if (require.main === module) {
191
+ run()
192
+ .then((result) => {
193
+ process.exit(result.success ? 0 : 1);
194
+ })
195
+ .catch((err) => {
196
+ console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
197
+ process.exit(1);
198
+ });
199
+ }
200
+ //# sourceMappingURL=empty-data-instead-of-redirect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-data-instead-of-redirect.js","sourceRoot":"","sources":["../../../src/checks/auth/empty-data-instead-of-redirect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ export declare const id = "auth/store-id-fallback";
3
+ export declare const name = "Store ID Fallback Detection";
4
+ export declare const description = "Detects risky patterns where storeId falls back to userId";
5
+ export declare const category = "auth";
6
+ export declare const blocking = true;
7
+ export declare const tags: string[];
8
+ export declare const requires: string[];
9
+ export declare function run(): Promise<{
10
+ success: boolean;
11
+ errors: number;
12
+ warnings: number;
13
+ }>;
14
+ //# sourceMappingURL=store-id-fallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-id-fallback.d.ts","sourceRoot":"","sources":["../../../src/checks/auth/store-id-fallback.ts"],"names":[],"mappings":";AA4BA,eAAO,MAAM,EAAE,2BAA2B,CAAC;AAC3C,eAAO,MAAM,IAAI,gCAAgC,CAAC;AAClD,eAAO,MAAM,WAAW,8DAA8D,CAAC;AACvF,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,IAAI,UAAwD,CAAC;AAC1E,eAAO,MAAM,QAAQ,UAA0B,CAAC;AA4FhD,wBAAsB,GAAG,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgH3F"}