satset-react 0.4.5 → 0.4.7

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 (169) hide show
  1. package/package.json +2 -3
  2. package/dist/adapter/index.d.ts +0 -4
  3. package/dist/adapter/index.d.ts.map +0 -1
  4. package/dist/adapter/index.js +0 -8
  5. package/dist/adapter/index.js.map +0 -1
  6. package/dist/adapter/node.d.ts +0 -3
  7. package/dist/adapter/node.d.ts.map +0 -1
  8. package/dist/adapter/node.js +0 -244
  9. package/dist/adapter/node.js.map +0 -1
  10. package/dist/adapter/types.d.ts +0 -24
  11. package/dist/adapter/types.d.ts.map +0 -1
  12. package/dist/adapter/types.js +0 -3
  13. package/dist/adapter/types.js.map +0 -1
  14. package/dist/adapter/vercel.d.ts +0 -10
  15. package/dist/adapter/vercel.d.ts.map +0 -1
  16. package/dist/adapter/vercel.js +0 -320
  17. package/dist/adapter/vercel.js.map +0 -1
  18. package/dist/assets/favicon.d.ts +0 -2
  19. package/dist/assets/favicon.d.ts.map +0 -1
  20. package/dist/assets/favicon.js +0 -67
  21. package/dist/assets/favicon.js.map +0 -1
  22. package/dist/assets/index.d.ts +0 -7
  23. package/dist/assets/index.d.ts.map +0 -1
  24. package/dist/assets/index.js +0 -31
  25. package/dist/assets/index.js.map +0 -1
  26. package/dist/assets/metadata.d.ts +0 -29
  27. package/dist/assets/metadata.d.ts.map +0 -1
  28. package/dist/assets/metadata.js +0 -55
  29. package/dist/assets/metadata.js.map +0 -1
  30. package/dist/assets/robots.d.ts +0 -23
  31. package/dist/assets/robots.d.ts.map +0 -1
  32. package/dist/assets/robots.js +0 -95
  33. package/dist/assets/robots.js.map +0 -1
  34. package/dist/assets/sitemap.d.ts +0 -19
  35. package/dist/assets/sitemap.d.ts.map +0 -1
  36. package/dist/assets/sitemap.js +0 -78
  37. package/dist/assets/sitemap.js.map +0 -1
  38. package/dist/cli/commands.d.ts +0 -5
  39. package/dist/cli/commands.d.ts.map +0 -1
  40. package/dist/cli/commands.js +0 -165
  41. package/dist/cli/commands.js.map +0 -1
  42. package/dist/cli/index.d.ts +0 -3
  43. package/dist/cli/index.d.ts.map +0 -1
  44. package/dist/cli/index.js +0 -40
  45. package/dist/cli/index.js.map +0 -1
  46. package/dist/components/ErrorBoundary.d.ts +0 -22
  47. package/dist/components/ErrorBoundary.d.ts.map +0 -1
  48. package/dist/components/ErrorBoundary.js +0 -61
  49. package/dist/components/ErrorBoundary.js.map +0 -1
  50. package/dist/components/Image.d.ts +0 -15
  51. package/dist/components/Image.d.ts.map +0 -1
  52. package/dist/components/Image.js +0 -67
  53. package/dist/components/Image.js.map +0 -1
  54. package/dist/components/Link.d.ts +0 -14
  55. package/dist/components/Link.d.ts.map +0 -1
  56. package/dist/components/Link.js +0 -66
  57. package/dist/components/Link.js.map +0 -1
  58. package/dist/components/Script.d.ts +0 -10
  59. package/dist/components/Script.d.ts.map +0 -1
  60. package/dist/components/Script.js +0 -60
  61. package/dist/components/Script.js.map +0 -1
  62. package/dist/components/index.d.ts +0 -6
  63. package/dist/components/index.d.ts.map +0 -1
  64. package/dist/components/index.js +0 -30
  65. package/dist/components/index.js.map +0 -1
  66. package/dist/components/theme.d.ts +0 -23
  67. package/dist/components/theme.d.ts.map +0 -1
  68. package/dist/components/theme.js +0 -118
  69. package/dist/components/theme.js.map +0 -1
  70. package/dist/config.d.ts +0 -23
  71. package/dist/config.d.ts.map +0 -1
  72. package/dist/config.js +0 -9
  73. package/dist/config.js.map +0 -1
  74. package/dist/core/dynamic.d.ts +0 -10
  75. package/dist/core/dynamic.d.ts.map +0 -1
  76. package/dist/core/dynamic.js +0 -51
  77. package/dist/core/dynamic.js.map +0 -1
  78. package/dist/core/hydrate.d.ts +0 -8
  79. package/dist/core/hydrate.d.ts.map +0 -1
  80. package/dist/core/hydrate.js +0 -73
  81. package/dist/core/hydrate.js.map +0 -1
  82. package/dist/core/index.d.ts +0 -10
  83. package/dist/core/index.d.ts.map +0 -1
  84. package/dist/core/index.js +0 -22
  85. package/dist/core/index.js.map +0 -1
  86. package/dist/core/response.d.ts +0 -26
  87. package/dist/core/response.d.ts.map +0 -1
  88. package/dist/core/response.js +0 -48
  89. package/dist/core/response.js.map +0 -1
  90. package/dist/core/ssr.d.ts +0 -29
  91. package/dist/core/ssr.d.ts.map +0 -1
  92. package/dist/core/ssr.js +0 -91
  93. package/dist/core/ssr.js.map +0 -1
  94. package/dist/core/translation.d.ts +0 -19
  95. package/dist/core/translation.d.ts.map +0 -1
  96. package/dist/core/translation.js +0 -84
  97. package/dist/core/translation.js.map +0 -1
  98. package/dist/core/types.d.ts +0 -47
  99. package/dist/core/types.d.ts.map +0 -1
  100. package/dist/core/types.js +0 -3
  101. package/dist/core/types.js.map +0 -1
  102. package/dist/index.d.ts +0 -7
  103. package/dist/index.d.ts.map +0 -1
  104. package/dist/index.js +0 -25
  105. package/dist/index.js.map +0 -1
  106. package/dist/navigation/notFound.d.ts +0 -3
  107. package/dist/navigation/notFound.d.ts.map +0 -1
  108. package/dist/navigation/notFound.js +0 -15
  109. package/dist/navigation/notFound.js.map +0 -1
  110. package/dist/router/file-system.d.ts +0 -19
  111. package/dist/router/file-system.d.ts.map +0 -1
  112. package/dist/router/file-system.js +0 -364
  113. package/dist/router/file-system.js.map +0 -1
  114. package/dist/router/index.d.ts +0 -3
  115. package/dist/router/index.d.ts.map +0 -1
  116. package/dist/router/index.js +0 -10
  117. package/dist/router/index.js.map +0 -1
  118. package/dist/router/router.d.ts +0 -17
  119. package/dist/router/router.d.ts.map +0 -1
  120. package/dist/router/router.js +0 -158
  121. package/dist/router/router.js.map +0 -1
  122. package/dist/router/types.d.ts +0 -11
  123. package/dist/router/types.d.ts.map +0 -1
  124. package/dist/router/types.js +0 -3
  125. package/dist/router/types.js.map +0 -1
  126. package/dist/server/build.d.ts +0 -5
  127. package/dist/server/build.d.ts.map +0 -1
  128. package/dist/server/build.js +0 -780
  129. package/dist/server/build.js.map +0 -1
  130. package/dist/server/bundler.d.ts +0 -28
  131. package/dist/server/bundler.d.ts.map +0 -1
  132. package/dist/server/bundler.js +0 -401
  133. package/dist/server/bundler.js.map +0 -1
  134. package/dist/server/dev.d.ts +0 -11
  135. package/dist/server/dev.d.ts.map +0 -1
  136. package/dist/server/dev.js +0 -1818
  137. package/dist/server/dev.js.map +0 -1
  138. package/dist/server/env.d.ts +0 -10
  139. package/dist/server/env.d.ts.map +0 -1
  140. package/dist/server/env.js +0 -102
  141. package/dist/server/env.js.map +0 -1
  142. package/dist/server/error-overlay.d.ts +0 -12
  143. package/dist/server/error-overlay.d.ts.map +0 -1
  144. package/dist/server/error-overlay.js +0 -396
  145. package/dist/server/error-overlay.js.map +0 -1
  146. package/dist/server/hmr.d.ts +0 -8
  147. package/dist/server/hmr.d.ts.map +0 -1
  148. package/dist/server/hmr.js +0 -166
  149. package/dist/server/hmr.js.map +0 -1
  150. package/dist/server/index.d.ts +0 -10
  151. package/dist/server/index.d.ts.map +0 -1
  152. package/dist/server/index.js +0 -25
  153. package/dist/server/index.js.map +0 -1
  154. package/dist/server/response.d.ts +0 -30
  155. package/dist/server/response.d.ts.map +0 -1
  156. package/dist/server/response.js +0 -238
  157. package/dist/server/response.js.map +0 -1
  158. package/dist/server/storage.d.ts +0 -13
  159. package/dist/server/storage.d.ts.map +0 -1
  160. package/dist/server/storage.js +0 -26
  161. package/dist/server/storage.js.map +0 -1
  162. package/dist/server/tui.d.ts +0 -23
  163. package/dist/server/tui.d.ts.map +0 -1
  164. package/dist/server/tui.js +0 -182
  165. package/dist/server/tui.js.map +0 -1
  166. package/dist/server/types.d.ts +0 -14
  167. package/dist/server/types.d.ts.map +0 -1
  168. package/dist/server/types.js +0 -3
  169. package/dist/server/types.js.map +0 -1
@@ -1,780 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.build = build;
40
- const fs_1 = __importDefault(require("fs"));
41
- const path_1 = __importDefault(require("path"));
42
- const file_system_1 = require("../router/file-system");
43
- const bundler_1 = require("./bundler");
44
- const esbuild = __importStar(require("esbuild"));
45
- const env_1 = require("./env");
46
- const vercel_1 = require("../adapter/vercel");
47
- const chalk_1 = __importDefault(require("chalk"));
48
- const ora_1 = __importDefault(require("ora"));
49
- const cli_table3_1 = __importDefault(require("cli-table3"));
50
- async function build(options) {
51
- const { root, outDir = 'dist', minify = true, target = 'node', } = options;
52
- console.log('');
53
- console.log(chalk_1.default.cyan('┌──────────────────────────────────────────────────────────────┐'));
54
- console.log(chalk_1.default.cyan(`│ SATSET BUILD ENGINE v0.3.0 [ 📦 BUILD ] │`));
55
- console.log(chalk_1.default.cyan('└──────────────────────────────────────────────────────────────┘'));
56
- console.log('');
57
- // Load production env
58
- const env = (0, env_1.loadEnv)(root, 'production');
59
- console.log(` ● Environment ${chalk_1.default.green('Loaded from .env')}`);
60
- console.log(` ● Target ${chalk_1.default.blue(target)}`);
61
- console.log('');
62
- const spinner = (0, ora_1.default)('Scanning project...').start();
63
- const distPath = path_1.default.join(root, outDir);
64
- try {
65
- // Clean dist folder
66
- if (fs_1.default.existsSync(distPath)) {
67
- fs_1.default.rmSync(distPath, { recursive: true });
68
- }
69
- fs_1.default.mkdirSync(distPath, { recursive: true });
70
- // Scan routes
71
- const { routes, apiRoutes } = (0, file_system_1.getRoutes)(root);
72
- spinner.succeed(`Project structure validated`);
73
- console.log(` ✔ ${routes.length} Pages discovered`);
74
- console.log(` ✔ ${apiRoutes.length} API Routes discovered`);
75
- console.log('');
76
- console.log(chalk_1.default.bold(' BUILDING...'));
77
- // 1. Build client bundle
78
- spinner.start('[1/4] Generating Client Bundle...');
79
- await buildClientBundle(root, distPath, routes, minify);
80
- spinner.succeed('[1/4] Client Bundle Generated');
81
- // 2. Build server bundle (for SSR)
82
- spinner.start('[2/4] Generating Server Bundle...');
83
- await buildServerBundle(root, distPath, routes, minify);
84
- await bundleSeoFiles(root, distPath, minify);
85
- spinner.succeed('[2/4] Server Bundle Ready');
86
- // 3. Copy public folder
87
- spinner.start('[3/4] Optimizing Assets...');
88
- const publicPath = path_1.default.join(root, 'public');
89
- if (fs_1.default.existsSync(publicPath)) {
90
- copyFolderRecursive(publicPath, path_1.default.join(distPath, 'public'));
91
- }
92
- spinner.succeed('[3/4] Assets Optimized');
93
- // 4. Generate route manifest & server
94
- spinner.start('[4/4] Finalizing Build...');
95
- // Manifest
96
- const manifest = {
97
- routes: routes.map(r => ({ path: r.path, component: r.component })),
98
- apiRoutes: apiRoutes.map(r => ({ path: r.path, component: r.component })),
99
- buildTime: new Date().toISOString(),
100
- };
101
- fs_1.default.writeFileSync(path_1.default.join(distPath, 'routes.json'), JSON.stringify(manifest, null, 2));
102
- // API Routes
103
- for (const route of apiRoutes) {
104
- // Determine relative path.
105
- // We try to support both src/app/api and src/api for flexibility,
106
- // but defaulting to src/app/api as base if contained there.
107
- let relativePath = '';
108
- if (route.component.includes('src/app/api')) {
109
- relativePath = path_1.default.relative(path_1.default.join(root, 'src/app/api'), route.component);
110
- }
111
- else if (route.component.includes('src/api')) {
112
- relativePath = path_1.default.relative(path_1.default.join(root, 'src/api'), route.component);
113
- }
114
- else {
115
- // Fallback: just filename
116
- relativePath = path_1.default.basename(route.component);
117
- }
118
- const dest = path_1.default.join(distPath, 'api', relativePath).replace(/\.tsx?$/, '.js');
119
- fs_1.default.mkdirSync(path_1.default.dirname(dest), { recursive: true });
120
- // Transpile to JS
121
- await esbuild.build({
122
- entryPoints: [route.component],
123
- outfile: dest,
124
- bundle: true,
125
- platform: 'node',
126
- format: 'cjs',
127
- packages: 'external',
128
- logLevel: 'silent'
129
- });
130
- }
131
- // Server or Adapter
132
- if (target === 'vercel') {
133
- await (0, vercel_1.vercelAdapter)({
134
- root,
135
- sourceDir: distPath,
136
- outDir: '.vercel/output',
137
- routes,
138
- apiRoutes,
139
- env
140
- });
141
- }
142
- else {
143
- generateProductionServer(distPath, routes, apiRoutes, env);
144
- }
145
- spinner.succeed('[4/4] Build Finalized');
146
- console.log('');
147
- console.log(chalk_1.default.green('┌──────────────────────────────────────────────────────────────┐'));
148
- console.log(chalk_1.default.green(`│ ✅ BUILD SUCCESSFUL │`));
149
- console.log(chalk_1.default.green('├──────────────────────────────────────────────────────────────┤'));
150
- // Route Table
151
- const table = new cli_table3_1.default({
152
- head: ['Route', 'Type', 'Size'].map(h => chalk_1.default.white(h)),
153
- chars: { 'top': '', 'top-mid': '', 'top-left': '', 'top-right': '', 'bottom': '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '', 'left': '│', 'left-mid': '', 'mid': '', 'mid-mid': '', 'right': '│', 'right-mid': '', 'middle': ' ' },
154
- style: { 'padding-left': 2, 'padding-right': 2, head: [], border: [] }
155
- });
156
- // Add sample routes (limit to 5 to avoid clutter)
157
- routes.slice(0, 5).forEach(r => {
158
- table.push([r.path, chalk_1.default.cyan('Static'), 'Unknown']);
159
- });
160
- apiRoutes.slice(0, 3).forEach(r => {
161
- table.push([r.path, chalk_1.default.yellow('API'), 'Unknown']);
162
- });
163
- console.log(table.toString());
164
- console.log(chalk_1.default.green('└──────────────────────────────────────────────────────────────┘'));
165
- if (target === 'node') {
166
- console.log('');
167
- console.log('🚀 To run production server:');
168
- console.log(chalk_1.default.cyan(` cd ${outDir}`));
169
- console.log(chalk_1.default.cyan(' node server.js'));
170
- }
171
- return { outDir: distPath };
172
- }
173
- catch (error) {
174
- spinner.fail(chalk_1.default.red('Build failed!'));
175
- console.error(error);
176
- throw error;
177
- }
178
- }
179
- function getDictionaries(root) {
180
- const langDir = path_1.default.join(root, 'src', 'lang');
181
- const dictionaries = {};
182
- if (fs_1.default.existsSync(langDir)) {
183
- try {
184
- const files = fs_1.default.readdirSync(langDir);
185
- for (const file of files) {
186
- if (file.endsWith('.json')) {
187
- const locale = path_1.default.basename(file, '.json');
188
- try {
189
- const content = fs_1.default.readFileSync(path_1.default.join(langDir, file), 'utf-8');
190
- dictionaries[locale] = JSON.parse(content);
191
- }
192
- catch (e) {
193
- console.warn(`[i18n] Failed to load dictionary for ${locale}:`, e);
194
- }
195
- }
196
- }
197
- }
198
- catch (e) {
199
- console.warn('[i18n] Failed to read lang directory:', e);
200
- }
201
- }
202
- return dictionaries;
203
- }
204
- async function buildClientBundle(root, outdir, routes, minify) {
205
- const clientDir = path_1.default.join(outdir, 'client');
206
- fs_1.default.mkdirSync(clientDir, { recursive: true });
207
- const dictionaries = getDictionaries(root);
208
- const entryContent = `
209
- import React from 'react';
210
- import { hydrateRoot, createRoot } from 'react-dom/client';
211
- import { I18nProvider } from 'satset-react';
212
-
213
- // Route definitions
214
- const routeDefs = [
215
- ${routes.map((route, idx) => {
216
- const relativePath = path_1.default.relative(root, route.component).replace(/\\/g, '/');
217
- // Use dynamic import for code splitting
218
- return ` { path: '${route.path}', component: React.lazy(() => import('../${relativePath}')) },`;
219
- }).join('\n')}
220
- ];
221
-
222
- function stripLocale(pathname) {
223
- if (!pathname) return '/';
224
- const raw = pathname.split('?')[0].split('#')[0];
225
- const segments = raw.split('/').filter(Boolean);
226
- if (!segments.length) return '/';
227
- const first = segments[0];
228
- const localePattern = /^[a-zA-Z]{2}(?:-[a-zA-Z]{2})?$/;
229
- if (localePattern.test(first)) {
230
- const rest = segments.slice(1);
231
- return rest.length ? '/' + rest.join('/') : '/';
232
- }
233
- return raw.startsWith('/') ? raw : '/' + raw;
234
- }
235
-
236
- function matchPath(pathname) {
237
- const normalized = stripLocale(pathname);
238
- const pathSegments = normalized.split('/').filter(Boolean);
239
- for (const r of routeDefs) {
240
- const routeSegments = r.path.split('/').filter(Boolean);
241
-
242
- if (r.path.includes('*')) {
243
- const catchIndex = routeSegments.findIndex(s => s.startsWith('*'));
244
- const paramName = routeSegments[catchIndex].slice(1);
245
- const params = {};
246
- params[paramName] = pathSegments.slice(catchIndex).join('/');
247
- return { component: r.component, params };
248
- }
249
-
250
- if (routeSegments.length !== pathSegments.length) continue;
251
-
252
- let matched = true;
253
- const params = {};
254
-
255
- for (let i = 0; i < routeSegments.length; i++) {
256
- const rs = routeSegments[i];
257
- const ps = pathSegments[i];
258
-
259
- if (rs.startsWith(':')) {
260
- params[rs.slice(1)] = ps;
261
- } else if (rs !== ps) {
262
- matched = false;
263
- break;
264
- }
265
- }
266
-
267
- if (matched) {
268
- return { component: r.component, params };
269
- }
270
- }
271
-
272
- return { component: routeDefs.find(r => r.path === '/')?.component, params: {} };
273
- }
274
-
275
- const currentPath = stripLocale(window.location.pathname);
276
- const match = matchPath(currentPath);
277
- window.__SATSET_ROUTES__ = routeDefs.map(r => r.path);
278
- window.__SATSET_PARAMS__ = match.params || {};
279
- window.__SATSET_DICTIONARIES__ = ${JSON.stringify(dictionaries)};
280
-
281
- const PageComponent = match.component;
282
-
283
- if (PageComponent) {
284
- const props = match.params ? { params: match.params } : undefined;
285
- const pathSegments = window.location.pathname.split('/').filter(Boolean);
286
- const firstSegment = pathSegments[0];
287
- const initialLocale = (firstSegment && /^[a-zA-Z]{2}(?:-[a-zA-Z]{2})?$/.test(firstSegment)) ? firstSegment : 'en-US';
288
-
289
- const App = React.createElement(I18nProvider, {
290
- initialLocale,
291
- dictionaries: window.__SATSET_DICTIONARIES__
292
- }, React.createElement(PageComponent, props));
293
-
294
- const root = document.getElementById('root');
295
- if (root) {
296
- if (root.hasChildNodes()) {
297
- hydrateRoot(root, App);
298
- } else {
299
- const rootInstance = createRoot(root);
300
- rootInstance.render(App);
301
- }
302
- } else {
303
- React.startTransition(() => {
304
- hydrateRoot(document, App);
305
- });
306
- }
307
- }
308
- `;
309
- const tempDir = path_1.default.join(root, '.satset');
310
- fs_1.default.mkdirSync(tempDir, { recursive: true });
311
- const entryPath = path_1.default.join(tempDir, '_entry.tsx');
312
- fs_1.default.writeFileSync(entryPath, entryContent);
313
- await bundler_1.bundler.bundle({
314
- entryPoints: [entryPath],
315
- outdir: clientDir,
316
- minify,
317
- sourcemap: false,
318
- watch: false,
319
- root,
320
- });
321
- const appDir = path_1.default.join(root, 'src/app');
322
- const cssFiles = findFiles(appDir, '.css');
323
- for (const cssFile of cssFiles) {
324
- const dest = path_1.default.join(clientDir, path_1.default.basename(cssFile));
325
- fs_1.default.copyFileSync(cssFile, dest);
326
- }
327
- console.log('✅ Client bundle built');
328
- }
329
- async function buildServerBundle(root, outdir, routes, minify) {
330
- const serverDir = path_1.default.join(outdir, 'server');
331
- fs_1.default.mkdirSync(serverDir, { recursive: true });
332
- const dictionaries = getDictionaries(root);
333
- const serverEntry = `
334
- import React from 'react';
335
- import { renderToString } from 'react-dom/server';
336
- import { I18nProvider } from 'satset-react';
337
-
338
- ${routes.map((route, idx) => {
339
- const relativePath = path_1.default.relative(root, route.component).replace(/\\/g, '/');
340
- return `import * as Page${idx} from '../${relativePath}';`;
341
- }).join('\n')}
342
-
343
- const dictionaries = ${JSON.stringify(dictionaries)};
344
-
345
- const routeDefs = [
346
- ${routes.map((route, idx) => ` { path: '${route.path}', module: Page${idx} },`).join('\n')}
347
- ];
348
-
349
- function getComponentFromModule(m) {
350
- if (!m) return null;
351
- if (typeof m.default === 'function') return m.default;
352
- for (const k of Object.keys(m)) {
353
- if (typeof m[k] === 'function') return m[k];
354
- }
355
- return null;
356
- }
357
-
358
- function matchPath(pathname) {
359
- const normalized = stripLocale(pathname);
360
- const pathSegments = normalized.split('/').filter(Boolean);
361
- for (const r of routeDefs) {
362
- const routeSegments = r.path.split('/').filter(Boolean);
363
-
364
- if (r.path.includes('*')) {
365
- const catchIndex = routeSegments.findIndex(s => s.startsWith('*'));
366
- const paramName = routeSegments[catchIndex].slice(1);
367
- const params = {};
368
- params[paramName] = pathSegments.slice(catchIndex).join('/');
369
- return { module: r.module, params };
370
- }
371
-
372
- if (routeSegments.length !== pathSegments.length) continue;
373
-
374
- let matched = true;
375
- const params = {};
376
-
377
- for (let i = 0; i < routeSegments.length; i++) {
378
- const rs = routeSegments[i];
379
- const ps = pathSegments[i];
380
-
381
- if (rs.startsWith(':')) {
382
- params[rs.slice(1)] = ps;
383
- } else if (rs !== ps) {
384
- matched = false;
385
- break;
386
- }
387
- }
388
-
389
- if (matched) {
390
- return { module: r.module, params };
391
- }
392
- }
393
-
394
- return null;
395
- }
396
-
397
- function stripLocale(pathname) {
398
- if (!pathname) return '/';
399
- const raw = pathname.split('?')[0].split('#')[0];
400
- const segments = raw.split('/').filter(Boolean);
401
- if (!segments.length) return '/';
402
- const first = segments[0];
403
- const localePattern = /^[a-zA-Z]{2}(?:-[a-zA-Z]{2})?$/;
404
- if (localePattern.test(first)) {
405
- const rest = segments.slice(1);
406
- return rest.length ? '/' + rest.join('/') : '/';
407
- }
408
- return raw.startsWith('/') ? raw : '/' + raw;
409
- }
410
-
411
- export function renderPage(pathname) {
412
- const match = matchPath(pathname);
413
- if (!match || !match.module) return null;
414
- const PageComponent = getComponentFromModule(match.module);
415
- const params = match.params || {};
416
- if (!PageComponent) return null;
417
-
418
- const segments = pathname.split('/').filter(Boolean);
419
- const first = segments[0];
420
- const locale = (first && /^[a-zA-Z]{2}(?:-[a-zA-Z]{2})?$/.test(first)) ? first : 'en-US';
421
-
422
- return renderToString(
423
- React.createElement(I18nProvider, { initialLocale: locale, dictionaries },
424
- React.createElement(PageComponent, { params })
425
- )
426
- );
427
- }
428
-
429
- export function getMetadataForPath(pathname) {
430
- const match = matchPath(pathname);
431
- if (!match || !match.module) return null;
432
- const m = match.module;
433
-
434
- const segments = pathname.split('/').filter(Boolean);
435
- const first = segments[0];
436
- const locale = (first && /^[a-zA-Z]{2}(?:-[a-zA-Z]{2})?$/.test(first)) ? first : 'en-US';
437
-
438
- const t = (key, params) => {
439
- const dict = dictionaries[locale] || dictionaries['en-US'] || {};
440
- let text = dict[key] || key;
441
- if (params) {
442
- Object.entries(params).forEach(([k, v]) => {
443
- text = text.replace(new RegExp('{' + k + '}', 'g'), v);
444
- });
445
- }
446
- return text;
447
- };
448
-
449
- if (m && m.metadata) return m.metadata;
450
- if (m && typeof m.getMetadata === 'function') {
451
- try { return m.getMetadata({ params: match.params || {}, locale, t }); } catch (e) { return null; }
452
- }
453
- return null;
454
- }
455
-
456
- export { routeDefs as routes, dictionaries };
457
- `;
458
- const tempDir = path_1.default.join(root, '.satset');
459
- const serverEntryPath = path_1.default.join(tempDir, '_server.tsx');
460
- fs_1.default.writeFileSync(serverEntryPath, serverEntry);
461
- await bundler_1.bundler.bundleServer({
462
- entryPoint: serverEntryPath,
463
- outfile: path_1.default.join(serverDir, 'render.js'),
464
- minify,
465
- });
466
- console.log('✅ Server bundle built');
467
- }
468
- async function bundleSeoFiles(root, distPath, minify) {
469
- const seoFiles = [
470
- { name: 'sitemap', entry: ['sitemap.ts', 'sitemap.js', 'sitemap.tsx'] },
471
- { name: 'robots', entry: ['robots.ts', 'robots.js'] },
472
- ];
473
- const serverDist = path_1.default.join(distPath, 'server');
474
- if (!fs_1.default.existsSync(serverDist))
475
- fs_1.default.mkdirSync(serverDist, { recursive: true });
476
- for (const file of seoFiles) {
477
- let entryPoint = null;
478
- for (const ext of file.entry) {
479
- const p = path_1.default.join(root, 'src', ext);
480
- if (fs_1.default.existsSync(p)) {
481
- entryPoint = p;
482
- break;
483
- }
484
- }
485
- if (entryPoint) {
486
- console.log(` - Bundling ${path_1.default.basename(entryPoint)}...`);
487
- const b = new bundler_1.Bundler();
488
- await b.bundleServer({
489
- entryPoint,
490
- outfile: path_1.default.join(serverDist, `${file.name}.js`),
491
- root,
492
- minify,
493
- });
494
- }
495
- }
496
- }
497
- function generateProductionServer(distPath, routes, apiRoutes, env) {
498
- const envScript = (0, env_1.getPublicEnvScript)(env.publicVars || {});
499
- const serverCode = `
500
- const http = require('http');
501
- const fs = require('fs');
502
- const path = require('path');
503
-
504
- ${Object.entries(env.privateVars || {}).map(([key, value]) => `process.env.${key} = '${value}';`).join('\n')}
505
-
506
- const PORT = process.env.PORT || 3000;
507
- const HOST = process.env.HOST || '0.0.0.0';
508
-
509
- const { renderPage, routes, getMetadataForPath, dictionaries } = require('./server/render.js');
510
- const { generateSitemapXml, generateSitemap, generateRobotsTxtFromData, generateRobotsTxt } = require('satset-react/assets');
511
-
512
- function stripLocale(pathname) {
513
- if (!pathname) return '/';
514
- const raw = pathname.split('?')[0].split('#')[0];
515
- const segments = raw.split('/').filter(Boolean);
516
- if (!segments.length) return '/';
517
- const first = segments[0];
518
- const localePattern = /^[a-zA-Z]{2}(?:-[a-zA-Z]{2})?$/;
519
- if (localePattern.test(first)) {
520
- const rest = segments.slice(1);
521
- return rest.length ? '/' + rest.join('/') : '/';
522
- }
523
- return raw.startsWith('/') ? raw : '/' + raw;
524
- }
525
-
526
- const server = http.createServer(async (req, res) => {
527
- const url = req.url || '/';
528
- const pathOnly = url.split('?')[0].split('#')[0];
529
- const normalizedPath = stripLocale(pathOnly);
530
- console.log(req.method + ' ' + url);
531
-
532
- // Helper to get base URL
533
- const getBaseUrl = () => {
534
- if (process.env.SATSET_PUBLIC_SITE_URL) return process.env.SATSET_PUBLIC_SITE_URL;
535
- const host = req.headers.host || 'localhost';
536
- const proto = (req.headers['x-forwarded-proto']) || 'http';
537
- return proto + '://' + host;
538
- };
539
-
540
- // Sitemap.xml Handler
541
- if (pathOnly === '/sitemap.xml') {
542
- try {
543
- const sitemapPath = path.join(__dirname, 'server', 'sitemap.js');
544
- if (fs.existsSync(sitemapPath)) {
545
- const mod = require(sitemapPath);
546
- const fn = mod.default;
547
- if (typeof fn === 'function' && generateSitemapXml) {
548
- const data = await fn();
549
- const xml = generateSitemapXml(data);
550
- res.writeHead(200, { 'Content-Type': 'application/xml' });
551
- res.end(xml);
552
- return;
553
- }
554
- }
555
-
556
- // Fallback
557
- if (generateSitemap) {
558
- const xml = generateSitemap({ baseUrl: getBaseUrl(), routes });
559
- res.writeHead(200, { 'Content-Type': 'application/xml' });
560
- res.end(xml);
561
- return;
562
- }
563
- } catch (e) {
564
- console.error('Error generating sitemap:', e);
565
- res.writeHead(500);
566
- res.end('Error generating sitemap');
567
- return;
568
- }
569
- }
570
-
571
- // Robots.txt Handler
572
- if (pathOnly === '/robots.txt') {
573
- try {
574
- const robotsPath = path.join(__dirname, 'server', 'robots.js');
575
- if (fs.existsSync(robotsPath)) {
576
- const mod = require(robotsPath);
577
- const fn = mod.default;
578
- if (typeof fn === 'function' && generateRobotsTxtFromData) {
579
- const data = await fn();
580
- const txt = generateRobotsTxtFromData(data);
581
- res.writeHead(200, { 'Content-Type': 'text/plain' });
582
- res.end(txt);
583
- return;
584
- }
585
- }
586
-
587
- // Fallback
588
- if (generateRobotsTxt) {
589
- const txt = generateRobotsTxt();
590
- res.writeHead(200, { 'Content-Type': 'text/plain' });
591
- res.end(txt);
592
- return;
593
- }
594
- } catch (e) {
595
- console.error('Error generating robots.txt:', e);
596
- res.writeHead(500);
597
- res.end('Error generating robots.txt');
598
- return;
599
- }
600
- }
601
-
602
- if (url.startsWith('/client/')) {
603
- serveStatic(path.join(__dirname, url), res);
604
- return;
605
- }
606
-
607
- if (url.startsWith('/public/')) {
608
- serveStatic(path.join(__dirname, url), res);
609
- return;
610
- }
611
-
612
- const apiRoute = ${JSON.stringify(apiRoutes)}.find(r => r.path === normalizedPath);
613
- if (apiRoute) {
614
- handleApiRoute(apiRoute, req, res);
615
- return;
616
- }
617
-
618
- const pageHTML = renderPage(url);
619
- if (pageHTML) {
620
- // Page found, assemble HTML and return
621
- let metaHtml = '';
622
- let htmlLang = 'en';
623
- try {
624
- const metaObj = await getMetadataForPath(url);
625
- const metadataAsset = require('./assets/metadata');
626
- if (metaObj && typeof metaObj.lang === 'string' && metaObj.lang.trim()) {
627
- htmlLang = metaObj.lang.trim();
628
- }
629
- metaHtml = metadataAsset.renderMetaTags(metaObj);
630
- } catch (e) {
631
- metaHtml = '';
632
- }
633
-
634
- const html = '<!DOCTYPE html>' +
635
- '<html lang="' + htmlLang + '">' +
636
- '<head>' +
637
- metaHtml +
638
- '<meta charset="UTF-8" />' +
639
- '<meta name="viewport" content="width=device-width, initial-scale=1.0" />' +
640
- '<link rel="stylesheet" href="/client/globals.css" />' +
641
- '</head>' +
642
- '<body>' +
643
- '<div id="root">' + pageHTML + '</div>' +
644
- '<script>' + envScript + '</script>' +
645
- '<script>window.__SATSET_DICTIONARIES__ = ' + JSON.stringify(dictionaries) + ';</script>' +
646
- '<script type="module" src="/client/_entry.js"></script>' +
647
- '</body>' +
648
- '</html>';
649
-
650
- res.writeHead(200, { 'Content-Type': 'text/html' });
651
- res.end(html);
652
- return;
653
- }
654
-
655
- res.writeHead(404, { 'Content-Type': 'text/html' });
656
- res.end('<h1>404 - Page Not Found</h1>');
657
- });
658
-
659
- function serveStatic(filePath, res) {
660
- if (!fs.existsSync(filePath)) {
661
- res.writeHead(404);
662
- res.end('Not Found');
663
- return;
664
- }
665
-
666
- const ext = path.extname(filePath);
667
- const contentType = getContentType(ext);
668
-
669
- res.writeHead(200, { 'Content-Type': contentType });
670
- fs.createReadStream(filePath).pipe(res);
671
- }
672
-
673
- function handleApiRoute(route, req, res) {
674
- try {
675
- const apiPath = path.join(__dirname, 'api', path.basename(route.component));
676
- delete require.cache[require.resolve(apiPath)];
677
- const handler = require(apiPath);
678
-
679
- if (typeof handler.default === 'function') {
680
- handler.default(req, res);
681
- } else if (typeof handler[req.method] === 'function') {
682
- handler[req.method](req, res);
683
- } else {
684
- res.writeHead(405, { 'Content-Type': 'application/json' });
685
- res.end(JSON.stringify({ error: 'Method not allowed' }));
686
- }
687
- } catch (error) {
688
- res.writeHead(500, { 'Content-Type': 'application/json' });
689
- res.end(JSON.stringify({ error: error.message }));
690
- }
691
- }
692
-
693
- function handlePageRoute(pathname, req, res) {
694
- try {
695
- const pageHTML = renderPage(pathname);
696
-
697
- const html = \`
698
- <!DOCTYPE html>
699
- <html lang="en">
700
- <head>
701
- <meta charset="UTF-8" />
702
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
703
- <title>Satset App</title>
704
- <link rel="stylesheet" href="/client/globals.css" />
705
- </head>
706
- <body>
707
- <div id="root">\${pageHTML}</div>
708
- <script>${envScript}</script>
709
- <script type="module" src="/client/_entry.js"></script>
710
- </body>
711
- </html>
712
- \`;
713
-
714
- res.writeHead(200, { 'Content-Type': 'text/html' });
715
- res.end(html);
716
- } catch (error) {
717
- res.writeHead(500, { 'Content-Type': 'text/html' });
718
- res.end(\`<h1>Error</h1><pre>\${error.stack}</pre>\`);
719
- }
720
- }
721
-
722
- function getContentType(ext) {
723
- const types = {
724
- '.html': 'text/html',
725
- '.css': 'text/css',
726
- '.js': 'application/javascript',
727
- '.json': 'application/json',
728
- '.png': 'image/png',
729
- '.jpg': 'image/jpeg',
730
- '.svg': 'image/svg+xml',
731
- '.xml': 'application/xml',
732
- };
733
- return types[ext] || 'text/plain';
734
- }
735
-
736
- if (require.main === module) {
737
- server.listen(PORT, HOST, () => {
738
- console.log(\`✅ Server running at http://\${HOST}:\${PORT}\`);
739
- });
740
- }
741
-
742
- module.exports = server;
743
- `;
744
- fs_1.default.writeFileSync(path_1.default.join(distPath, 'server.js'), serverCode);
745
- }
746
- function findFiles(dir, ext) {
747
- const files = [];
748
- if (!fs_1.default.existsSync(dir))
749
- return files;
750
- const items = fs_1.default.readdirSync(dir);
751
- for (const item of items) {
752
- const fullPath = path_1.default.join(dir, item);
753
- const stat = fs_1.default.statSync(fullPath);
754
- if (stat.isDirectory()) {
755
- files.push(...findFiles(fullPath, ext));
756
- }
757
- else if (fullPath.endsWith(ext)) {
758
- files.push(fullPath);
759
- }
760
- }
761
- return files;
762
- }
763
- function copyFolderRecursive(source, target) {
764
- if (!fs_1.default.existsSync(target)) {
765
- fs_1.default.mkdirSync(target, { recursive: true });
766
- }
767
- const files = fs_1.default.readdirSync(source);
768
- for (const file of files) {
769
- const sourcePath = path_1.default.join(source, file);
770
- const targetPath = path_1.default.join(target, file);
771
- const stat = fs_1.default.statSync(sourcePath);
772
- if (stat.isDirectory()) {
773
- copyFolderRecursive(sourcePath, targetPath);
774
- }
775
- else {
776
- fs_1.default.copyFileSync(sourcePath, targetPath);
777
- }
778
- }
779
- }
780
- //# sourceMappingURL=build.js.map