create-moost 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -63,16 +63,15 @@ async function getPrompts(inputs) {
63
63
  {
64
64
  name: "type",
65
65
  type: () => {
66
- if (inputs.ws && !inputs.cli && !inputs.http) {
67
- predefined.type = "ws";
68
- return null;
69
- }
70
- if (inputs.cli && !inputs.http && !inputs.ws) {
71
- predefined.type = "cli";
72
- return null;
73
- }
74
- if (inputs.http && !inputs.cli && !inputs.ws) {
75
- predefined.type = "http";
66
+ const typeFlags = [
67
+ "http",
68
+ "cli",
69
+ "ws",
70
+ "ssr"
71
+ ];
72
+ const selected = typeFlags.filter((t) => inputs[t]);
73
+ if (selected.length === 1) {
74
+ predefined.type = selected[0];
76
75
  return null;
77
76
  }
78
77
  return "select";
@@ -83,6 +82,10 @@ async function getPrompts(inputs) {
83
82
  title: "HTTP (Web) Application",
84
83
  value: "http"
85
84
  },
85
+ {
86
+ title: "Vue + Moost (SSR/SPA)",
87
+ value: "ssr"
88
+ },
86
89
  {
87
90
  title: "WebSocket Application",
88
91
  value: "ws"
@@ -100,6 +103,18 @@ async function getPrompts(inputs) {
100
103
  initial: () => toValidPackageName(predefined.targetDir),
101
104
  validate: (dir) => isValidPackageName(dir) || "Invalid package.json name"
102
105
  },
106
+ {
107
+ name: "ssr",
108
+ type: (prev, values) => {
109
+ const type = values.type || predefined.type;
110
+ if (type !== "ssr") return null;
111
+ return "toggle";
112
+ },
113
+ message: "Enable SSR (Server-Side Rendering)?",
114
+ initial: true,
115
+ active: "Yes",
116
+ inactive: "No (SPA only)"
117
+ },
103
118
  {
104
119
  name: "ws",
105
120
  type: (prev, values) => {
@@ -176,7 +191,7 @@ async function scaffold(data) {
176
191
  if ((0, fs.existsSync)(projectDir)) {
177
192
  if (data.overwrite) emptyDirectorySync(projectDir);
178
193
  } else (0, fs.mkdirSync)(projectDir);
179
- const templatePath = (0, path.join)(__dirname, "../templates", data.type === "ws" ? "ws" : data.type);
194
+ const templatePath = (0, path.join)(__dirname, "../templates", data.type);
180
195
  const commonPath = (0, path.join)(__dirname, "../templates/common");
181
196
  const wfPath = (0, path.join)(__dirname, "../templates/wf");
182
197
  const wsAddonPath = (0, path.join)(__dirname, "../templates/ws-addon");
@@ -189,13 +204,17 @@ async function scaffold(data) {
189
204
  excludeCommon.push(".oxlintrc.json");
190
205
  excludeCommon.push(".oxfmtrc.json");
191
206
  }
207
+ if (data.type === "ssr") excludeCommon.push("tsconfig.json");
192
208
  const renameFile = (filename) => {
193
209
  if (filename.endsWith(".jsonc")) return filename.replace(/c$/, "");
194
210
  return filename;
195
211
  };
212
+ const excludeTemplate = [];
213
+ if (data.type === "ssr" && !data.ssr) excludeTemplate.push("src/entry-server.ts");
196
214
  await rw.rewriteDir({
197
215
  baseDir: templatePath,
198
216
  output: projectDir,
217
+ exclude: excludeTemplate,
199
218
  renameFile
200
219
  }, context);
201
220
  await rw.rewriteDir({
@@ -256,6 +275,7 @@ let Commands = class Commands$1 extends __moostjs_event_cli.CliApp {
256
275
  cli: !!(0, __wooksjs_event_cli.useCliOption)("cli"),
257
276
  ws: !!(0, __wooksjs_event_cli.useCliOption)("ws"),
258
277
  wf: !!(0, __wooksjs_event_cli.useCliOption)("wf"),
278
+ ssr: !!(0, __wooksjs_event_cli.useCliOption)("ssr"),
259
279
  oxc: !!(0, __wooksjs_event_cli.useCliOption)("oxc"),
260
280
  force: !!(0, __wooksjs_event_cli.useCliOption)("force")
261
281
  });
@@ -263,6 +283,7 @@ let Commands = class Commands$1 extends __moostjs_event_cli.CliApp {
263
283
  await scaffold(prompts$2);
264
284
  const cli = prompts$2.type === "cli";
265
285
  const ws = prompts$2.type === "ws";
286
+ const ssr = prompts$2.type === "ssr";
266
287
  return `
267
288
  Success! Your new "${prompts$2.projectName}" project has been created successfully. 
268
289
 
@@ -282,7 +303,10 @@ ${cli ? "4" : "3"}. ${ws ? "Build and start" : "Start the development server"}:
282
303
 
283
304
  You're all set!${ws ? "" : " The development server will help you in building your application."}
284
305
  Enjoy coding, and build something amazing!
285
- `;
306
+ ${ssr ? `
307
+ Vue app: http://localhost:3000
308
+ API routes: http://localhost:3000/api/hello/World
309
+ ` : ""}`;
286
310
  }
287
311
  };
288
312
  _ts_decorate([
@@ -320,6 +344,11 @@ function run() {
320
344
  description: "Add Workflow Adapter",
321
345
  type: Boolean
322
346
  },
347
+ {
348
+ keys: ["ssr"],
349
+ description: "Vue + Moost (SSR/SPA)",
350
+ type: Boolean
351
+ },
323
352
  {
324
353
  keys: ["oxc"],
325
354
  description: "Add OXC lint and formatter (oxlint + oxfmt)",
package/dist/index.mjs CHANGED
@@ -40,16 +40,15 @@ async function getPrompts(inputs) {
40
40
  {
41
41
  name: "type",
42
42
  type: () => {
43
- if (inputs.ws && !inputs.cli && !inputs.http) {
44
- predefined.type = "ws";
45
- return null;
46
- }
47
- if (inputs.cli && !inputs.http && !inputs.ws) {
48
- predefined.type = "cli";
49
- return null;
50
- }
51
- if (inputs.http && !inputs.cli && !inputs.ws) {
52
- predefined.type = "http";
43
+ const typeFlags = [
44
+ "http",
45
+ "cli",
46
+ "ws",
47
+ "ssr"
48
+ ];
49
+ const selected = typeFlags.filter((t) => inputs[t]);
50
+ if (selected.length === 1) {
51
+ predefined.type = selected[0];
53
52
  return null;
54
53
  }
55
54
  return "select";
@@ -60,6 +59,10 @@ async function getPrompts(inputs) {
60
59
  title: "HTTP (Web) Application",
61
60
  value: "http"
62
61
  },
62
+ {
63
+ title: "Vue + Moost (SSR/SPA)",
64
+ value: "ssr"
65
+ },
63
66
  {
64
67
  title: "WebSocket Application",
65
68
  value: "ws"
@@ -77,6 +80,18 @@ async function getPrompts(inputs) {
77
80
  initial: () => toValidPackageName(predefined.targetDir),
78
81
  validate: (dir) => isValidPackageName(dir) || "Invalid package.json name"
79
82
  },
83
+ {
84
+ name: "ssr",
85
+ type: (prev, values) => {
86
+ const type = values.type || predefined.type;
87
+ if (type !== "ssr") return null;
88
+ return "toggle";
89
+ },
90
+ message: "Enable SSR (Server-Side Rendering)?",
91
+ initial: true,
92
+ active: "Yes",
93
+ inactive: "No (SPA only)"
94
+ },
80
95
  {
81
96
  name: "ws",
82
97
  type: (prev, values) => {
@@ -153,7 +168,7 @@ async function scaffold(data) {
153
168
  if (existsSync(projectDir)) {
154
169
  if (data.overwrite) emptyDirectorySync(projectDir);
155
170
  } else mkdirSync(projectDir);
156
- const templatePath = join(__dirname, "../templates", data.type === "ws" ? "ws" : data.type);
171
+ const templatePath = join(__dirname, "../templates", data.type);
157
172
  const commonPath = join(__dirname, "../templates/common");
158
173
  const wfPath = join(__dirname, "../templates/wf");
159
174
  const wsAddonPath = join(__dirname, "../templates/ws-addon");
@@ -166,13 +181,17 @@ async function scaffold(data) {
166
181
  excludeCommon.push(".oxlintrc.json");
167
182
  excludeCommon.push(".oxfmtrc.json");
168
183
  }
184
+ if (data.type === "ssr") excludeCommon.push("tsconfig.json");
169
185
  const renameFile = (filename) => {
170
186
  if (filename.endsWith(".jsonc")) return filename.replace(/c$/, "");
171
187
  return filename;
172
188
  };
189
+ const excludeTemplate = [];
190
+ if (data.type === "ssr" && !data.ssr) excludeTemplate.push("src/entry-server.ts");
173
191
  await rw.rewriteDir({
174
192
  baseDir: templatePath,
175
193
  output: projectDir,
194
+ exclude: excludeTemplate,
176
195
  renameFile
177
196
  }, context);
178
197
  await rw.rewriteDir({
@@ -233,6 +252,7 @@ let Commands = class Commands$1 extends CliApp {
233
252
  cli: !!useCliOption("cli"),
234
253
  ws: !!useCliOption("ws"),
235
254
  wf: !!useCliOption("wf"),
255
+ ssr: !!useCliOption("ssr"),
236
256
  oxc: !!useCliOption("oxc"),
237
257
  force: !!useCliOption("force")
238
258
  });
@@ -240,6 +260,7 @@ let Commands = class Commands$1 extends CliApp {
240
260
  await scaffold(prompts$1);
241
261
  const cli = prompts$1.type === "cli";
242
262
  const ws = prompts$1.type === "ws";
263
+ const ssr = prompts$1.type === "ssr";
243
264
  return `
244
265
  Success! Your new "${prompts$1.projectName}" project has been created successfully. 
245
266
 
@@ -259,7 +280,10 @@ ${cli ? "4" : "3"}. ${ws ? "Build and start" : "Start the development server"}:
259
280
 
260
281
  You're all set!${ws ? "" : " The development server will help you in building your application."}
261
282
  Enjoy coding, and build something amazing!
262
- `;
283
+ ${ssr ? `
284
+ Vue app: http://localhost:3000
285
+ API routes: http://localhost:3000/api/hello/World
286
+ ` : ""}`;
263
287
  }
264
288
  };
265
289
  _ts_decorate([
@@ -297,6 +321,11 @@ function run() {
297
321
  description: "Add Workflow Adapter",
298
322
  type: Boolean
299
323
  },
324
+ {
325
+ keys: ["ssr"],
326
+ description: "Vue + Moost (SSR/SPA)",
327
+ type: Boolean
328
+ },
300
329
  {
301
330
  keys: ["oxc"],
302
331
  description: "Add OXC lint and formatter (oxlint + oxfmt)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-moost",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "create-moost",
5
5
  "keywords": [
6
6
  "composables",
@@ -43,19 +43,17 @@
43
43
  }
44
44
  },
45
45
  "dependencies": {
46
- "@prostojs/rewrite": "^0.1.1",
47
- "@wooksjs/event-cli": "^0.7.3",
46
+ "@prostojs/rewrite": "^0.2.3",
47
+ "@wooksjs/event-cli": "^0.7.7",
48
48
  "prompts": "^2.4.2",
49
- "moost": "^0.6.1",
50
- "@moostjs/event-cli": "^0.6.1"
49
+ "@moostjs/event-cli": "^0.6.3",
50
+ "moost": "^0.6.3"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/prompts": "^2.4.9",
54
- "rolldown": "1.0.0-beta.19",
55
- "unplugin-swc": "^1.5.9",
56
- "vite": "^6.4.1",
54
+ "vite": "^8.0.0",
57
55
  "vitest": "3.2.4",
58
- "@moostjs/vite": "^0.6.1"
56
+ "@moostjs/vite": "^0.6.3"
59
57
  },
60
58
  "scripts": {
61
59
  "pub": "pnpm publish --access public",
@@ -33,7 +33,6 @@
33
33
  "oxfmt": "^0.34.0",
34
34
  //=END IF
35
35
  "typescript": "^5.7.2",
36
- "unplugin-swc": "^1.5.9",
37
36
  "rolldown": "1.0.0-beta.19"
38
37
  }
39
38
  }
@@ -1,5 +1,4 @@
1
1
  import { defineConfig } from 'rolldown'
2
- import swc from 'unplugin-swc';
3
2
 
4
3
  export default defineConfig({
5
4
  input: 'src/main.ts',
@@ -8,7 +7,4 @@ export default defineConfig({
8
7
  file: 'dist/main.js',
9
8
  },
10
9
  external: ['@moostjs/event-cli', 'moost'],
11
- plugins: [
12
- swc.rolldown(),
13
- ]
14
- })
10
+ })
@@ -4,7 +4,7 @@
4
4
 
5
5
  "target": "ESNext",
6
6
  "module": "ESNext",
7
- "moduleResolution": "node",
7
+ "moduleResolution": "bundler",
8
8
 
9
9
  "experimentalDecorators": true,
10
10
  "emitDecoratorMetadata": true,
@@ -24,7 +24,7 @@
24
24
  //=END IF
25
25
  //=IF (wf)
26
26
  "@moostjs/event-wf": "^{{ version }}",
27
- "@wooksjs/http-static": "^0.7.3",
27
+ "@wooksjs/http-static": "^0.7.4",
28
28
  //=END IF
29
29
  "moost": "^{{ version }}"
30
30
  },
@@ -36,7 +36,6 @@
36
36
  "oxfmt": "^0.34.0",
37
37
  //=END IF
38
38
  "typescript": "^5.7.2",
39
- "unplugin-swc": "^1.5.9",
40
- "vite": "^7.0.0"
39
+ "vite": "^8.0.0"
41
40
  }
42
41
  }
@@ -1,5 +1,4 @@
1
- import { defineConfig } from "vite";
2
- import swc from 'unplugin-swc';
1
+ import { defineConfig } from "vite";
3
2
  import { moostVite } from "@moostjs/vite";
4
3
 
5
4
  export default defineConfig({
@@ -7,7 +6,5 @@ export default defineConfig({
7
6
  moostVite({
8
7
  entry: "/src/main.ts",
9
8
  }),
10
- swc.vite(),
11
9
  ],
12
10
  });
13
-
@@ -0,0 +1,21 @@
1
+ # {{ projectName }}
2
+
3
+ A full-stack application built with [Moost](https://moost.org), [Vite](https://vite.dev), and [Vue](https://vuejs.org).
4
+
5
+ ## Dev
6
+
7
+ ```bash
8
+ npm run dev
9
+ ```
10
+
11
+ ## Build
12
+
13
+ ```bash
14
+ npm run build
15
+ ```
16
+
17
+ ## Start (production)
18
+
19
+ ```bash
20
+ npm run start
21
+ ```
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{ projectName }}</title>
7
+ <style>
8
+ body { margin: 0; background: #151e38; }
9
+ </style>
10
+ </head>
11
+ <body>
12
+ <div id="app"><!--ssr-outlet--></div>
13
+ <!--ssr-state-->
14
+ <script type="module" src="/src/entry-client.ts"></script>
15
+ </body>
16
+ </html>
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "{{ packageName }}",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "tsx server.ts",
8
+ "build": "vite build",
9
+ "start": "node dist/server.js",
10
+ "preview": "node dist/server.js",
11
+ //=IF (oxc)
12
+ "lint": "oxlint",
13
+ "format": "oxfmt .",
14
+ "format:check": "oxfmt --check .",
15
+ //=END IF
16
+ "test": "echo \"Error: no test specified\" && exit 1"
17
+ },
18
+ "keywords": [],
19
+ "author": "",
20
+ "license": "ISC",
21
+ "dependencies": {
22
+ "@moostjs/event-http": "^{{ version }}",
23
+ "@moostjs/vite": "^{{ version }}",
24
+ "moost": "^{{ version }}",
25
+ "sirv": "^3.0.2",
26
+ "vue": "^3.5.0",
27
+ "vue-router": "^4.5.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.10.2",
31
+ "@vitejs/plugin-vue": "^6.0.5",
32
+ //=IF (oxc)
33
+ "oxlint": "^1.49.0",
34
+ "oxfmt": "^0.34.0",
35
+ //=END IF
36
+ "tsx": "^4.19.0",
37
+ "typescript": "^5.7.2",
38
+ "vite": "^8.0.0"
39
+ }
40
+ }
@@ -0,0 +1,12 @@
1
+ <svg width="356" height="140" viewBox="0 0 356 140" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_438_169)">
3
+ <path d="M9.64 115V51.28H27.88L28.48 64.72L25 63.88C26.04 61.96 27.4 60.16 29.08 58.48C30.84 56.8 32.8 55.36 34.96 54.16C37.2 52.88 39.6 51.88 42.16 51.16C44.72 50.44 47.48 50.08 50.44 50.08C53.88 50.08 57.04 50.6 59.92 51.64C62.88 52.68 65.4 54.4 67.48 56.8C69.56 59.12 71.16 62.24 72.28 66.16L68.32 65.68L69.28 63.76C70.56 61.92 72.08 60.2 73.84 58.6C75.68 56.92 77.76 55.48 80.08 54.28C82.4 53 84.88 52 87.52 51.28C90.16 50.48 92.88 50.08 95.68 50.08C101.52 50.08 106.28 51.2 109.96 53.44C113.64 55.6 116.36 58.68 118.12 62.68C119.88 66.68 120.76 71.32 120.76 76.6V115H101.44V78.64C101.44 76.08 101.04 73.88 100.24 72.04C99.44 70.2 98.2 68.8 96.52 67.84C94.92 66.8 92.84 66.28 90.28 66.28C88.04 66.28 85.96 66.64 84.04 67.36C82.2 68.08 80.56 69.08 79.12 70.36C77.76 71.56 76.68 73 75.88 74.68C75.16 76.28 74.8 78.04 74.8 79.96V115H55.48V78.52C55.48 76.04 55.04 73.88 54.16 72.04C53.28 70.2 51.92 68.8 50.08 67.84C48.24 66.8 45.96 66.28 43.24 66.28C41.08 66.28 39.12 66.68 37.36 67.48C35.68 68.2 34.2 69.2 32.92 70.48C31.64 71.68 30.64 73 29.92 74.44C29.28 75.88 28.96 77.36 28.96 78.88V115H9.64ZM273.572 116.2C266.532 116.2 260.212 115.2 254.612 113.2C249.092 111.2 244.652 108.36 241.292 104.68L252.932 94.36C255.652 96.92 258.892 98.88 262.652 100.24C266.412 101.6 270.372 102.28 274.532 102.28C275.812 102.28 277.052 102.16 278.252 101.92C279.532 101.68 280.612 101.36 281.492 100.96C282.452 100.48 283.212 99.92 283.772 99.28C284.332 98.64 284.612 97.84 284.612 96.88C284.612 95.36 283.652 94.16 281.732 93.28C280.372 92.8 278.652 92.32 276.572 91.84C274.492 91.36 272.132 90.84 269.492 90.28C265.092 89.48 261.212 88.52 257.852 87.4C254.572 86.2 251.812 84.72 249.572 82.96C247.652 81.28 246.172 79.36 245.132 77.2C244.092 75.04 243.572 72.52 243.572 69.64C243.572 66.68 244.332 64 245.852 61.6C247.372 59.12 249.492 57.04 252.212 55.36C254.932 53.6 258.052 52.28 261.572 51.4C265.092 50.44 268.772 49.96 272.612 49.96C276.452 49.96 280.212 50.36 283.892 51.16C287.572 51.88 291.052 52.96 294.332 54.4C297.613 55.76 300.492 57.52 302.972 59.68L293.132 71.2C291.372 69.84 289.332 68.6 287.012 67.48C284.692 66.36 282.212 65.48 279.572 64.84C277.012 64.12 274.492 63.76 272.012 63.76C270.652 63.76 269.332 63.84 268.052 64C266.852 64.16 265.812 64.48 264.932 64.96C264.052 65.36 263.332 65.88 262.772 66.52C262.292 67.08 262.052 67.8 262.052 68.68C262.052 69.4 262.252 70.08 262.652 70.72C263.052 71.36 263.652 71.88 264.452 72.28C265.572 73 267.212 73.64 269.372 74.2C271.612 74.76 274.412 75.36 277.772 76C282.652 77.04 286.812 78.24 290.252 79.6C293.692 80.88 296.452 82.44 298.532 84.28C300.212 85.56 301.452 87.16 302.252 89.08C303.052 90.92 303.452 92.96 303.452 95.2C303.452 99.28 302.132 102.92 299.492 106.12C296.932 109.24 293.412 111.72 288.932 113.56C284.532 115.32 279.412 116.2 273.572 116.2ZM316.027 115V33.76H335.227V115H316.027ZM301.867 68.08V51.28H351.427V68.08H301.867Z" fill="#3D61BE"/>
4
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M217 64H218.5C228.717 64 237 72.2827 237 82.5C237 92.7173 228.717 101 218.5 101H217C211.942 110.021 204.089 115 194.012 115H218.5C236.449 115 251 100.449 251 82.5C251 64.5507 236.449 50 218.5 50H194.012C204.089 50 211.942 54.9792 217 64ZM194.012 64L180 50H178.5C160.551 50 146 64.5507 146 82.5C146 100.449 160.551 115 178.5 115H180L194.012 101H178.5C168.283 101 160 92.7173 160 82.5C160 72.2827 168.283 64 178.5 64H194.012Z" fill="#FF269B"/>
5
+ <rect x="118" y="57" width="91" height="51" rx="25.5" stroke="#FF269B" stroke-width="14"/>
6
+ </g>
7
+ <defs>
8
+ <clipPath id="clip0_438_169">
9
+ <rect width="356" height="140" fill="white"/>
10
+ </clipPath>
11
+ </defs>
12
+ </svg>
@@ -0,0 +1,133 @@
1
+ <svg viewBox="0 0 87 15" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M74.9427 14.6539C74.73 14.9246 74.295 14.7741 74.295 14.4301V11.127C74.295 10.7264 73.9704 10.4019 73.5698 10.4019H69.9228C69.6279 10.4019 69.4559 10.0683 69.6279 9.82865L72.0256 6.47163C72.3689 5.99166 72.0256 5.32454 71.4352 5.32454H67.0215C66.7266 5.32454 66.5547 4.99098 66.7266 4.75134L69.835 0.399156C69.9034 0.303852 70.0132 0.247223 70.1299 0.247223H79.393C79.6879 0.247223 79.8598 0.580784 79.6879 0.820424L77.2901 4.17745C76.9469 4.65742 77.2901 5.32454 77.8806 5.32454H81.5277C81.8301 5.32454 82 5.67329 81.8129 5.91155L74.9434 14.6546L74.9427 14.6539Z" fill="#863BFF"/>
3
+ <mask id="mask0_242_20652" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="66" y="0" width="16" height="15">
4
+ <path d="M74.9095 14.6538C74.6968 14.9246 74.2618 14.774 74.2618 14.4301V11.1269C74.2618 10.7264 73.9372 10.4018 73.5366 10.4018H69.8896C69.5947 10.4018 69.4227 10.0682 69.5947 9.82859L71.9924 6.47157C72.3357 5.9916 71.9924 5.32448 71.402 5.32448H66.9883C66.6934 5.32448 66.5215 4.99092 66.6934 4.75128L69.8018 0.399095C69.8702 0.303791 69.98 0.247162 70.0967 0.247162H79.3598C79.6547 0.247162 79.8266 0.580723 79.6547 0.820363L77.2569 4.17739C76.9137 4.65735 77.2569 5.32448 77.8474 5.32448H81.4945C81.7969 5.32448 81.9668 5.67323 81.7797 5.91149L74.9102 14.6545L74.9095 14.6538Z" fill="black"/>
5
+ </mask>
6
+ <g mask="url(#mask0_242_20652)">
7
+ <g filter="url(#filter0_f_242_20652)">
8
+ <ellipse cx="1.76581" cy="4.71403" rx="1.76581" ry="4.71403" transform="matrix(0.00324134 0.999995 0.999995 -0.00324134 65.1924 10.3508)" fill="#EDE6FF"/>
9
+ </g>
10
+ <g filter="url(#filter1_f_242_20652)">
11
+ <ellipse cx="3.33396" cy="9.57004" rx="3.33396" ry="9.57004" transform="matrix(0.00324134 0.999995 0.999995 -0.00324134 54.0166 2.77428)" fill="#EDE6FF"/>
12
+ </g>
13
+ <g filter="url(#filter2_f_242_20652)">
14
+ <ellipse cx="1.76581" cy="9.77374" rx="1.76581" ry="9.77374" transform="matrix(0.00324134 0.999995 0.999995 -0.00324134 53.6514 3.87662)" fill="#7E14FF"/>
15
+ </g>
16
+ <g filter="url(#filter3_f_242_20652)">
17
+ <ellipse cx="1.76581" cy="9.80957" rx="1.76581" ry="9.80957" transform="matrix(0.00324134 0.999995 0.999995 -0.00324134 55.125 9.64699)" fill="#7E14FF"/>
18
+ </g>
19
+ <g filter="url(#filter4_f_242_20652)">
20
+ <ellipse cx="1.76581" cy="9.80957" rx="1.76581" ry="9.80957" transform="matrix(0.00324134 0.999995 0.999995 -0.00324134 55.6162 10.0153)" fill="#7E14FF"/>
21
+ </g>
22
+ <g filter="url(#filter5_f_242_20652)">
23
+ <ellipse cx="4.51116" cy="7.07808" rx="4.51116" ry="7.07808" transform="matrix(0.0584509 -0.99829 -0.99829 -0.0584509 90.4609 8.85927)" fill="#EDE6FF"/>
24
+ </g>
25
+ <g filter="url(#filter6_f_242_20652)">
26
+ <ellipse cx="1.11255" cy="6.89295" rx="1.11255" ry="6.89295" transform="matrix(-0.0172986 -0.99985 -0.99985 0.0172986 90.9238 6.03786)" fill="#7E14FF"/>
27
+ </g>
28
+ <g filter="url(#filter7_f_242_20652)">
29
+ <ellipse cx="1.11255" cy="6.89295" rx="1.11255" ry="6.89295" transform="matrix(-0.0172986 -0.99985 -0.99985 0.0172986 90.9238 6.03786)" fill="#7E14FF"/>
30
+ </g>
31
+ <g filter="url(#filter8_f_242_20652)">
32
+ <ellipse cx="66.7487" cy="3.12336" rx="1.41273" ry="9.3316" transform="rotate(39.5103 66.7487 3.12336)" fill="#7E14FF"/>
33
+ </g>
34
+ <g filter="url(#filter9_f_242_20652)">
35
+ <ellipse cx="81.8602" cy="-1.70576" rx="1.41273" ry="9.3316" transform="rotate(37.8923 81.8602 -1.70576)" fill="#7E14FF"/>
36
+ </g>
37
+ <g filter="url(#filter10_f_242_20652)">
38
+ <ellipse cx="79.9017" cy="2.27762" rx="1.9144" ry="3.09855" transform="rotate(37.8923 79.9017 2.27762)" fill="#47BFFF"/>
39
+ </g>
40
+ <g filter="url(#filter11_f_242_20652)">
41
+ <ellipse cx="66.0223" cy="12.536" rx="1.41273" ry="9.3316" transform="rotate(37.8923 66.0223 12.536)" fill="#7E14FF"/>
42
+ </g>
43
+ <g filter="url(#filter12_f_242_20652)">
44
+ <ellipse cx="66.0223" cy="12.536" rx="1.41273" ry="9.3316" transform="rotate(37.8923 66.0223 12.536)" fill="#7E14FF"/>
45
+ </g>
46
+ <g filter="url(#filter13_f_242_20652)">
47
+ <ellipse cx="78.0545" cy="9.83499" rx="1.41273" ry="9.3316" transform="rotate(37.8923 78.0545 9.83499)" fill="#7E14FF"/>
48
+ </g>
49
+ <g filter="url(#filter14_f_242_20652)">
50
+ <ellipse cx="78.9411" cy="10.6343" rx="1.9144" ry="4.90418" transform="rotate(37.8923 78.9411 10.6343)" fill="#47BFFF"/>
51
+ </g>
52
+ </g>
53
+ <path d="M64.2894 0C61.3405 4.22097 61.3233 10.7637 64.2894 14.9999H66.2818C63.3164 10.7637 63.3336 4.22097 66.2818 0H64.2894Z" fill="white"/>
54
+ <path d="M84.302 1.52588e-05H82.3096C85.2584 4.22098 85.2757 10.7638 82.3096 14.9999H84.302C87.2674 10.7638 87.2501 4.22098 84.302 1.52588e-05Z" fill="white"/>
55
+ <path d="M9.13672 10.6901L12.9072 0.248688H18.0664L12.3477 14.7516H5.71777L0 0.248688H5.30371L9.13672 10.6901ZM24.7578 14.7516H19.7861V0.248688H24.7578V14.7516ZM42.8174 3.81216H37.2441V14.7516H32.2715V3.81216H26.6982V0.248688H42.8174V3.81216ZM59.0742 3.77115H49.7305V5.71841H58.9287V9.13638H49.7305V11.2292H59.3438V14.7516H44.7578V0.248688H59.0742V3.77115Z" fill="white"/>
56
+ <defs>
57
+ <filter id="filter0_f_242_20652" x="60.2873" y="5.42446" width="19.2496" height="13.3537" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
58
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
59
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
60
+ <feGaussianBlur stdDeviation="2.45548" result="effect1_foregroundBlur_242_20652"/>
61
+ </filter>
62
+ <filter id="filter1_f_242_20652" x="49.1164" y="-2.16785" width="28.9616" height="16.4901" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
63
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
64
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
65
+ <feGaussianBlur stdDeviation="2.45548" result="effect1_foregroundBlur_242_20652"/>
66
+ </filter>
67
+ <filter id="filter2_f_242_20652" x="50.7107" y="0.898076" width="25.44" height="9.42533" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
68
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
69
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
70
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
71
+ </filter>
72
+ <filter id="filter3_f_242_20652" x="52.1843" y="6.66832" width="25.5123" height="9.42534" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
73
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
74
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
75
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
76
+ </filter>
77
+ <filter id="filter4_f_242_20652" x="52.6755" y="7.03664" width="25.5123" height="9.42534" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
78
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
79
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
80
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
81
+ </filter>
82
+ <filter id="filter5_f_242_20652" x="71.6769" y="-5.49157" width="23.9635" height="18.8673" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
83
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
84
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
85
+ <feGaussianBlur stdDeviation="2.45548" result="effect1_foregroundBlur_242_20652"/>
86
+ </filter>
87
+ <filter id="filter6_f_242_20652" x="74.1745" y="0.979283" width="19.6764" height="8.13085" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
88
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
89
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
90
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
91
+ </filter>
92
+ <filter id="filter7_f_242_20652" x="74.1745" y="0.979283" width="19.6764" height="8.13085" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
93
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
94
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
95
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
96
+ </filter>
97
+ <filter id="filter8_f_242_20652" x="57.7653" y="-7.07928" width="17.9674" height="20.4053" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
98
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
99
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
100
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
101
+ </filter>
102
+ <filter id="filter9_f_242_20652" x="73.0739" y="-12.0682" width="17.5728" height="20.7248" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
103
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
104
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
105
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
106
+ </filter>
107
+ <filter id="filter10_f_242_20652" x="74.5251" y="-3.38285" width="10.7535" height="11.3209" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
108
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
109
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
110
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
111
+ </filter>
112
+ <filter id="filter11_f_242_20652" x="57.236" y="2.1736" width="17.5728" height="20.7248" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
113
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
114
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
115
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
116
+ </filter>
117
+ <filter id="filter12_f_242_20652" x="57.236" y="2.1736" width="17.5728" height="20.7248" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
118
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
119
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
120
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
121
+ </filter>
122
+ <filter id="filter13_f_242_20652" x="69.2683" y="-0.527431" width="17.5728" height="20.7248" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
123
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
124
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
125
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
126
+ </filter>
127
+ <filter id="filter14_f_242_20652" x="72.6237" y="3.64173" width="12.6344" height="13.985" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
128
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
129
+ <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
130
+ <feGaussianBlur stdDeviation="1.47329" result="effect1_foregroundBlur_242_20652"/>
131
+ </filter>
132
+ </defs>
133
+ </svg>
@@ -0,0 +1 @@
1
+ <svg viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><path fill="#42b883" d="M78.8,10L64,35.4L49.2,10H0l64,110l64-110C128,10,78.8,10,78.8,10z"/><path fill="#35495e" d="M78.8,10L64,35.4L49.2,10H25.6L64,76l38.4-66H78.8z"/></svg>
@@ -0,0 +1,4 @@
1
+ import { createSSRServer } from '@moostjs/vite/server'
2
+
3
+ const app = await createSSRServer()
4
+ await app.listen()
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <nav>
3
+ <router-link to="/">Home</router-link> |
4
+ <router-link to="/about">About</router-link>
5
+ </nav>
6
+ <router-view />
7
+ </template>
8
+
9
+ <style>
10
+ nav {
11
+ padding: 0.75rem 1rem;
12
+ text-align: center;
13
+ font-family: system-ui, -apple-system, sans-serif;
14
+ }
15
+ nav a {
16
+ color: #577fe6;
17
+ text-decoration: none;
18
+ font-size: 0.9rem;
19
+ }
20
+ nav a:hover {
21
+ color: #88a7f5;
22
+ }
23
+ nav a.router-link-exact-active {
24
+ color: #ff279b;
25
+ }
26
+ </style>
@@ -0,0 +1,10 @@
1
+ import { createSSRApp } from 'vue'
2
+ import App from './App.vue'
3
+ import { createRouter } from './router'
4
+
5
+ export function createApp() {
6
+ const app = createSSRApp(App)
7
+ const router = createRouter()
8
+ app.use(router)
9
+ return { app, router }
10
+ }
@@ -0,0 +1,10 @@
1
+ import { Controller, Param } from 'moost'
2
+ import { Get } from '@moostjs/event-http'
3
+
4
+ @Controller('api')
5
+ export class ApiController {
6
+ @Get('hello/:name')
7
+ hello(@Param('name') name: string) {
8
+ return { message: `Hello, ${name}!`, timestamp: Date.now() }
9
+ }
10
+ }
@@ -0,0 +1,4 @@
1
+ import { createApp } from './app'
2
+
3
+ const { app, router } = createApp()
4
+ router.isReady().then(() => app.mount('#app'))
@@ -0,0 +1,14 @@
1
+ import { renderToString } from 'vue/server-renderer'
2
+ import { createApp } from './app'
3
+
4
+ export async function render(url: string) {
5
+ const { app, router } = createApp()
6
+ await router.push(url)
7
+ await router.isReady()
8
+
9
+ const ctx: Record<string, any> = {}
10
+ const html = await renderToString(app, ctx)
11
+
12
+ const state = JSON.stringify(ctx.state || {})
13
+ return { html, state }
14
+ }
@@ -0,0 +1,8 @@
1
+ import { Moost } from 'moost'
2
+ import { MoostHttp } from '@moostjs/event-http'
3
+ import { ApiController } from './controllers/api.controller'
4
+
5
+ const app = new Moost()
6
+ app.adapter(new MoostHttp()).listen(3000)
7
+ app.registerControllers(ApiController)
8
+ app.init()
@@ -0,0 +1,89 @@
1
+ <template>
2
+ <div class="about">
3
+ <h1>About</h1>
4
+ <p>This is a full-stack SSR starter built with Moost, Vite, and Vue.</p>
5
+
6
+ <h2>Ecosystem</h2>
7
+ <div class="links">
8
+ <a href="https://moost.org" target="_blank" class="link-card">
9
+ <strong>Moost</strong>
10
+ <span>TypeScript framework with NestJS-style controllers, DI, pipes, and interceptors.</span>
11
+ </a>
12
+ <a href="https://wooks.moost.org" target="_blank" class="link-card">
13
+ <strong>Wooks</strong>
14
+ <span>Composable event processing framework. The HTTP engine behind Moost.</span>
15
+ </a>
16
+ <a href="https://atscript.dev" target="_blank" class="link-card">
17
+ <strong>Atscript</strong>
18
+ <span>A powerful data definition language and framework, seamlessly integrated into Moost.</span>
19
+ </a>
20
+ <a href="https://db.atscript.dev" target="_blank" class="link-card">
21
+ <strong>Atscript DB</strong>
22
+ <span>A database layer for Atscript.</span>
23
+ </a>
24
+ </div>
25
+
26
+ <h2>Tooling</h2>
27
+ <div class="links">
28
+ <a href="https://vite.dev" target="_blank" class="link-card">
29
+ <strong>Vite</strong>
30
+ <span>Next-generation frontend tooling with Oxc and Rolldown.</span>
31
+ </a>
32
+ <a href="https://vuejs.org" target="_blank" class="link-card">
33
+ <strong>Vue.js</strong>
34
+ <span>The progressive JavaScript framework for building user interfaces.</span>
35
+ </a>
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <style scoped>
41
+ .about {
42
+ max-width: 720px;
43
+ margin: 0 auto;
44
+ padding: 2rem 1rem;
45
+ font-family: system-ui, -apple-system, sans-serif;
46
+ color: #dfdfd6;
47
+ }
48
+ h1 {
49
+ color: #88a7f5;
50
+ margin: 0 0 0.5rem;
51
+ }
52
+ h2 {
53
+ color: #577fe6;
54
+ font-size: 1.1rem;
55
+ margin: 1.5rem 0 0.75rem;
56
+ }
57
+ h1 + p {
58
+ color: #98989f;
59
+ margin: 0 0 1rem;
60
+ }
61
+ .links {
62
+ display: flex;
63
+ flex-direction: column;
64
+ gap: 0.75rem;
65
+ }
66
+ .link-card {
67
+ display: block;
68
+ padding: 1rem 1.25rem;
69
+ background: #1c2b59;
70
+ border: 1px solid #273760;
71
+ border-radius: 8px;
72
+ text-decoration: none;
73
+ transition: border-color 0.15s;
74
+ }
75
+ .link-card:hover {
76
+ border-color: #577fe6;
77
+ }
78
+ .link-card strong {
79
+ display: block;
80
+ color: #ff279b;
81
+ margin-bottom: 0.25rem;
82
+ font-size: 0.95rem;
83
+ }
84
+ .link-card span {
85
+ color: #98989f;
86
+ font-size: 0.85rem;
87
+ line-height: 1.4;
88
+ }
89
+ </style>
@@ -0,0 +1,232 @@
1
+ <template>
2
+ <div class="home">
3
+ <div class="hero">
4
+ <a href="https://moost.org" target="_blank">
5
+ <img src="/moost-logo.svg" alt="Moost" height="128px" class="logo-moost" />
6
+ </a>
7
+ <div class="powered-by">
8
+ <span>powered by</span>
9
+ <div class="sub-logos">
10
+ <a href="https://vite.dev" target="_blank">
11
+ <img src="/vite-logo.svg" alt="Vite" height="32px" class="logo-sub" />
12
+ </a>
13
+ <span class="plus">+</span>
14
+ <a href="https://vuejs.org" target="_blank">
15
+ <img src="/vue-logo.svg" alt="Vue" height="32px" class="logo-sub" />
16
+ </a>
17
+ </div>
18
+ </div>
19
+ <p class="tagline">Full-stack SSR with decorator-driven API, zero-config HMR, and local fetch</p>
20
+ </div>
21
+
22
+ <div class="cards">
23
+ <div class="card">
24
+ <h2>SSR Fetch</h2>
25
+ <p class="description">
26
+ Data below was fetched from <code>/api/hello/SSR</code> during server rendering.
27
+ On the server, <code>fetch()</code> calls the Moost handler directly in-process — no HTTP roundtrip.
28
+ </p>
29
+ <pre v-if="ssrData" class="result">{{ JSON.stringify(ssrData, null, 2) }}</pre>
30
+ <p v-else class="loading">Loading...</p>
31
+ <p class="note" v-if="fetchSource">Fetched via: <strong>{{ fetchSource }}</strong></p>
32
+ </div>
33
+
34
+ <div class="card">
35
+ <h2>Client Hydration</h2>
36
+ <p class="description">
37
+ This counter was server-rendered at <strong>{{ count }}</strong> and hydrated on the client.
38
+ </p>
39
+ <div class="counter">
40
+ <button @click="count--">-</button>
41
+ <span>{{ count }}</span>
42
+ <button @click="count++">+</button>
43
+ </div>
44
+ </div>
45
+
46
+ <div class="card">
47
+ <h2>Client Fetch</h2>
48
+ <p class="description">Click to fetch from the API on the client side (real HTTP request).</p>
49
+ <button class="fetch-btn" @click="clientFetch">Fetch /api/hello/World</button>
50
+ <pre v-if="clientData" class="result">{{ JSON.stringify(clientData, null, 2) }}</pre>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ </template>
55
+
56
+ <script setup lang="ts">
57
+ import { ref, onServerPrefetch, onMounted, useSSRContext } from 'vue'
58
+
59
+ const count = ref(0)
60
+ const clientData = ref<any>(null)
61
+ const fetchSource = ref('')
62
+
63
+ // Restore SSR state on client, or initialize empty
64
+ const ssrState = import.meta.env.SSR ? useSSRContext()! : (window as any).__SSR_STATE__ || {}
65
+ const ssrData = ref<any>(ssrState.ssrData || null)
66
+
67
+ if (ssrData.value) {
68
+ fetchSource.value = 'server (local fetch)'
69
+ }
70
+
71
+ // SSR: fetch runs on the server via local moost handler (no HTTP roundtrip)
72
+ onServerPrefetch(async () => {
73
+ const res = await fetch('/api/hello/SSR')
74
+ ssrData.value = await res.json()
75
+ fetchSource.value = 'server (local fetch)'
76
+ // Save to SSR context for client hydration
77
+ ssrState.state = ssrState.state || {}
78
+ ssrState.state.ssrData = ssrData.value
79
+ })
80
+
81
+ // Client fallback: fetch if SSR data wasn't available (SPA mode or no state transfer)
82
+ onMounted(async () => {
83
+ if (!ssrData.value) {
84
+ const res = await fetch('/api/hello/SSR')
85
+ ssrData.value = await res.json()
86
+ fetchSource.value = 'client (HTTP)'
87
+ }
88
+ })
89
+
90
+ async function clientFetch() {
91
+ const res = await fetch('/api/hello/World')
92
+ clientData.value = await res.json()
93
+ }
94
+ </script>
95
+
96
+ <style scoped>
97
+ .home {
98
+ max-width: 720px;
99
+ margin: 0 auto;
100
+ padding: 2rem 1rem;
101
+ font-family: system-ui, -apple-system, sans-serif;
102
+ color: #dfdfd6;
103
+ }
104
+ .hero {
105
+ display: flex;
106
+ flex-direction: column;
107
+ align-items: center;
108
+ margin-bottom: 2.5rem;
109
+ }
110
+ .logo-moost {
111
+ height: 128px;
112
+ margin-bottom: 1rem;
113
+ transition: transform 0.2s;
114
+ }
115
+ .logo-moost:hover {
116
+ transform: scale(1.05);
117
+ }
118
+ .powered-by {
119
+ display: flex;
120
+ flex-direction: column;
121
+ align-items: center;
122
+ gap: 0.4rem;
123
+ margin-bottom: 1.25rem;
124
+ }
125
+ .powered-by span {
126
+ font-size: 0.75rem;
127
+ text-transform: uppercase;
128
+ letter-spacing: 0.15em;
129
+ color: #6a6a71;
130
+ }
131
+ .sub-logos {
132
+ display: flex;
133
+ align-items: center;
134
+ gap: 0.75rem;
135
+ }
136
+ .logo-sub {
137
+ height: 32px;
138
+ transition: transform 0.2s;
139
+ }
140
+ .logo-sub:hover {
141
+ transform: scale(1.1);
142
+ }
143
+ .plus {
144
+ font-size: 1.25rem;
145
+ color: #577fe6;
146
+ font-weight: 300;
147
+ }
148
+ .tagline {
149
+ text-align: center;
150
+ color: #98989f;
151
+ margin: 0;
152
+ font-size: 0.95rem;
153
+ }
154
+ .cards {
155
+ display: flex;
156
+ flex-direction: column;
157
+ gap: 1.25rem;
158
+ }
159
+ .card {
160
+ border: 1px solid #273760;
161
+ border-radius: 10px;
162
+ padding: 1.25rem;
163
+ background: #1c2b59;
164
+ }
165
+ h2 {
166
+ margin: 0 0 0.5rem;
167
+ font-size: 1.15rem;
168
+ color: #88a7f5;
169
+ }
170
+ .description {
171
+ color: #98989f;
172
+ margin: 0 0 0.75rem;
173
+ font-size: 0.9rem;
174
+ line-height: 1.5;
175
+ }
176
+ code {
177
+ background: #212e51;
178
+ color: #ff279b;
179
+ padding: 0.15em 0.4em;
180
+ border-radius: 3px;
181
+ font-size: 0.85em;
182
+ }
183
+ .result {
184
+ background: #0e1c41;
185
+ color: #a8e6cf;
186
+ padding: 0.75rem 1rem;
187
+ border-radius: 6px;
188
+ font-size: 0.85rem;
189
+ overflow-x: auto;
190
+ margin: 0.5rem 0;
191
+ border: 1px solid #273760;
192
+ }
193
+ .note {
194
+ font-size: 0.8rem;
195
+ color: #6a6a71;
196
+ margin: 0.5rem 0 0;
197
+ }
198
+ .note strong {
199
+ color: #ff279b;
200
+ }
201
+ .loading {
202
+ color: #6a6a71;
203
+ font-style: italic;
204
+ }
205
+ .counter {
206
+ display: flex;
207
+ align-items: center;
208
+ gap: 1rem;
209
+ }
210
+ .counter span {
211
+ font-size: 1.5rem;
212
+ min-width: 2rem;
213
+ text-align: center;
214
+ color: #dfdfd6;
215
+ }
216
+ .counter button,
217
+ .fetch-btn {
218
+ padding: 0.4rem 1rem;
219
+ border: 1px solid #3d61be;
220
+ border-radius: 6px;
221
+ background: #212e51;
222
+ color: #dfdfd6;
223
+ cursor: pointer;
224
+ font-size: 0.9rem;
225
+ transition: all 0.15s;
226
+ }
227
+ .counter button:hover,
228
+ .fetch-btn:hover {
229
+ background: #273760;
230
+ border-color: #577fe6;
231
+ }
232
+ </style>
@@ -0,0 +1,13 @@
1
+ import { createMemoryHistory, createRouter as _createRouter, createWebHistory } from 'vue-router'
2
+
3
+ const routes = [
4
+ { path: '/', component: () => import('./pages/Home.vue') },
5
+ { path: '/about', component: () => import('./pages/About.vue') },
6
+ ]
7
+
8
+ export function createRouter() {
9
+ return _createRouter({
10
+ history: import.meta.env.SSR ? createMemoryHistory() : createWebHistory(),
11
+ routes,
12
+ })
13
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+
7
+ "experimentalDecorators": true,
8
+ "emitDecoratorMetadata": true,
9
+
10
+ "strict": true,
11
+ "skipLibCheck": true,
12
+ "isolatedModules": true,
13
+ "useDefineForClassFields": false
14
+ },
15
+ "include": ["src/**/*.ts", "src/**/*.vue", "server.ts", "vite-env.d.ts"]
16
+ }
@@ -0,0 +1,7 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module '*.vue' {
4
+ import type { DefineComponent } from 'vue'
5
+ const component: DefineComponent
6
+ export default component
7
+ }
@@ -0,0 +1,19 @@
1
+ import { defineConfig } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+ import { moostVite } from '@moostjs/vite'
4
+
5
+ export default defineConfig({
6
+ appType: 'custom',
7
+ server: { port: 3000 },
8
+ plugins: [
9
+ vue(),
10
+ moostVite({
11
+ entry: '/src/main.ts',
12
+ middleware: true,
13
+ prefix: '/api',
14
+ //=IF (ssr)
15
+ ssrEntry: '/src/entry-server.ts',
16
+ //=END IF
17
+ }),
18
+ ],
19
+ })
@@ -27,7 +27,6 @@
27
27
  "oxfmt": "^0.34.0",
28
28
  //=END IF
29
29
  "typescript": "^5.7.2",
30
- "unplugin-swc": "^1.5.9",
31
30
  "rolldown": "1.0.0-beta.19"
32
31
  }
33
32
  }
@@ -1,5 +1,4 @@
1
1
  import { defineConfig } from 'rolldown'
2
- import swc from 'unplugin-swc';
3
2
 
4
3
  export default defineConfig({
5
4
  input: 'src/main.ts',
@@ -8,7 +7,4 @@ export default defineConfig({
8
7
  file: 'dist/main.js',
9
8
  },
10
9
  external: ['@moostjs/event-ws', 'moost'],
11
- plugins: [
12
- swc.rolldown(),
13
- ]
14
10
  })