blumenjs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,129 @@
1
+ // cli/commands/start.ts
2
+ import { spawn } from "child_process";
3
+ import * as fs from "fs";
4
+
5
+ // cli/utils.ts
6
+ var c = {
7
+ reset: "\x1B[0m",
8
+ bold: "\x1B[1m",
9
+ dim: "\x1B[2m",
10
+ red: "\x1B[31m",
11
+ green: "\x1B[32m",
12
+ yellow: "\x1B[33m",
13
+ blue: "\x1B[34m",
14
+ magenta: "\x1B[35m",
15
+ cyan: "\x1B[36m",
16
+ white: "\x1B[37m",
17
+ gray: "\x1B[90m"
18
+ };
19
+ var log = {
20
+ info: (msg) => console.log(` ${c.magenta}\u25CF${c.reset} ${msg}`),
21
+ success: (msg) => console.log(` ${c.green}\u2713${c.reset} ${msg}`),
22
+ error: (msg) => console.error(` ${c.red}\u2717${c.reset} ${msg}`),
23
+ warn: (msg) => console.log(` ${c.yellow}\u26A0${c.reset} ${msg}`),
24
+ step: (msg) => console.log(` ${c.dim}\u2192${c.reset} ${msg}`),
25
+ blank: () => console.log("")
26
+ };
27
+ function banner() {
28
+ console.log("");
29
+ console.log(
30
+ ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v0.1.0${c.reset}`
31
+ );
32
+ console.log(
33
+ ` ${c.dim}The React framework powered by Go${c.reset}`
34
+ );
35
+ console.log("");
36
+ }
37
+ function divider() {
38
+ console.log(` ${c.dim}${"\u2500".repeat(48)}${c.reset}`);
39
+ }
40
+
41
+ // cli/commands/start.ts
42
+ async function start() {
43
+ banner();
44
+ if (!fs.existsSync("dist/ssr-server.js")) {
45
+ log.error("Production build not found.");
46
+ log.info(
47
+ `Run ${c.bold}blumen build${c.reset} first to create a production build.`
48
+ );
49
+ process.exit(1);
50
+ }
51
+ log.info("Starting production server...");
52
+ log.blank();
53
+ const services = [
54
+ {
55
+ name: "ssr",
56
+ label: "ssr",
57
+ color: c.cyan,
58
+ cmd: "node",
59
+ args: ["dist/ssr-server.js"],
60
+ readyPattern: /SSR server running|listening/i
61
+ },
62
+ {
63
+ name: "go",
64
+ label: " go",
65
+ color: c.green,
66
+ cmd: "go",
67
+ args: ["run", "go-server/main.go"],
68
+ readyPattern: /Go server starting/
69
+ }
70
+ ];
71
+ const children = [];
72
+ const ready = /* @__PURE__ */ new Set();
73
+ for (const svc of services) {
74
+ const child = spawn(svc.cmd, svc.args, {
75
+ cwd: process.cwd(),
76
+ env: { ...process.env, NODE_ENV: "production" },
77
+ stdio: ["inherit", "pipe", "pipe"]
78
+ });
79
+ const prefix = ` ${svc.color}\u2502${c.reset} ${svc.color}${svc.label}${c.reset} `;
80
+ const handleOutput = (data) => {
81
+ for (const line of data.toString().split("\n")) {
82
+ const trimmed = line.replace(/\r$/, "");
83
+ if (!trimmed)
84
+ continue;
85
+ console.log(`${prefix}${trimmed}`);
86
+ if (svc.readyPattern && svc.readyPattern.test(trimmed) && !ready.has(svc.name)) {
87
+ ready.add(svc.name);
88
+ if (ready.size === services.length) {
89
+ log.blank();
90
+ divider();
91
+ log.blank();
92
+ log.success(
93
+ `${c.bold}Production server running.${c.reset}`
94
+ );
95
+ console.log(
96
+ ` ${c.dim}\u279C${c.reset} ${c.cyan}http://localhost:3000${c.reset}`
97
+ );
98
+ log.blank();
99
+ }
100
+ }
101
+ }
102
+ };
103
+ child.stdout?.on("data", handleOutput);
104
+ child.stderr?.on("data", handleOutput);
105
+ children.push(child);
106
+ }
107
+ const shutdown = () => {
108
+ log.blank();
109
+ log.info("Shutting down...");
110
+ for (const child of children) {
111
+ if (!child.killed)
112
+ child.kill("SIGTERM");
113
+ }
114
+ setTimeout(() => {
115
+ for (const child of children) {
116
+ if (!child.killed)
117
+ child.kill("SIGKILL");
118
+ }
119
+ process.exit(0);
120
+ }, 3e3);
121
+ };
122
+ process.on("SIGINT", shutdown);
123
+ process.on("SIGTERM", shutdown);
124
+ await new Promise(() => {
125
+ });
126
+ }
127
+ export {
128
+ start
129
+ };
@@ -0,0 +1,85 @@
1
+ // cli/utils.ts
2
+ var c = {
3
+ reset: "\x1B[0m",
4
+ bold: "\x1B[1m",
5
+ dim: "\x1B[2m",
6
+ red: "\x1B[31m",
7
+ green: "\x1B[32m",
8
+ yellow: "\x1B[33m",
9
+ blue: "\x1B[34m",
10
+ magenta: "\x1B[35m",
11
+ cyan: "\x1B[36m",
12
+ white: "\x1B[37m",
13
+ gray: "\x1B[90m"
14
+ };
15
+ var log = {
16
+ info: (msg) => console.log(` ${c.magenta}\u25CF${c.reset} ${msg}`),
17
+ success: (msg) => console.log(` ${c.green}\u2713${c.reset} ${msg}`),
18
+ error: (msg) => console.error(` ${c.red}\u2717${c.reset} ${msg}`),
19
+ warn: (msg) => console.log(` ${c.yellow}\u26A0${c.reset} ${msg}`),
20
+ step: (msg) => console.log(` ${c.dim}\u2192${c.reset} ${msg}`),
21
+ blank: () => console.log("")
22
+ };
23
+ function banner() {
24
+ console.log("");
25
+ console.log(
26
+ ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v0.1.0${c.reset}`
27
+ );
28
+ console.log(
29
+ ` ${c.dim}The React framework powered by Go${c.reset}`
30
+ );
31
+ console.log("");
32
+ }
33
+ function divider() {
34
+ console.log(` ${c.dim}${"\u2500".repeat(48)}${c.reset}`);
35
+ }
36
+ async function select(question, options) {
37
+ const readline = await import("readline");
38
+ const rl = readline.createInterface({
39
+ input: process.stdin,
40
+ output: process.stdout
41
+ });
42
+ return new Promise((resolve) => {
43
+ console.log(`
44
+ ${c.bold}${question}${c.reset}`);
45
+ options.forEach((opt, i) => {
46
+ console.log(` ${c.cyan}${i + 1}${c.reset}) ${opt}`);
47
+ });
48
+ rl.question(`
49
+ ${c.dim}Enter choice [1-${options.length}]:${c.reset} `, (answer) => {
50
+ rl.close();
51
+ const idx = parseInt(answer, 10) - 1;
52
+ if (idx >= 0 && idx < options.length) {
53
+ resolve(options[idx]);
54
+ } else {
55
+ resolve(options[0]);
56
+ }
57
+ });
58
+ });
59
+ }
60
+ async function confirm(question, defaultYes = true) {
61
+ const readline = await import("readline");
62
+ const rl = readline.createInterface({
63
+ input: process.stdin,
64
+ output: process.stdout
65
+ });
66
+ const hint = defaultYes ? "Y/n" : "y/N";
67
+ return new Promise((resolve) => {
68
+ rl.question(` ${c.bold}${question}${c.reset} ${c.dim}(${hint})${c.reset} `, (answer) => {
69
+ rl.close();
70
+ const a = answer.trim().toLowerCase();
71
+ if (a === "")
72
+ resolve(defaultYes);
73
+ else
74
+ resolve(a === "y" || a === "yes");
75
+ });
76
+ });
77
+ }
78
+ export {
79
+ banner,
80
+ c,
81
+ confirm,
82
+ divider,
83
+ log,
84
+ select
85
+ };
@@ -0,0 +1,41 @@
1
+ import React from "react";
2
+ import { hydrateRoot } from "react-dom/client";
3
+ import NotFoundPage from "../pages/NotFound";
4
+
5
+ // Auto-generated route map (run `npm run routes` to regenerate)
6
+ import { routes, App } from "./generated-routes";
7
+ import { RouterProvider } from "../shared/RouterContext";
8
+
9
+ function init() {
10
+ const container = document.getElementById("root");
11
+ if (!container) {
12
+ console.error("Root element not found");
13
+ return;
14
+ }
15
+
16
+ // Get props from server (used for the initial SSR hydration)
17
+ const propsElement = document.getElementById("ssr-props");
18
+ const propsText = propsElement?.textContent?.trim();
19
+ const initialProps = propsText ? JSON.parse(propsText) : {};
20
+
21
+ // Hydrate the app with the RouterProvider.
22
+ // The provider handles route matching, page rendering, and SPA navigation.
23
+ hydrateRoot(
24
+ container,
25
+ <RouterProvider
26
+ routes={routes}
27
+ App={App}
28
+ notFoundComponent={NotFoundPage}
29
+ initialProps={initialProps}
30
+ />,
31
+ );
32
+
33
+ console.log("Hydrated with client-side router:", window.location.pathname);
34
+ }
35
+
36
+ // Initialize when DOM is ready
37
+ if (document.readyState === "loading") {
38
+ document.addEventListener("DOMContentLoaded", init);
39
+ } else {
40
+ init();
41
+ }
@@ -0,0 +1,398 @@
1
+ import React from "react";
2
+
3
+ interface HomeProps {
4
+ timestamp?: number;
5
+ serverRendered?: boolean;
6
+ }
7
+
8
+ const HomePage: React.FC<HomeProps> = () => {
9
+ return (
10
+ <>
11
+ <style
12
+ dangerouslySetInnerHTML={{
13
+ __html: `
14
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
15
+
16
+ @keyframes float {
17
+ 0%, 100% { transform: translateY(0px) rotate(0deg); opacity: 0.3; }
18
+ 50% { transform: translateY(-30px) rotate(5deg); opacity: 0.6; }
19
+ }
20
+
21
+ @keyframes pulse-glow {
22
+ 0%, 100% { box-shadow: 0 0 40px rgba(168, 85, 247, 0.15); }
23
+ 50% { box-shadow: 0 0 80px rgba(168, 85, 247, 0.3); }
24
+ }
25
+
26
+ @keyframes gradient-shift {
27
+ 0% { background-position: 0% 50%; }
28
+ 50% { background-position: 100% 50%; }
29
+ 100% { background-position: 0% 50%; }
30
+ }
31
+
32
+ @keyframes fade-up {
33
+ from { opacity: 0; transform: translateY(30px); }
34
+ to { opacity: 1; transform: translateY(0); }
35
+ }
36
+
37
+ @keyframes shimmer {
38
+ 0% { background-position: -200% center; }
39
+ 100% { background-position: 200% center; }
40
+ }
41
+
42
+ .blumen-home * { box-sizing: border-box; margin: 0; padding: 0; }
43
+
44
+ .blumen-home {
45
+ min-height: 100vh;
46
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
47
+ background: #0a0612;
48
+ color: #e2e8f0;
49
+ overflow-x: hidden;
50
+ position: relative;
51
+ }
52
+
53
+ .blumen-bg {
54
+ position: fixed;
55
+ inset: 0;
56
+ background:
57
+ radial-gradient(ellipse 80% 60% at 50% 0%, rgba(88, 28, 135, 0.25), transparent),
58
+ radial-gradient(ellipse 60% 50% at 80% 50%, rgba(139, 92, 246, 0.1), transparent),
59
+ radial-gradient(ellipse 50% 40% at 20% 80%, rgba(168, 85, 247, 0.08), transparent);
60
+ pointer-events: none;
61
+ }
62
+
63
+ .blumen-orb {
64
+ position: absolute;
65
+ border-radius: 50%;
66
+ filter: blur(80px);
67
+ pointer-events: none;
68
+ }
69
+
70
+ .blumen-orb-1 {
71
+ width: 500px; height: 500px;
72
+ background: rgba(139, 92, 246, 0.12);
73
+ top: -100px; right: -100px;
74
+ animation: float 12s ease-in-out infinite;
75
+ }
76
+
77
+ .blumen-orb-2 {
78
+ width: 400px; height: 400px;
79
+ background: rgba(168, 85, 247, 0.08);
80
+ bottom: -80px; left: -80px;
81
+ animation: float 15s ease-in-out infinite 3s;
82
+ }
83
+
84
+ .blumen-orb-3 {
85
+ width: 300px; height: 300px;
86
+ background: rgba(192, 132, 252, 0.06);
87
+ top: 40%; left: 60%;
88
+ animation: float 18s ease-in-out infinite 6s;
89
+ }
90
+
91
+ .blumen-grid-overlay {
92
+ position: fixed;
93
+ inset: 0;
94
+ background-image:
95
+ linear-gradient(rgba(139, 92, 246, 0.03) 1px, transparent 1px),
96
+ linear-gradient(90deg, rgba(139, 92, 246, 0.03) 1px, transparent 1px);
97
+ background-size: 60px 60px;
98
+ pointer-events: none;
99
+ }
100
+
101
+ .blumen-content {
102
+ position: relative;
103
+ z-index: 1;
104
+ display: flex;
105
+ flex-direction: column;
106
+ align-items: center;
107
+ justify-content: center;
108
+ min-height: 100vh;
109
+ padding: 4rem 2rem;
110
+ }
111
+
112
+ .blumen-badge {
113
+ display: inline-flex;
114
+ align-items: center;
115
+ gap: 8px;
116
+ padding: 6px 16px;
117
+ border-radius: 100px;
118
+ background: rgba(139, 92, 246, 0.1);
119
+ border: 1px solid rgba(139, 92, 246, 0.2);
120
+ font-size: 0.8rem;
121
+ font-weight: 500;
122
+ color: #c084fc;
123
+ letter-spacing: 0.05em;
124
+ text-transform: uppercase;
125
+ margin-bottom: 2rem;
126
+ animation: fade-up 0.8s ease-out both;
127
+ }
128
+
129
+ .blumen-badge-dot {
130
+ width: 6px; height: 6px;
131
+ background: #a855f7;
132
+ border-radius: 50%;
133
+ animation: pulse-glow 2s ease-in-out infinite;
134
+ }
135
+
136
+ .blumen-logo {
137
+ font-size: clamp(4rem, 8vw, 7rem);
138
+ font-weight: 900;
139
+ line-height: 1.05;
140
+ letter-spacing: -0.03em;
141
+ background: linear-gradient(135deg, #e2e8f0 0%, #c084fc 40%, #a855f7 60%, #7c3aed 100%);
142
+ background-size: 200% 200%;
143
+ -webkit-background-clip: text;
144
+ -webkit-text-fill-color: transparent;
145
+ background-clip: text;
146
+ animation: fade-up 0.8s ease-out 0.15s both, gradient-shift 8s ease infinite;
147
+ margin-bottom: 1.5rem;
148
+ }
149
+
150
+ .blumen-tagline {
151
+ font-size: clamp(1.1rem, 2vw, 1.4rem);
152
+ font-weight: 300;
153
+ color: #94a3b8;
154
+ line-height: 1.7;
155
+ max-width: 560px;
156
+ text-align: center;
157
+ animation: fade-up 0.8s ease-out 0.3s both;
158
+ }
159
+
160
+ .blumen-tagline strong {
161
+ color: #c084fc;
162
+ font-weight: 500;
163
+ }
164
+
165
+ .blumen-cta-row {
166
+ display: flex;
167
+ gap: 16px;
168
+ margin-top: 3rem;
169
+ animation: fade-up 0.8s ease-out 0.45s both;
170
+ flex-wrap: wrap;
171
+ justify-content: center;
172
+ }
173
+
174
+ .blumen-btn-primary {
175
+ display: inline-flex;
176
+ align-items: center;
177
+ gap: 8px;
178
+ padding: 14px 32px;
179
+ border-radius: 12px;
180
+ background: linear-gradient(135deg, #7c3aed, #a855f7);
181
+ color: white;
182
+ font-family: inherit;
183
+ font-size: 0.95rem;
184
+ font-weight: 600;
185
+ border: none;
186
+ cursor: pointer;
187
+ transition: all 0.3s ease;
188
+ text-decoration: none;
189
+ letter-spacing: 0.01em;
190
+ }
191
+
192
+ .blumen-btn-primary:hover {
193
+ transform: translateY(-2px);
194
+ box-shadow: 0 8px 30px rgba(139, 92, 246, 0.4);
195
+ }
196
+
197
+ .blumen-btn-secondary {
198
+ display: inline-flex;
199
+ align-items: center;
200
+ gap: 8px;
201
+ padding: 14px 32px;
202
+ border-radius: 12px;
203
+ background: rgba(139, 92, 246, 0.08);
204
+ color: #c084fc;
205
+ font-family: inherit;
206
+ font-size: 0.95rem;
207
+ font-weight: 500;
208
+ border: 1px solid rgba(139, 92, 246, 0.2);
209
+ cursor: pointer;
210
+ transition: all 0.3s ease;
211
+ text-decoration: none;
212
+ }
213
+
214
+ .blumen-btn-secondary:hover {
215
+ background: rgba(139, 92, 246, 0.15);
216
+ border-color: rgba(139, 92, 246, 0.4);
217
+ transform: translateY(-2px);
218
+ }
219
+
220
+ .blumen-code-block {
221
+ margin-top: 3.5rem;
222
+ padding: 20px 28px;
223
+ border-radius: 14px;
224
+ background: rgba(15, 10, 25, 0.8);
225
+ border: 1px solid rgba(139, 92, 246, 0.15);
226
+ font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', monospace;
227
+ font-size: 0.9rem;
228
+ color: #94a3b8;
229
+ animation: fade-up 0.8s ease-out 0.6s both;
230
+ backdrop-filter: blur(12px);
231
+ display: flex;
232
+ align-items: center;
233
+ gap: 12px;
234
+ }
235
+
236
+ .blumen-code-block .prompt { color: #7c3aed; }
237
+ .blumen-code-block .cmd { color: #c084fc; }
238
+ .blumen-code-block .arg { color: #e2e8f0; }
239
+
240
+ .blumen-features {
241
+ display: grid;
242
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
243
+ gap: 20px;
244
+ max-width: 900px;
245
+ width: 100%;
246
+ margin-top: 5rem;
247
+ animation: fade-up 0.8s ease-out 0.75s both;
248
+ }
249
+
250
+ .blumen-feature {
251
+ padding: 28px;
252
+ border-radius: 16px;
253
+ background: rgba(15, 10, 25, 0.6);
254
+ border: 1px solid rgba(139, 92, 246, 0.1);
255
+ backdrop-filter: blur(12px);
256
+ transition: all 0.3s ease;
257
+ }
258
+
259
+ .blumen-feature:hover {
260
+ border-color: rgba(139, 92, 246, 0.3);
261
+ transform: translateY(-4px);
262
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
263
+ }
264
+
265
+ .blumen-feature-icon {
266
+ width: 44px; height: 44px;
267
+ border-radius: 12px;
268
+ background: rgba(139, 92, 246, 0.12);
269
+ display: flex;
270
+ align-items: center;
271
+ justify-content: center;
272
+ font-size: 1.3rem;
273
+ margin-bottom: 16px;
274
+ }
275
+
276
+ .blumen-feature h3 {
277
+ font-size: 1.05rem;
278
+ font-weight: 600;
279
+ color: #e2e8f0;
280
+ margin-bottom: 8px;
281
+ }
282
+
283
+ .blumen-feature p {
284
+ font-size: 0.88rem;
285
+ color: #64748b;
286
+ line-height: 1.6;
287
+ }
288
+
289
+ .blumen-footer {
290
+ margin-top: 5rem;
291
+ padding: 2rem;
292
+ text-align: center;
293
+ color: #475569;
294
+ font-size: 0.82rem;
295
+ animation: fade-up 0.8s ease-out 0.9s both;
296
+ }
297
+
298
+ .blumen-footer a {
299
+ color: #7c3aed;
300
+ text-decoration: none;
301
+ transition: color 0.2s;
302
+ }
303
+
304
+ .blumen-footer a:hover { color: #a855f7; }
305
+ `,
306
+ }}
307
+ />
308
+ <div className="blumen-home">
309
+ {/* Background effects */}
310
+ <div className="blumen-bg" />
311
+ <div className="blumen-orb blumen-orb-1" />
312
+ <div className="blumen-orb blumen-orb-2" />
313
+ <div className="blumen-orb blumen-orb-3" />
314
+ <div className="blumen-grid-overlay" />
315
+
316
+ {/* Main content */}
317
+ <div className="blumen-content">
318
+ <div className="blumen-badge">
319
+ <span className="blumen-badge-dot" />
320
+ Framework v0.1.0
321
+ </div>
322
+
323
+ <h1 className="blumen-logo">๐ŸŒธ Blumen</h1>
324
+
325
+ <p className="blumen-tagline">
326
+ The <strong>React framework</strong> powered by{" "}
327
+ <strong>Go</strong>. Lightning-fast server-side
328
+ rendering with the developer experience you deserve.
329
+ </p>
330
+
331
+ <div className="blumen-cta-row">
332
+ <button className="blumen-btn-primary">
333
+ ๐Ÿ“– Read the Docs
334
+ </button>
335
+ <button className="blumen-btn-secondary">
336
+ โšก Quick Start
337
+ </button>
338
+ </div>
339
+
340
+ <div className="blumen-code-block">
341
+ <span className="prompt">$</span>
342
+ <span className="cmd">npx</span>
343
+ <span className="arg">
344
+ create-blumen-app my-project
345
+ </span>
346
+ </div>
347
+
348
+ {/* Feature cards */}
349
+ <div className="blumen-features">
350
+ <div className="blumen-feature">
351
+ <div className="blumen-feature-icon">โšก</div>
352
+ <h3>Go-Powered SSR</h3>
353
+ <p>
354
+ Your server runs on Go โ€” blazing fast data
355
+ fetching, auth, and API calls at native speed.
356
+ </p>
357
+ </div>
358
+ <div className="blumen-feature">
359
+ <div className="blumen-feature-icon">๐Ÿ”ฅ</div>
360
+ <h3>React Fast Refresh</h3>
361
+ <p>
362
+ Edit a component, see it update instantly.
363
+ No page reload, no lost state. Pure speed.
364
+ </p>
365
+ </div>
366
+ <div className="blumen-feature">
367
+ <div className="blumen-feature-icon">๐Ÿ“</div>
368
+ <h3>File-Based Routing</h3>
369
+ <p>
370
+ Drop a file in{" "}
371
+ <code
372
+ style={{
373
+ color: "#c084fc",
374
+ fontSize: "0.82rem",
375
+ }}
376
+ >
377
+ app/pages/
378
+ </code>
379
+ . It's a route. Dynamic params, nested
380
+ layouts โ€” just works.
381
+ </p>
382
+ </div>
383
+ </div>
384
+
385
+ <div className="blumen-footer">
386
+ <p>
387
+ Built with ๐Ÿ’œ ยท{" "}
388
+ <a href="https://github.com">GitHub</a> ยท MIT
389
+ License
390
+ </p>
391
+ </div>
392
+ </div>
393
+ </div>
394
+ </>
395
+ );
396
+ };
397
+
398
+ export default HomePage;
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { Link } from '../shared/Link';
3
+
4
+ interface NotFoundProps {
5
+ path?: string;
6
+ status?: number;
7
+ serverRendered?: boolean;
8
+ }
9
+
10
+ export const NotFoundPage: React.FC<NotFoundProps> = () => {
11
+ return (
12
+ <div className="not-found">
13
+ <h1>404 - Page Not Found</h1>
14
+ <p>The page you are looking for does not exist.</p>
15
+ <nav className="page-nav">
16
+ <Link href="/" className="nav-link">โ† Go Home</Link>
17
+ </nav>
18
+ </div>
19
+ );
20
+ };
21
+
22
+ export default NotFoundPage;
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+
3
+ export function DefaultApp({ Component, pageProps }: any) {
4
+ return <Component {...pageProps} />;
5
+ }