create-vitnode-app 1.2.0-canary.9 → 2.0.0-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +58 -18
  3. package/copy-of-vitnode-app/.vscode/settings.json +10 -0
  4. package/copy-of-vitnode-app/README.md +62 -0
  5. package/copy-of-vitnode-app/api/.gitignore_template +32 -0
  6. package/copy-of-vitnode-app/api/drizzle.config.ts +12 -0
  7. package/copy-of-vitnode-app/api/src/index.ts +27 -0
  8. package/copy-of-vitnode-app/api/src/vitnode.api.config.ts +57 -0
  9. package/copy-of-vitnode-app/api/tsconfig.json +17 -0
  10. package/copy-of-vitnode-app/api-bun/src/index.ts +16 -0
  11. package/copy-of-vitnode-app/api-single-app/drizzle.config.ts +12 -0
  12. package/copy-of-vitnode-app/api-single-app/src/routes/api/$.ts +32 -0
  13. package/copy-of-vitnode-app/api-single-app/src/server/api-bridge.ts +22 -0
  14. package/copy-of-vitnode-app/api-single-app/src/server/vitnode-api.server.ts +29 -0
  15. package/copy-of-vitnode-app/api-single-app/src/vitnode.api.config.ts +36 -0
  16. package/copy-of-vitnode-app/docker/docker-compose.yml +30 -0
  17. package/copy-of-vitnode-app/eslint/.prettierrc.mjs +1 -1
  18. package/copy-of-vitnode-app/eslint/eslint.config.mjs +18 -2
  19. package/copy-of-vitnode-app/{root → eslint-react}/.prettierrc.mjs +1 -1
  20. package/copy-of-vitnode-app/eslint-react/eslint.config.mjs +19 -0
  21. package/copy-of-vitnode-app/monorepo/.gitignore_template +41 -0
  22. package/copy-of-vitnode-app/monorepo/apps/api/.env.example +12 -0
  23. package/copy-of-vitnode-app/monorepo/apps/web/.env.example +12 -0
  24. package/copy-of-vitnode-app/monorepo/turbo.json +53 -0
  25. package/copy-of-vitnode-app/root/.env.example +16 -5
  26. package/copy-of-vitnode-app/root/.gitignore_template +41 -0
  27. package/copy-of-vitnode-app/root/global.d.ts +28 -0
  28. package/copy-of-vitnode-app/root/src/components/admin-shell.tsx +72 -0
  29. package/copy-of-vitnode-app/root/src/components/main-header.tsx +33 -0
  30. package/copy-of-vitnode-app/root/src/lib/admin-auth.ts +11 -0
  31. package/copy-of-vitnode-app/root/src/lib/admin-nav.ts +43 -0
  32. package/copy-of-vitnode-app/root/src/lib/admin-search.ts +37 -0
  33. package/copy-of-vitnode-app/root/src/lib/auth.ts +66 -0
  34. package/copy-of-vitnode-app/root/src/lib/content-registry.ts +52 -0
  35. package/copy-of-vitnode-app/root/src/lib/i18n/runtime.ts +75 -0
  36. package/copy-of-vitnode-app/root/src/lib/i18n/shared.ts +20 -0
  37. package/copy-of-vitnode-app/root/src/lib/navigation.ts +24 -0
  38. package/copy-of-vitnode-app/root/src/lib/page-head.ts +19 -0
  39. package/copy-of-vitnode-app/root/src/locales/app.ts +28 -0
  40. package/copy-of-vitnode-app/root/src/locales/packages.ts +43 -0
  41. package/copy-of-vitnode-app/root/src/router.tsx +227 -0
  42. package/copy-of-vitnode-app/root/src/routes/__root.tsx +212 -0
  43. package/copy-of-vitnode-app/root/src/routes/_admin/admin.core.index.tsx +69 -0
  44. package/copy-of-vitnode-app/root/src/routes/_admin.tsx +258 -0
  45. package/copy-of-vitnode-app/root/src/routes/_main/index.tsx +60 -0
  46. package/copy-of-vitnode-app/root/src/routes/_main.tsx +64 -0
  47. package/copy-of-vitnode-app/root/src/server/messages.server.ts +21 -0
  48. package/copy-of-vitnode-app/root/src/start.ts +24 -0
  49. package/copy-of-vitnode-app/root/src/styles.css +139 -0
  50. package/copy-of-vitnode-app/root/src/vitnode.config.ts +73 -0
  51. package/copy-of-vitnode-app/root/src/vitnode.server.config.ts +23 -0
  52. package/copy-of-vitnode-app/root/tsconfig.json +24 -16
  53. package/copy-of-vitnode-app/root/tsr.config.json +3 -0
  54. package/copy-of-vitnode-app/root/vite.config.ts +106 -0
  55. package/copy-of-vitnode-plugin/root/.swcrc +26 -0
  56. package/copy-of-vitnode-plugin/root/global.d.ts +21 -0
  57. package/copy-of-vitnode-plugin/root/npmignore.template +17 -0
  58. package/copy-of-vitnode-plugin/root/tsconfig.build.json +5 -0
  59. package/copy-of-vitnode-plugin/root/tsconfig.json +25 -0
  60. package/dist/src/create/create-package-json.js +266 -56
  61. package/dist/src/create/create-vitnode.js +177 -28
  62. package/dist/src/create/package-versions.js +49 -0
  63. package/dist/src/helpers/get-available-package-managers.js +6 -6
  64. package/dist/src/helpers/get-package-json.js +2 -2
  65. package/dist/src/helpers/get-package-manager-from-root.js +15 -0
  66. package/dist/src/helpers/get-vitnode-package-version.js +9 -0
  67. package/dist/src/helpers/init-vitnode.js +34 -0
  68. package/dist/src/helpers/install-dependencies.js +55 -14
  69. package/dist/src/helpers/is-folder-empty.js +25 -26
  70. package/dist/src/helpers/is-online.js +16 -16
  71. package/dist/src/helpers/is-writeable.js +3 -3
  72. package/dist/src/helpers/validate-pkg.js +1 -1
  73. package/dist/src/helpers/with-If.js +1 -0
  74. package/dist/src/index.js +29 -26
  75. package/dist/src/plugin/create/add-plugin-to-workspace.js +74 -0
  76. package/dist/src/plugin/create/create-package-json.js +54 -0
  77. package/dist/src/plugin/create/create-plugin-vitnode.js +80 -0
  78. package/dist/src/plugin/create/route-templates.js +144 -0
  79. package/dist/src/plugin/index.js +17 -6
  80. package/dist/src/plugin/questions.js +14 -0
  81. package/dist/src/plugin/validation.js +76 -0
  82. package/dist/src/prepare/prepare.js +11 -8
  83. package/dist/src/questions.js +52 -15
  84. package/dist/src/validation.js +15 -15
  85. package/dist/tsconfig.build.tsbuildinfo +1 -0
  86. package/package.json +22 -12
  87. package/copy-of-vitnode-app/root/README.md +0 -1
  88. package/copy-of-vitnode-app/root/drizzle.config.ts +0 -12
  89. package/copy-of-vitnode-app/root/gitignore_template +0 -43
  90. package/copy-of-vitnode-app/root/next.config.ts +0 -11
  91. package/copy-of-vitnode-app/root/postcss.config.mjs +0 -8
  92. package/copy-of-vitnode-app/root/src/app/[locale]/(main)/[...rest]/page.tsx +0 -5
  93. package/copy-of-vitnode-app/root/src/app/[locale]/(main)/layout.tsx +0 -10
  94. package/copy-of-vitnode-app/root/src/app/[locale]/(main)/not-found.tsx +0 -5
  95. package/copy-of-vitnode-app/root/src/app/[locale]/(main)/page.tsx +0 -113
  96. package/copy-of-vitnode-app/root/src/app/[locale]/admin/(auth)/layout.tsx +0 -10
  97. package/copy-of-vitnode-app/root/src/app/[locale]/admin/not-found.tsx +0 -5
  98. package/copy-of-vitnode-app/root/src/app/[locale]/admin/page.tsx +0 -5
  99. package/copy-of-vitnode-app/root/src/app/[locale]/layout.tsx +0 -36
  100. package/copy-of-vitnode-app/root/src/app/api/[...route]/route.ts +0 -18
  101. package/copy-of-vitnode-app/root/src/app/favicon.ico +0 -0
  102. package/copy-of-vitnode-app/root/src/app/global-error.tsx +0 -27
  103. package/copy-of-vitnode-app/root/src/app/global.css +0 -128
  104. package/copy-of-vitnode-app/root/src/app/layout.tsx +0 -9
  105. package/copy-of-vitnode-app/root/src/app/not-found.tsx +0 -13
  106. package/copy-of-vitnode-app/root/src/vitnode.api.config.ts +0 -5
  107. package/dist/tsconfig.tsbuildinfo +0 -1
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Maciej Piotr Balcerzak
3
+ Copyright (c) 2025 aXenDev Maciej Balcerzak
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,44 +1,84 @@
1
- # (VitNode) Create App
1
+ # Create VitNode App
2
2
 
3
- This package is a CLI tool to create a new VitNode app quickly.
4
-
5
- Script based on [Create Next App](https://nextjs.org/).
3
+ `create-vitnode-app` scaffolds a TanStack Start and Hono VitNode application,
4
+ or an installable plugin for an existing VitNode workspace.
6
5
 
7
6
  <p align="center">
8
- <br>
9
7
  <a href="https://vitnode.com/" target="_blank">
10
8
  <picture>
11
9
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/VitNode/vitnode/canary/assets/logo/vitnode_logo_dark.svg">
12
10
  <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/VitNode/vitnode/canary/assets/logo/vitnode_logo_light.svg">
13
- <img alt="VitNode Logo" src="https://raw.githubusercontent.com/VitNode/vitnode/canary/assets/logo/vitnode_logo_light.svg" width="400">
11
+ <img alt="VitNode" src="https://raw.githubusercontent.com/VitNode/vitnode/canary/assets/logo/vitnode_logo_light.svg" width="400">
14
12
  </picture>
15
13
  </a>
16
- <br>
17
- <br>
18
14
  </p>
19
15
 
20
- ## Usage
16
+ ## Create an app
17
+
18
+ ### Bun
21
19
 
22
20
  ```bash
23
- npx create-vitnode-app@latest
21
+ bun create vitnode-app@latest
24
22
  ```
25
23
 
26
- or
24
+ ### pnpm
27
25
 
28
26
  ```bash
29
27
  pnpm create vitnode-app@latest
30
28
  ```
31
29
 
32
- or
30
+ ### npm
33
31
 
34
32
  ```bash
35
- bun create vitnode-app@latest
33
+ npm create vitnode-app@latest
34
+ ```
35
+
36
+ Choose Turborepo during setup if you will build plugins. It gives your project a
37
+ workspace root and a `plugins/*` home.
38
+
39
+ ## Create a plugin
40
+
41
+ Run this from an existing VitNode workspace, then enter the plugin package name
42
+ when prompted:
43
+
44
+ ### Bun
45
+
46
+ ```bash
47
+ bun create vitnode-app@latest --plugin
48
+ ```
49
+
50
+ ### pnpm
51
+
52
+ ```bash
53
+ pnpm create vitnode-app@latest --plugin
54
+ ```
55
+
56
+ ### npm
57
+
58
+ ```bash
59
+ npm create vitnode-app@latest -- --plugin
60
+ ```
61
+
62
+ The generator creates the package and adds its workspace dependency. Enable the
63
+ feature by registering it in the host’s `vitnode.config.ts`:
64
+
65
+ ```ts
66
+ import { myPlugin } from '@acme/my-plugin/config'
67
+
68
+ plugins: [myPlugin()]
36
69
  ```
37
70
 
38
71
  ## Options
39
72
 
40
- | Option | Description |
41
- | ------------------- | ---------------------------------------------------------- |
42
- | `--package-manager` | Specify the package manager to use. Support `npm`, `pnpm`. |
43
- | `--eslint` | Initialize with eslint config. |
44
- | `--skip-install` | Skip installing packages after initializing the project. |
73
+ | Option | Description |
74
+ | --- | --- |
75
+ | `--package-manager` | Choose `npm` or `pnpm` for the generated project. |
76
+ | `--eslint` | Include ESLint and Prettier configuration. |
77
+ | `--skip-install` | Skip dependency installation after scaffolding. |
78
+ | `--mode` | Choose `singleApp`, `apiMonorepo`, or `onlyApi`. |
79
+ | `--monorepo` | Create a workspace layout for plugins and multiple applications. |
80
+ | `--docker` | Include local Docker services. |
81
+ | `--plugin` | Create a VitNode plugin package. |
82
+
83
+ Read the [VitNode documentation](https://vitnode.com/docs/dev) for setup,
84
+ plugins, deployment, and AdminCP guides.
@@ -0,0 +1,10 @@
1
+ {
2
+ "cSpell.words": [
3
+ "vitnode"
4
+ ],
5
+ "github.copilot.chat.commitMessageGeneration.instructions": [
6
+ {
7
+ "text": "Follow the Conventional Commits format strictly for commit messages. Use the structure below:\n\n```\n<type>[optional scope]: <gitmoji> <description>\n```\n\nGuidelines:\n\n1. **Type and Scope**: Choose an appropriate type (e.g., `feat`, `fix`, `refactor`, `docs`) and optional scope to describe the affected module or feature.\n\n2. **Gitmoji**: Include a relevant `gitmoji` that best represents the nature of the change.\n\n3. **Description**: Write a concise, informative description in the header; use backticks if referencing code or specific terms.\n\nCommit messages should be clear, informative, and professional, aiding readability and project tracking."
8
+ }
9
+ ]
10
+ }
@@ -0,0 +1,62 @@
1
+ <p align="center">
2
+ <br>
3
+ <a href="https://vitnode.com/" target="_blank">
4
+ <picture>
5
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/VitNode/vitnode/canary/assets/logo/vitnode_logo_dark.svg">
6
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/VitNode/vitnode/canary/assets/logo/vitnode_logo_light.svg">
7
+ <img alt="VitNode Logo" src="https://raw.githubusercontent.com/VitNode/vitnode/canary/assets/logo/vitnode_logo_light.svg" width="400">
8
+ </picture>
9
+ </a>
10
+ <br>
11
+ <br>
12
+ </p>
13
+
14
+ # VitNode App
15
+
16
+ This is a basic template for a [VitNode](https://vitnode.com/) app.
17
+
18
+ ## Getting Started
19
+
20
+ To get started, run the following commands:
21
+
22
+ ```bash
23
+ pnpm i
24
+ ```
25
+
26
+ Open {{START_URLS}} with your browser to see the result.
27
+
28
+ ## Development
29
+
30
+ To start the development server, you need to create a `.env` file from the provided `.env.example` file.
31
+
32
+ In the `development` environment, you can just copy and paste the content of `.env.example` to `.env`.
33
+
34
+ ### Development server
35
+
36
+ To start the development server, run the following command:
37
+
38
+ ```bash
39
+ pnpm dev
40
+ ```
41
+
42
+ ## Configuration
43
+
44
+ Two files, and the line between them is one question: may a browser hold this?
45
+
46
+ | File | Holds |
47
+ | :----------------------------- | :----------------------------------------------------------------------------------------------------------------------- |
48
+ | `src/vitnode.config.ts` | locales, metadata, theme, `debug`, enabled plugin ids - plain data, read by the browser, the server, and your Vite build |
49
+ | `src/vitnode.server.config.ts` | message loaders - server only |
50
+
51
+ Add a language to `i18n.locales` in the shared config; register the files that
52
+ translate it in `src/locales/packages.ts` (a package's own translations) or
53
+ `src/locales/app.ts` (your rewordings). `pnpm vitnode i18n:create de Deutsch`
54
+ does all three.
55
+
56
+ `src/start.ts` is one call to `createVitNodeStart`, which installs CSRF
57
+ protection for server functions, canonical locale redirects with the
58
+ remembered-locale cookie, and the `private, no-store` directive every rendered
59
+ document needs. Add your own request middleware with `requestMiddleware` - it
60
+ runs after all of it.
61
+
62
+ See [Configuration](https://vitnode.com/docs/dev/configuration).
@@ -0,0 +1,32 @@
1
+ # Dependencies
2
+ node_modules
3
+
4
+ # Turbo
5
+ .turbo
6
+
7
+ # Test & Build
8
+ /coverage
9
+ /desc
10
+ *.tsbuildinfo
11
+
12
+ # Misc
13
+ .DS_Store
14
+ *.pem
15
+ /.pnp
16
+ .pnp.js
17
+ npm-debug.log*
18
+ yarn-debug.log*
19
+ yarn-error.log*
20
+
21
+ # Local env files
22
+ .env
23
+ .env.local
24
+ .env.development.local
25
+ .env.test.local
26
+ .env.production.local
27
+
28
+ # Others
29
+ .vercel
30
+
31
+ # Local storage adapter uploads
32
+ /public/uploads
@@ -0,0 +1,12 @@
1
+ import { defineVitNodeDrizzleConfig } from "@vitnode/core/drizzle.config";
2
+
3
+ import { POSTGRES_URL, vitNodeApiConfig } from "./src/vitnode.api.config";
4
+
5
+ export default defineVitNodeDrizzleConfig({
6
+ vitNodeApiConfig,
7
+ out: "./migrations/",
8
+ dialect: "postgresql",
9
+ dbCredentials: {
10
+ url: POSTGRES_URL,
11
+ },
12
+ });
@@ -0,0 +1,27 @@
1
+ import { serve } from "@hono/node-server";
2
+ import { OpenAPIHono } from "@hono/zod-openapi";
3
+ import { VitNodeAPI } from "@vitnode/core/api/config";
4
+
5
+ import { vitNodeApiConfig } from "./vitnode.api.config.js";
6
+
7
+ const app = new OpenAPIHono().basePath("/api");
8
+
9
+ VitNodeAPI({
10
+ app,
11
+ vitNodeApiConfig,
12
+ });
13
+
14
+ serve(
15
+ {
16
+ fetch: app.fetch,
17
+ port: 8000,
18
+ },
19
+ info => {
20
+ const initMessage = "\x1b[34m[VitNode]\x1b[0m";
21
+
22
+ // eslint-disable-next-line no-console
23
+ console.log(
24
+ `${initMessage} API server is running on http://localhost:${info.port}`,
25
+ );
26
+ },
27
+ );
@@ -0,0 +1,57 @@
1
+ import { buildApiConfig } from "@vitnode/core/vitnode.config";
2
+ import { config } from "dotenv";
3
+ import { coreRelations } from "@vitnode/core/database/relations";
4
+ import { drizzle } from "drizzle-orm/postgres-js";
5
+
6
+ config({
7
+ quiet: true,
8
+ });
9
+
10
+ export const POSTGRES_URL =
11
+ process.env.POSTGRES_URL ?? "postgresql://root:root@localhost:5432/vitnode";
12
+
13
+ export const vitNodeApiConfig = buildApiConfig({
14
+ plugins: [],
15
+ /**
16
+ * The languages this installation serves.
17
+ *
18
+ * The API half of a split deployment. `apps/web/src/vitnode.config.ts`
19
+ * declares the same list, and the two are one declaration in two places by
20
+ * necessity rather than by design: they are separate packages, so neither can
21
+ * import the other's. Nothing walks the filesystem looking for the web app's
22
+ * config either - a bootstrap that guessed at a sibling application is exactly
23
+ * what that replaced, and it guessed wrong the moment the two were not laid
24
+ * out the way it expected.
25
+ *
26
+ * They have to agree, and this is the copy that matters most: this app owns
27
+ * the schema, so `vitnode db:prepare` seeds `core_languages` from *this* list.
28
+ * A language that is here and not in the web app's renders nowhere; one that
29
+ * is in the web app's and not here has no row in the database.
30
+ *
31
+ * Packages ship their own translations, so a new locale needs no `messages`
32
+ * entry - anything untranslated falls back to `defaultLocale` key by key.
33
+ */
34
+ i18n: {
35
+ defaultLocale: "en",
36
+ locales: [{ code: "en", name: "English" }],
37
+ /**
38
+ * Explicit, because this API renders emails on a server: without one, dates
39
+ * format in whatever zone the host happens to run in.
40
+ */
41
+ timeZone: "UTC",
42
+ },
43
+ dbProvider: drizzle({
44
+ connection: POSTGRES_URL,
45
+ relations: coreRelations,
46
+ }),
47
+ // Redis is opt-in: only enabled when REDIS_URL is set. Without it the cache
48
+ // is a no-op, the rate limiter uses in-memory storage, and WebSockets run in
49
+ // single-instance mode.
50
+ redis: process.env.REDIS_URL
51
+ ? { url: process.env.REDIS_URL, password: process.env.REDIS_PASSWORD }
52
+ : undefined,
53
+ metadata: {
54
+ title: "VitNode API",
55
+ shortTitle: "VitNode",
56
+ },
57
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "@vitnode/config/tsconfig",
4
+ "compilerOptions": {
5
+ "target": "ESNext",
6
+ "module": "NodeNext",
7
+ "rootDir": "./",
8
+ "outDir": "./dist",
9
+ "incremental": false,
10
+ "types": ["node"],
11
+ "paths": {
12
+ "@/*": ["./src/*"]
13
+ }
14
+ },
15
+ "include": ["src", "global.d.ts"],
16
+ "exclude": ["node_modules"]
17
+ }
@@ -0,0 +1,16 @@
1
+ import { OpenAPIHono } from "@hono/zod-openapi";
2
+ import { VitNodeAPI } from "@vitnode/core/api/config";
3
+
4
+ import { vitNodeApiConfig } from "./vitnode.api.config.js";
5
+
6
+ const app = new OpenAPIHono().basePath("/api");
7
+
8
+ VitNodeAPI({
9
+ app,
10
+ vitNodeApiConfig,
11
+ });
12
+
13
+ export default {
14
+ port: 8000,
15
+ fetch: app.fetch,
16
+ };
@@ -0,0 +1,12 @@
1
+ import { defineVitNodeDrizzleConfig } from "@vitnode/core/drizzle.config";
2
+
3
+ import { POSTGRES_URL, vitNodeApiConfig } from "./src/vitnode.api.config";
4
+
5
+ export default defineVitNodeDrizzleConfig({
6
+ vitNodeApiConfig,
7
+ out: "./migrations/",
8
+ dialect: "postgresql",
9
+ dbCredentials: {
10
+ url: POSTGRES_URL,
11
+ },
12
+ });
@@ -0,0 +1,32 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+
3
+ import { apiBridge } from '#/server/vitnode-api.server'
4
+
5
+ /**
6
+ * `/api/*` - the existing VitNode Hono application, mounted.
7
+ *
8
+ * `server` is the only option on this route on purpose. TanStack Start prunes a
9
+ * route file whose sole option is `server` out of the client route tree
10
+ * entirely (and its client code-splitter deletes the `server` node on top of
11
+ * that), so none of the API - Hono, Drizzle, the plugins - can reach the browser
12
+ * bundle. The `.server.ts` import is refused by import protection if that ever
13
+ * stops being true.
14
+ *
15
+ * `ANY` rather than a handler per method: routing, OpenAPI, middleware, auth,
16
+ * plugin mounting and error handling all stay inside Hono, exactly as they are
17
+ * when the same app runs standalone in `apps/api` or under the Next.js catch-all
18
+ * in `apps/docs`. `ANY` is part of the framework's `RouteMethod` union and is
19
+ * what Start falls back to for any method it was given no handler for - `HEAD`
20
+ * included, where it calls this handler and strips the response body itself.
21
+ * So the API keeps answering for methods this file has never heard of, which is
22
+ * the point: there is nothing here to keep in sync with the API's routes.
23
+ *
24
+ * `src/tests/api-server-route.test.ts` drives the real request handler over this
25
+ * route to hold that to every method the API needs.
26
+ */
27
+ export const Route = createFileRoute('/api/$')({
28
+ server: {
29
+ handlers: ({ createHandlers }) =>
30
+ createHandlers({ ANY: async ({ request }) => apiBridge(request) }),
31
+ },
32
+ })
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The seam between the web runtime and the Hono API.
3
+ *
4
+ * A bridge is handed the `Request` the browser (or an SSR loader) made to
5
+ * `/api/*` on this origin and answers it with whatever Hono answers. It is one
6
+ * line, and that is the point: status, body, every `Set-Cookie`, the cookie and
7
+ * `x-forwarded-*` headers the API reads are all already correct on the request
8
+ * the platform built, and stay correct exactly as long as nobody rebuilds them.
9
+ *
10
+ * `src/tests/api-bridge-contract.ts` holds this to that behaviour, including the
11
+ * ways a rebuilt request loses it.
12
+ */
13
+ export type ApiBridge = (request: Request) => Promise<Response> | Response
14
+
15
+ interface FetchableApp {
16
+ fetch: (request: Request) => Promise<Response> | Response
17
+ }
18
+
19
+ export const createApiBridge =
20
+ (app: FetchableApp): ApiBridge =>
21
+ async (request) =>
22
+ app.fetch(request)
@@ -0,0 +1,29 @@
1
+ import '@tanstack/react-start/server-only'
2
+ import { OpenAPIHono } from '@hono/zod-openapi'
3
+ import { VitNodeAPI } from '@vitnode/core/api/config'
4
+
5
+ import { createApiBridge } from '#/server/api-bridge'
6
+ import { vitNodeApiConfig } from '#/vitnode.api.config'
7
+
8
+ // The same two lines `apps/api` and `apps/docs` run. `basePath("/api")` is what
9
+ // makes the mount point part of the API's own routing, so every path the plugins
10
+ // register - `/api/@vitnode/core/...` - resolves identically here.
11
+ const createVitNodeApi = () => {
12
+ const app = new OpenAPIHono().basePath('/api')
13
+
14
+ VitNodeAPI({ app, vitNodeApiConfig })
15
+
16
+ return app
17
+ }
18
+
19
+ // `VitNodeAPI` is a boot step, not a request step: it opens the Redis client,
20
+ // starts the cron scheduler and registers every plugin route. Vite re-evaluates
21
+ // server modules on HMR, so the instance is parked on `globalThis` to keep one
22
+ // API per process instead of one per edit.
23
+ const cache = globalThis as typeof globalThis & {
24
+ __vitnodeApi?: ReturnType<typeof createVitNodeApi>
25
+ }
26
+
27
+ export const vitNodeApi = (cache.__vitnodeApi ??= createVitNodeApi())
28
+
29
+ export const apiBridge = createApiBridge(vitNodeApi)
@@ -0,0 +1,36 @@
1
+ import { buildApiConfig } from "@vitnode/core/vitnode.config";
2
+ import { coreRelations } from "@vitnode/core/database/relations";
3
+ import { drizzle } from "drizzle-orm/postgres-js";
4
+
5
+ import { vitNodeConfig } from "./vitnode.config";
6
+
7
+ export const POSTGRES_URL =
8
+ process.env.POSTGRES_URL ?? "postgresql://root:root@localhost:5432/vitnode";
9
+
10
+ export const vitNodeApiConfig = buildApiConfig({
11
+ metadata: {
12
+ title: "VitNode",
13
+ shortTitle: "VitNode",
14
+ },
15
+ plugins: [],
16
+ /**
17
+ * The site's own locale declaration, because this app is both: `vitnode.config.ts`
18
+ * is the one statement of which languages exist, and both configs read it.
19
+ *
20
+ * It is also what `vitnode db:prepare` seeds `core_languages` from - this app
21
+ * owns the schema - so adding a language there and re-running `dev` inserts
22
+ * its row. Leave it out and the seed falls back to `en` alone, whatever the
23
+ * site serves.
24
+ */
25
+ i18n: vitNodeConfig.i18n,
26
+ dbProvider: drizzle({
27
+ connection: POSTGRES_URL,
28
+ relations: coreRelations,
29
+ }),
30
+ // Redis is opt-in: only enabled when REDIS_URL is set. Without it the cache
31
+ // is a no-op, the rate limiter uses in-memory storage, and WebSockets run in
32
+ // single-instance mode.
33
+ redis: process.env.REDIS_URL
34
+ ? { url: process.env.REDIS_URL, password: process.env.REDIS_PASSWORD }
35
+ : undefined,
36
+ });
@@ -0,0 +1,30 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ database:
5
+ container_name: vitnode_postgres_dev
6
+ image: postgres:17.5-alpine
7
+ restart: unless-stopped
8
+ environment:
9
+ POSTGRES_USER: ${POSTGRES_USER-root}
10
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD-root}
11
+ POSTGRES_DB: ${POSTGRES_NAME-vitnode}
12
+ volumes:
13
+ - ./docker/dev:/var/lib/postgresql/data
14
+ ports:
15
+ - '5432:5432'
16
+ networks:
17
+ - vitnode_dev
18
+
19
+ cache:
20
+ container_name: vitnode_redis_dev
21
+ image: redis:8.8-alpine
22
+ restart: unless-stopped
23
+ command: redis-server --requirepass ${REDIS_PASSWORD-root}
24
+ ports:
25
+ - '6379:6379'
26
+ networks:
27
+ - vitnode_dev
28
+
29
+ networks:
30
+ vitnode_dev:
@@ -1,4 +1,4 @@
1
- import vitnodePrettier from "eslint-config-typescript-vitnode/prettierrc";
1
+ import vitnodePrettier from "@vitnode/config/prettierrc";
2
2
 
3
3
  /**
4
4
  * @see https://prettier.io/docs/en/configuration.html
@@ -1,3 +1,19 @@
1
- import eslintVitNode from 'eslint-config-typescript-vitnode/eslint';
1
+ import eslintVitNode from "@vitnode/config/eslint";
2
+ import eslintVitNodeReact from "@vitnode/config/eslint.react";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname } from "node:path";
2
5
 
3
- export default [...eslintVitNode];
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+
8
+ export default [
9
+ ...eslintVitNode,
10
+ ...eslintVitNodeReact,
11
+ {
12
+ languageOptions: {
13
+ parserOptions: {
14
+ project: "./tsconfig.json",
15
+ tsconfigRootDir: __dirname,
16
+ },
17
+ },
18
+ },
19
+ ];
@@ -1,4 +1,4 @@
1
- import vitnodePrettier from "eslint-config-typescript-vitnode/prettierrc";
1
+ import vitnodePrettier from "@vitnode/config/prettierrc";
2
2
 
3
3
  /**
4
4
  * @see https://prettier.io/docs/en/configuration.html
@@ -0,0 +1,19 @@
1
+ import eslintVitNode from "@vitnode/config/eslint";
2
+ import eslintVitNodeReact from "@vitnode/config/eslint.react";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname } from "node:path";
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+
8
+ export default [
9
+ ...eslintVitNode,
10
+ ...eslintVitNodeReact,
11
+ {
12
+ languageOptions: {
13
+ parserOptions: {
14
+ project: "./tsconfig.json",
15
+ tsconfigRootDir: __dirname,
16
+ },
17
+ },
18
+ },
19
+ ];
@@ -0,0 +1,41 @@
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+ # Dependencies
4
+ node_modules
5
+ .pnp
6
+ .pnp.js
7
+
8
+ # Local env files
9
+ .env
10
+ .env.local
11
+ .env.development.local
12
+ .env.test.local
13
+ .env.production.local
14
+
15
+ # Testing
16
+ coverage
17
+
18
+ # Turbo
19
+ .turbo
20
+
21
+ # Vercel
22
+ .vercel
23
+
24
+ # Build Outputs
25
+ .output/
26
+ out/
27
+ build
28
+ dist
29
+
30
+
31
+ # Debug
32
+ npm-debug.log*
33
+ yarn-debug.log*
34
+ yarn-error.log*
35
+
36
+ # Misc
37
+ .DS_Store
38
+ *.pem
39
+
40
+ # VitNode
41
+ /docker
@@ -0,0 +1,12 @@
1
+ POSTGRES_URL=postgresql://root:root@localhost:5432/vitnode
2
+ REDIS_URL=redis://localhost:6379
3
+
4
+ NEXT_PUBLIC_WEB_URL=http://localhost:3000
5
+
6
+ # === Docker Database Postgres ===
7
+ POSTGRES_USER=root
8
+ POSTGRES_PASSWORD=root
9
+ POSTGRES_NAME=vitnode
10
+
11
+ # === Docker Redis ===
12
+ REDIS_PASSWORD=root
@@ -0,0 +1,12 @@
1
+ NEXT_PUBLIC_API_URL=http://localhost:8000
2
+
3
+ # Optional. Set these to back the Next.js caches with Redis, so cached pages and
4
+ # `use cache` entries are shared between instances and a tag revalidation on one
5
+ # instance is seen by all of them.
6
+ #
7
+ # The web process needs its own copy: the cache handlers are loaded by Next.js
8
+ # itself and read the environment directly - they cannot see the API's
9
+ # `vitnode.api.config.ts`. Point them at the same Redis the API uses.
10
+ # https://vitnode.com/docs/dev/advanced/redis#caching-nextjs-output
11
+ # REDIS_URL=redis://localhost:6379
12
+ # REDIS_PASSWORD=root