percher 0.4.0 → 0.4.1

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 (174) hide show
  1. package/dist/bin/percher.js +111049 -18287
  2. package/dist/package.json +13 -4
  3. package/dist/src/cli-utils.d.ts +9 -0
  4. package/dist/src/cli-utils.d.ts.map +1 -1
  5. package/dist/src/cli-utils.js +18 -0
  6. package/dist/src/cli-utils.js.map +1 -1
  7. package/dist/src/commands/account.d.ts.map +1 -1
  8. package/dist/src/commands/account.js +63 -7
  9. package/dist/src/commands/account.js.map +1 -1
  10. package/dist/src/commands/admin.d.ts +17 -0
  11. package/dist/src/commands/admin.d.ts.map +1 -0
  12. package/dist/src/commands/admin.js +92 -0
  13. package/dist/src/commands/admin.js.map +1 -0
  14. package/dist/src/commands/apps.d.ts.map +1 -1
  15. package/dist/src/commands/apps.js +60 -8
  16. package/dist/src/commands/apps.js.map +1 -1
  17. package/dist/src/commands/deploys.d.ts.map +1 -1
  18. package/dist/src/commands/deploys.js +12 -2
  19. package/dist/src/commands/deploys.js.map +1 -1
  20. package/dist/src/commands/migrate.d.ts +4 -0
  21. package/dist/src/commands/migrate.d.ts.map +1 -0
  22. package/dist/src/commands/migrate.js +142 -0
  23. package/dist/src/commands/migrate.js.map +1 -0
  24. package/dist/src/commands/sharing.d.ts +23 -0
  25. package/dist/src/commands/sharing.d.ts.map +1 -0
  26. package/dist/src/commands/sharing.js +162 -0
  27. package/dist/src/commands/sharing.js.map +1 -0
  28. package/dist/src/commands/transfers.d.ts +20 -0
  29. package/dist/src/commands/transfers.d.ts.map +1 -0
  30. package/dist/src/commands/transfers.js +117 -0
  31. package/dist/src/commands/transfers.js.map +1 -0
  32. package/dist/src/index.d.ts.map +1 -1
  33. package/dist/src/index.js +42 -4
  34. package/dist/src/index.js.map +1 -1
  35. package/dist/templates/astro/Caddyfile +6 -0
  36. package/dist/templates/astro/Dockerfile +34 -0
  37. package/dist/templates/astro/astro.config.mjs +3 -0
  38. package/dist/templates/astro/package.json +14 -0
  39. package/dist/templates/astro/percher.toml +11 -0
  40. package/dist/templates/astro/src/pages/index.astro +15 -0
  41. package/dist/templates/bun/index.ts +23 -0
  42. package/dist/templates/bun/package.json +8 -0
  43. package/dist/templates/bun/percher.toml +10 -0
  44. package/dist/templates/django/Procfile +1 -0
  45. package/dist/templates/django/app/__init__.py +0 -0
  46. package/dist/templates/django/app/settings.py +44 -0
  47. package/dist/templates/django/app/urls.py +21 -0
  48. package/dist/templates/django/app/wsgi.py +5 -0
  49. package/dist/templates/django/manage.py +19 -0
  50. package/dist/templates/django/percher.toml +11 -0
  51. package/dist/templates/django/requirements.txt +2 -0
  52. package/dist/templates/dotnet/Dockerfile +18 -0
  53. package/dist/templates/dotnet/Program.cs +23 -0
  54. package/dist/templates/dotnet/app.csproj +9 -0
  55. package/dist/templates/dotnet/percher.toml +11 -0
  56. package/dist/templates/eleventy/.eleventy.js +12 -0
  57. package/dist/templates/eleventy/Caddyfile +6 -0
  58. package/dist/templates/eleventy/Dockerfile +34 -0
  59. package/dist/templates/eleventy/package.json +12 -0
  60. package/dist/templates/eleventy/percher.toml +11 -0
  61. package/dist/templates/eleventy/src/_includes/base.njk +12 -0
  62. package/dist/templates/eleventy/src/assets/style.css +12 -0
  63. package/dist/templates/eleventy/src/index.md +10 -0
  64. package/dist/templates/elysia/index.ts +8 -0
  65. package/dist/templates/elysia/package.json +12 -0
  66. package/dist/templates/elysia/percher.toml +11 -0
  67. package/dist/templates/express/index.ts +16 -0
  68. package/dist/templates/express/package.json +11 -0
  69. package/dist/templates/express/percher.toml +11 -0
  70. package/dist/templates/fastify/index.ts +13 -0
  71. package/dist/templates/fastify/package.json +11 -0
  72. package/dist/templates/fastify/percher.toml +11 -0
  73. package/dist/templates/flask/main.py +23 -0
  74. package/dist/templates/flask/percher.toml +11 -0
  75. package/dist/templates/flask/requirements.txt +1 -0
  76. package/dist/templates/go/Dockerfile +11 -0
  77. package/dist/templates/go/go.mod +3 -0
  78. package/dist/templates/go/main.go +53 -0
  79. package/dist/templates/go/percher.toml +11 -0
  80. package/dist/templates/hono/index.ts +12 -0
  81. package/dist/templates/hono/package.json +11 -0
  82. package/dist/templates/hono/percher.toml +11 -0
  83. package/dist/templates/htmx/index.ts +32 -0
  84. package/dist/templates/htmx/package.json +15 -0
  85. package/dist/templates/htmx/percher.toml +11 -0
  86. package/dist/templates/hugo/Caddyfile +6 -0
  87. package/dist/templates/hugo/Dockerfile +32 -0
  88. package/dist/templates/hugo/content/_index.md +7 -0
  89. package/dist/templates/hugo/hugo.toml +11 -0
  90. package/dist/templates/hugo/layouts/index.html +22 -0
  91. package/dist/templates/hugo/percher.toml +11 -0
  92. package/dist/templates/java/Dockerfile +15 -0
  93. package/dist/templates/java/Main.java +77 -0
  94. package/dist/templates/java/percher.toml +11 -0
  95. package/dist/templates/laravel/Dockerfile +15 -0
  96. package/dist/templates/laravel/composer.json +15 -0
  97. package/dist/templates/laravel/percher.toml +11 -0
  98. package/dist/templates/laravel/public/index.php +37 -0
  99. package/dist/templates/nextjs/app/api/health/route.ts +3 -0
  100. package/dist/templates/nextjs/app/layout.tsx +11 -0
  101. package/dist/templates/nextjs/app/page.tsx +10 -0
  102. package/dist/templates/nextjs/next.config.ts +5 -0
  103. package/dist/templates/nextjs/package.json +15 -0
  104. package/dist/templates/nextjs/percher.toml +15 -0
  105. package/dist/templates/node/index.js +26 -0
  106. package/dist/templates/node/index.ts +12 -0
  107. package/dist/templates/node/package.json +8 -0
  108. package/dist/templates/node/percher.toml +10 -0
  109. package/dist/templates/nuxt/app.vue +6 -0
  110. package/dist/templates/nuxt/nuxt.config.ts +4 -0
  111. package/dist/templates/nuxt/package.json +15 -0
  112. package/dist/templates/nuxt/percher.toml +15 -0
  113. package/dist/templates/nuxt/server/api/health.ts +1 -0
  114. package/dist/templates/phoenix/Dockerfile +15 -0
  115. package/dist/templates/phoenix/lib/application.ex +15 -0
  116. package/dist/templates/phoenix/lib/router.ex +39 -0
  117. package/dist/templates/phoenix/mix.exs +30 -0
  118. package/dist/templates/phoenix/percher.toml +11 -0
  119. package/dist/templates/preact/Caddyfile +7 -0
  120. package/dist/templates/preact/Dockerfile +34 -0
  121. package/dist/templates/preact/index.html +12 -0
  122. package/dist/templates/preact/package.json +19 -0
  123. package/dist/templates/preact/percher.toml +11 -0
  124. package/dist/templates/preact/src/main.tsx +13 -0
  125. package/dist/templates/preact/vite.config.ts +6 -0
  126. package/dist/templates/python/main.py +13 -0
  127. package/dist/templates/python/percher.toml +11 -0
  128. package/dist/templates/python/requirements.txt +2 -0
  129. package/dist/templates/rails/Dockerfile +11 -0
  130. package/dist/templates/rails/Gemfile +12 -0
  131. package/dist/templates/rails/config.ru +32 -0
  132. package/dist/templates/rails/percher.toml +11 -0
  133. package/dist/templates/remix/app/root.tsx +19 -0
  134. package/dist/templates/remix/app/routes/_index.tsx +10 -0
  135. package/dist/templates/remix/app/routes/health.tsx +3 -0
  136. package/dist/templates/remix/package.json +30 -0
  137. package/dist/templates/remix/percher.toml +15 -0
  138. package/dist/templates/remix/vite.config.ts +7 -0
  139. package/dist/templates/rust/Cargo.toml +19 -0
  140. package/dist/templates/rust/Dockerfile +14 -0
  141. package/dist/templates/rust/percher.toml +11 -0
  142. package/dist/templates/rust/src/main.rs +45 -0
  143. package/dist/templates/solid/Caddyfile +7 -0
  144. package/dist/templates/solid/Dockerfile +34 -0
  145. package/dist/templates/solid/index.html +12 -0
  146. package/dist/templates/solid/package.json +19 -0
  147. package/dist/templates/solid/percher.toml +11 -0
  148. package/dist/templates/solid/src/main.tsx +13 -0
  149. package/dist/templates/solid/vite.config.ts +6 -0
  150. package/dist/templates/static/index.html +15 -0
  151. package/dist/templates/static/percher.toml +6 -0
  152. package/dist/templates/static/style.css +32 -0
  153. package/dist/templates/sveltekit/package.json +19 -0
  154. package/dist/templates/sveltekit/percher.toml +15 -0
  155. package/dist/templates/sveltekit/src/app.html +12 -0
  156. package/dist/templates/sveltekit/src/routes/+page.svelte +2 -0
  157. package/dist/templates/sveltekit/src/routes/health/+server.ts +5 -0
  158. package/dist/templates/sveltekit/svelte.config.js +8 -0
  159. package/dist/templates/sveltekit/vite.config.js +6 -0
  160. package/dist/templates/vite-react/Caddyfile +7 -0
  161. package/dist/templates/vite-react/Dockerfile +34 -0
  162. package/dist/templates/vite-react/index.html +12 -0
  163. package/dist/templates/vite-react/package.json +22 -0
  164. package/dist/templates/vite-react/percher.toml +11 -0
  165. package/dist/templates/vite-react/src/main.tsx +20 -0
  166. package/dist/templates/vite-react/vite.config.ts +6 -0
  167. package/dist/templates/vite-vue/Caddyfile +7 -0
  168. package/dist/templates/vite-vue/Dockerfile +34 -0
  169. package/dist/templates/vite-vue/index.html +12 -0
  170. package/dist/templates/vite-vue/package.json +19 -0
  171. package/dist/templates/vite-vue/percher.toml +11 -0
  172. package/dist/templates/vite-vue/src/main.ts +12 -0
  173. package/dist/templates/vite-vue/vite.config.ts +6 -0
  174. package/package.json +13 -4
@@ -0,0 +1,11 @@
1
+ export const metadata = {
2
+ title: "__APP_NAME__",
3
+ };
4
+
5
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
6
+ return (
7
+ <html lang="en">
8
+ <body>{children}</body>
9
+ </html>
10
+ );
11
+ }
@@ -0,0 +1,10 @@
1
+ export default function Home() {
2
+ return (
3
+ <main style={{ fontFamily: "system-ui", padding: "2rem", maxWidth: 600, margin: "0 auto" }}>
4
+ <h1>__APP_NAME__</h1>
5
+ <p>
6
+ Edit <code>app/page.tsx</code> and run <code>bunx percher push</code> to deploy.
7
+ </p>
8
+ </main>
9
+ );
10
+ }
@@ -0,0 +1,5 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {};
4
+
5
+ export default nextConfig;
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "__APP_NAME__",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start"
9
+ },
10
+ "dependencies": {
11
+ "next": "^15.0.0",
12
+ "react": "^19.0.0",
13
+ "react-dom": "^19.0.0"
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ [app]
2
+ name = "__APP_NAME__"
3
+ runtime = "node"
4
+ framework = "nextjs"
5
+
6
+ [build]
7
+ command = "bun run build"
8
+ output = ".next"
9
+
10
+ [web]
11
+ port = 3000
12
+ health = "/api/health"
13
+
14
+ [data]
15
+ mode = "none"
@@ -0,0 +1,26 @@
1
+ const http = require("node:http");
2
+
3
+ const port = Number(process.env.PORT ?? 3000);
4
+
5
+ const server = http.createServer((req, res) => {
6
+ const url = new URL(req.url, `http://${req.headers.host}`);
7
+
8
+ if (url.pathname === "/health") {
9
+ res.writeHead(200, { "Content-Type": "application/json" });
10
+ res.end(JSON.stringify({ status: "ok" }));
11
+ return;
12
+ }
13
+
14
+ if (url.pathname === "/") {
15
+ res.writeHead(200, { "Content-Type": "text/plain" });
16
+ res.end("Hello from __APP_NAME__!");
17
+ return;
18
+ }
19
+
20
+ res.writeHead(404, { "Content-Type": "text/plain" });
21
+ res.end("Not found");
22
+ });
23
+
24
+ server.listen(port, "0.0.0.0", () => {
25
+ console.log(`[__APP_NAME__] listening on http://0.0.0.0:${port}`);
26
+ });
@@ -0,0 +1,12 @@
1
+ const server = Bun.serve({
2
+ port: Number(process.env.PORT ?? 3000),
3
+ fetch(req) {
4
+ const url = new URL(req.url);
5
+ if (url.pathname === "/health") {
6
+ return Response.json({ status: "ok" });
7
+ }
8
+ return new Response("Hello from __APP_NAME__!");
9
+ },
10
+ });
11
+
12
+ console.log(`Listening on http://localhost:${server.port}`);
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "__APP_NAME__",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "start": "node index.js"
7
+ }
8
+ }
@@ -0,0 +1,10 @@
1
+ [app]
2
+ name = "__APP_NAME__"
3
+ runtime = "node"
4
+
5
+ [web]
6
+ port = 3000
7
+ health = "/health"
8
+
9
+ [data]
10
+ mode = "none"
@@ -0,0 +1,6 @@
1
+ <template>
2
+ <main style="font-family: system-ui; padding: 40px;">
3
+ <h1>Hello from __APP_NAME__</h1>
4
+ <p>Nuxt 3 on Percher. Edit <code>app.vue</code> or add pages under <code>pages/</code>.</p>
5
+ </main>
6
+ </template>
@@ -0,0 +1,4 @@
1
+ export default defineNuxtConfig({
2
+ compatibilityDate: "2025-01-01",
3
+ devtools: { enabled: true },
4
+ });
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "__APP_NAME__",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "build": "nuxt build",
8
+ "dev": "nuxt dev",
9
+ "start": "node .output/server/index.mjs"
10
+ },
11
+ "devDependencies": {
12
+ "nuxt": "^3.13.0",
13
+ "vue": "^3.4.0"
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ [app]
2
+ name = "__APP_NAME__"
3
+ runtime = "node"
4
+ framework = "nuxt"
5
+
6
+ [build]
7
+ command = "bun run build"
8
+ output = ".output"
9
+
10
+ [web]
11
+ port = 3000
12
+ health = "/api/health"
13
+
14
+ [data]
15
+ mode = "none"
@@ -0,0 +1 @@
1
+ export default defineEventHandler(() => ({ status: "ok" }));
@@ -0,0 +1,15 @@
1
+ FROM elixir:1.17-alpine
2
+ WORKDIR /app
3
+ RUN apk add --no-cache build-base \
4
+ && addgroup -S app && adduser -S app -G app \
5
+ && mkdir -p /home/app/.mix \
6
+ && chown -R app:app /home/app /app
7
+ USER app
8
+ RUN mix local.hex --force && mix local.rebar --force
9
+ COPY --chown=app:app mix.exs ./
10
+ RUN mix deps.get
11
+ COPY --chown=app:app . .
12
+ RUN mix compile
13
+ ENV PORT=4000
14
+ EXPOSE 4000
15
+ CMD ["mix", "run", "--no-halt"]
@@ -0,0 +1,15 @@
1
+ defmodule PercherApp.Application do
2
+ use Application
3
+
4
+ @impl true
5
+ def start(_type, _args) do
6
+ port = String.to_integer(System.get_env("PORT") || "4000")
7
+
8
+ children = [
9
+ {Bandit, plug: PercherApp.Router, port: port}
10
+ ]
11
+
12
+ opts = [strategy: :one_for_one, name: PercherApp.Supervisor]
13
+ Supervisor.start_link(children, opts)
14
+ end
15
+ end
@@ -0,0 +1,39 @@
1
+ defmodule PercherApp.Router do
2
+ use Plug.Router
3
+
4
+ plug(:match)
5
+ plug(:dispatch)
6
+
7
+ get "/health" do
8
+ send_resp(conn, 200, Jason.encode!(%{ok: true}))
9
+ end
10
+
11
+ get "/" do
12
+ html = """
13
+ <!doctype html>
14
+ <html lang="en">
15
+ <head>
16
+ <meta charset="utf-8" />
17
+ <title>__APP_NAME__</title>
18
+ <style>
19
+ body { font-family: system-ui, sans-serif; max-width: 640px; margin: 48px auto; padding: 0 24px; line-height: 1.6; }
20
+ h1 { letter-spacing: -0.5px; }
21
+ </style>
22
+ </head>
23
+ <body>
24
+ <h1>__APP_NAME__</h1>
25
+ <p>An Elixir app deployed on Percher.</p>
26
+ <p>To upgrade to full Phoenix, run <code>mix phx.new .</code> in this directory (replaces the current skeleton).</p>
27
+ </body>
28
+ </html>
29
+ """
30
+
31
+ conn
32
+ |> put_resp_content_type("text/html; charset=utf-8")
33
+ |> send_resp(200, html)
34
+ end
35
+
36
+ match _ do
37
+ send_resp(conn, 404, "Not found")
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ defmodule PercherApp.MixProject do
2
+ use Mix.Project
3
+
4
+ def project do
5
+ [
6
+ app: :percher_app,
7
+ version: "0.1.0",
8
+ elixir: "~> 1.17",
9
+ start_permanent: Mix.env() == :prod,
10
+ deps: deps()
11
+ ]
12
+ end
13
+
14
+ def application do
15
+ [
16
+ extra_applications: [:logger],
17
+ mod: {PercherApp.Application, []}
18
+ ]
19
+ end
20
+
21
+ # Minimal Plug + Bandit. Run `mix phx.new .` once you're ready to upgrade
22
+ # to the full Phoenix framework — you'll replace this project skeleton.
23
+ defp deps do
24
+ [
25
+ {:plug, "~> 1.16"},
26
+ {:bandit, "~> 1.5"},
27
+ {:jason, "~> 1.4"}
28
+ ]
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ [app]
2
+ name = "__APP_NAME__"
3
+ runtime = "docker"
4
+ framework = "phoenix"
5
+
6
+ [web]
7
+ port = 4000
8
+ health = "/health"
9
+
10
+ [data]
11
+ mode = "none"
@@ -0,0 +1,7 @@
1
+ :8080 {
2
+ bind 0.0.0.0
3
+ root * /srv
4
+ encode gzip zstd
5
+ try_files {path} /index.html
6
+ file_server
7
+ }
@@ -0,0 +1,34 @@
1
+ # Multi-stage build: a Bun stage compiles the static bundle, then a
2
+ # minimal Caddy image serves it. This project uses runtime = "docker"
3
+ # (not "static") because Percher's static runtime serves pre-built
4
+ # files only — it does not run a build command. Generated by Percher;
5
+ # safe to edit and own.
6
+
7
+ # --- Build stage: install deps and build the static bundle -----------
8
+ FROM oven/bun:1-alpine AS build
9
+ WORKDIR /app
10
+ COPY . .
11
+ RUN bun install && bun run build
12
+
13
+ # --- Serve stage: minimal Caddy image --------------------------------
14
+ # caddy:2-alpine ships /usr/bin/caddy with cap_net_bind_service file
15
+ # caps. Percher runs every container with --security-opt
16
+ # no-new-privileges, which makes execve refuse a cap-bearing binary
17
+ # (an "operation not permitted" crash-loop). Copy Caddy onto a plain
18
+ # alpine base and strip the caps with setcap -r — Caddy never needs
19
+ # the cap here, it listens on :8080 (>= 1024).
20
+ FROM caddy:2-alpine AS caddy-source
21
+ FROM alpine:3.21
22
+ COPY --from=caddy-source /usr/bin/caddy /usr/bin/caddy
23
+ RUN apk add --no-cache libcap \
24
+ && setcap -r /usr/bin/caddy \
25
+ && apk del libcap \
26
+ && rm -rf /var/cache/apk/*
27
+ COPY Caddyfile /etc/caddy/Caddyfile
28
+ COPY --from=build /app/dist /srv
29
+ # HOME points at the writable tmpfs so non-root Caddy can persist its
30
+ # XDG state (storage-clean lock, config autosave) under Percher's
31
+ # read-only root filesystem.
32
+ ENV HOME=/tmp
33
+ EXPOSE 8080
34
+ CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
@@ -0,0 +1,12 @@
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>__APP_NAME__</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "__APP_NAME__",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "preact": "^10.22.0"
13
+ },
14
+ "devDependencies": {
15
+ "@preact/preset-vite": "^2.9.0",
16
+ "vite": "^5.3.0",
17
+ "typescript": "^5.5.0"
18
+ }
19
+ }
@@ -0,0 +1,11 @@
1
+ [app]
2
+ name = "__APP_NAME__"
3
+ runtime = "docker"
4
+ framework = "preact"
5
+
6
+ [web]
7
+ port = 8080
8
+ health = "/"
9
+
10
+ [data]
11
+ mode = "none"
@@ -0,0 +1,13 @@
1
+ import { render } from "preact";
2
+
3
+ function App() {
4
+ return (
5
+ <main style={{ fontFamily: "system-ui", padding: 40 }}>
6
+ <h1>Hello from __APP_NAME__</h1>
7
+ <p>Preact + Vite, served as static from Percher.</p>
8
+ </main>
9
+ );
10
+ }
11
+
12
+ const root = document.getElementById("app");
13
+ if (root) render(<App />, root);
@@ -0,0 +1,6 @@
1
+ import preact from "@preact/preset-vite";
2
+ import { defineConfig } from "vite";
3
+
4
+ export default defineConfig({
5
+ plugins: [preact()],
6
+ });
@@ -0,0 +1,13 @@
1
+ from fastapi import FastAPI
2
+
3
+ app = FastAPI()
4
+
5
+
6
+ @app.get("/health")
7
+ async def health():
8
+ return {"status": "ok"}
9
+
10
+
11
+ @app.get("/")
12
+ async def root():
13
+ return {"message": "Hello from __APP_NAME__!"}
@@ -0,0 +1,11 @@
1
+ [app]
2
+ name = "__APP_NAME__"
3
+ runtime = "python"
4
+ framework = "fastapi"
5
+
6
+ [web]
7
+ port = 8000
8
+ health = "/health"
9
+
10
+ [data]
11
+ mode = "none"
@@ -0,0 +1,2 @@
1
+ fastapi>=0.115.0
2
+ uvicorn>=0.32.0
@@ -0,0 +1,11 @@
1
+ FROM ruby:3.3-alpine
2
+ WORKDIR /app
3
+ RUN apk add --no-cache build-base \
4
+ && addgroup -S app && adduser -S app -G app
5
+ COPY --chown=app:app Gemfile ./
6
+ RUN bundle install --jobs 4 --retry 3
7
+ COPY --chown=app:app . .
8
+ RUN chown -R app:app /app /usr/local/bundle
9
+ USER app
10
+ EXPOSE 3000
11
+ CMD ["bundle", "exec", "rackup", "-o", "0.0.0.0", "-p", "3000"]
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ ruby "~> 3.3"
4
+
5
+ # Minimal Rack app — run `rails new . --force` (with rails + sqlite3 gems added)
6
+ # to upgrade to a full Rails project once you're ready.
7
+ gem "rack", "~> 3.1"
8
+ gem "rackup", "~> 2.1"
9
+ # rackup 2.x no longer ships a default handler — pick one explicitly.
10
+ # webrick is the lightest stdlib option for the starter; swap to puma
11
+ # / falcon when scaling.
12
+ gem "webrick", "~> 1.8"
@@ -0,0 +1,32 @@
1
+ require "json"
2
+
3
+ app = lambda do |env|
4
+ case env["PATH_INFO"]
5
+ when "/health"
6
+ [200, { "content-type" => "application/json" }, [JSON.generate({ ok: true })]]
7
+ when "/"
8
+ html = <<~HTML
9
+ <!doctype html>
10
+ <html lang="en">
11
+ <head>
12
+ <meta charset="utf-8" />
13
+ <title>__APP_NAME__</title>
14
+ <style>
15
+ body { font-family: system-ui, sans-serif; max-width: 640px; margin: 48px auto; padding: 0 24px; line-height: 1.6; }
16
+ h1 { letter-spacing: -0.5px; }
17
+ </style>
18
+ </head>
19
+ <body>
20
+ <h1>__APP_NAME__</h1>
21
+ <p>A Ruby app deployed on Percher.</p>
22
+ <p>To upgrade to full Rails, add <code>rails</code> to the Gemfile and run <code>bundle install &amp;&amp; rails new . --force --skip-bundle</code>.</p>
23
+ </body>
24
+ </html>
25
+ HTML
26
+ [200, { "content-type" => "text/html; charset=utf-8" }, [html]]
27
+ else
28
+ [404, { "content-type" => "text/plain" }, ["Not found"]]
29
+ end
30
+ end
31
+
32
+ run app
@@ -0,0 +1,11 @@
1
+ [app]
2
+ name = "__APP_NAME__"
3
+ runtime = "docker"
4
+ framework = "rails"
5
+
6
+ [web]
7
+ port = 3000
8
+ health = "/health"
9
+
10
+ [data]
11
+ mode = "none"
@@ -0,0 +1,19 @@
1
+ import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "@remix-run/react";
2
+
3
+ export default function App() {
4
+ return (
5
+ <html lang="en">
6
+ <head>
7
+ <meta charSet="utf-8" />
8
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
9
+ <Meta />
10
+ <Links />
11
+ </head>
12
+ <body>
13
+ <Outlet />
14
+ <ScrollRestoration />
15
+ <Scripts />
16
+ </body>
17
+ </html>
18
+ );
19
+ }
@@ -0,0 +1,10 @@
1
+ export default function Index() {
2
+ return (
3
+ <main style={{ fontFamily: "system-ui", padding: 40 }}>
4
+ <h1>Hello from __APP_NAME__</h1>
5
+ <p>
6
+ Remix on Percher. Add routes under <code>app/routes/</code>.
7
+ </p>
8
+ </main>
9
+ );
10
+ }
@@ -0,0 +1,3 @@
1
+ export function loader() {
2
+ return Response.json({ status: "ok" });
3
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "__APP_NAME__",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "build": "remix vite:build",
8
+ "dev": "remix vite:dev",
9
+ "start": "remix-serve ./build/server/index.js"
10
+ },
11
+ "dependencies": {
12
+ "@remix-run/node": "^2.13.0",
13
+ "@remix-run/react": "^2.13.0",
14
+ "@remix-run/serve": "^2.13.0",
15
+ "isbot": "^5.1.0",
16
+ "react": "^18.3.0",
17
+ "react-dom": "^18.3.0"
18
+ },
19
+ "devDependencies": {
20
+ "@remix-run/dev": "^2.13.0",
21
+ "@types/react": "^18.3.0",
22
+ "@types/react-dom": "^18.3.0",
23
+ "typescript": "^5.5.0",
24
+ "vite": "^5.3.0",
25
+ "vite-tsconfig-paths": "^5.0.0"
26
+ },
27
+ "engines": {
28
+ "node": ">=22.0.0"
29
+ }
30
+ }
@@ -0,0 +1,15 @@
1
+ [app]
2
+ name = "__APP_NAME__"
3
+ runtime = "node"
4
+ framework = "remix"
5
+
6
+ [build]
7
+ command = "bun run build"
8
+ output = "build"
9
+
10
+ [web]
11
+ port = 3000
12
+ health = "/health"
13
+
14
+ [data]
15
+ mode = "none"
@@ -0,0 +1,7 @@
1
+ import { vitePlugin as remix } from "@remix-run/dev";
2
+ import { defineConfig } from "vite";
3
+ import tsconfigPaths from "vite-tsconfig-paths";
4
+
5
+ export default defineConfig({
6
+ plugins: [remix(), tsconfigPaths()],
7
+ });
@@ -0,0 +1,19 @@
1
+ [package]
2
+ name = "app"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "__APP_NAME__ on Percher"
6
+
7
+ [[bin]]
8
+ name = "app"
9
+ path = "src/main.rs"
10
+
11
+ [dependencies]
12
+ axum = "0.7"
13
+ tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
14
+
15
+ [profile.release]
16
+ opt-level = "z"
17
+ lto = true
18
+ codegen-units = 1
19
+ strip = true
@@ -0,0 +1,14 @@
1
+ FROM rust:1.82-alpine AS build
2
+ RUN apk add --no-cache musl-dev
3
+ WORKDIR /src
4
+ COPY Cargo.toml Cargo.lock* ./
5
+ COPY src ./src
6
+ RUN cargo build --release --bin app
7
+
8
+ FROM alpine:3.20
9
+ RUN apk add --no-cache ca-certificates \
10
+ && addgroup -S app && adduser -S app -G app
11
+ COPY --from=build --chown=app:app /src/target/release/app /app
12
+ USER app
13
+ EXPOSE 8080
14
+ CMD ["/app"]
@@ -0,0 +1,11 @@
1
+ [app]
2
+ name = "__APP_NAME__"
3
+ runtime = "docker"
4
+ framework = "rust"
5
+
6
+ [web]
7
+ port = 8080
8
+ health = "/health"
9
+
10
+ [data]
11
+ mode = "none"