render-create 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +207 -0
  2. package/dist/cli.d.ts +6 -0
  3. package/dist/cli.js +45 -0
  4. package/dist/commands/check.d.ts +8 -0
  5. package/dist/commands/check.js +96 -0
  6. package/dist/commands/init.d.ts +12 -0
  7. package/dist/commands/init.js +1201 -0
  8. package/dist/commands/sync.d.ts +8 -0
  9. package/dist/commands/sync.js +126 -0
  10. package/dist/types.d.ts +246 -0
  11. package/dist/types.js +4 -0
  12. package/dist/utils.d.ts +53 -0
  13. package/dist/utils.js +142 -0
  14. package/package.json +65 -0
  15. package/templates/LINTING_SETUP.md +205 -0
  16. package/templates/README_TEMPLATE.md +68 -0
  17. package/templates/STYLE_GUIDE.md +241 -0
  18. package/templates/assets/favicon.png +0 -0
  19. package/templates/assets/favicon.svg +17 -0
  20. package/templates/biome.json +43 -0
  21. package/templates/cursor/rules/drizzle.mdc +165 -0
  22. package/templates/cursor/rules/fastify.mdc +132 -0
  23. package/templates/cursor/rules/general.mdc +112 -0
  24. package/templates/cursor/rules/nextjs.mdc +89 -0
  25. package/templates/cursor/rules/python.mdc +89 -0
  26. package/templates/cursor/rules/react.mdc +200 -0
  27. package/templates/cursor/rules/sqlalchemy.mdc +205 -0
  28. package/templates/cursor/rules/tailwind.mdc +139 -0
  29. package/templates/cursor/rules/typescript.mdc +112 -0
  30. package/templates/cursor/rules/vite.mdc +169 -0
  31. package/templates/cursor/rules/workflows.mdc +349 -0
  32. package/templates/docker-compose.example.yml +55 -0
  33. package/templates/drizzle/db-index.ts +15 -0
  34. package/templates/drizzle/drizzle.config.ts +10 -0
  35. package/templates/drizzle/schema.ts +12 -0
  36. package/templates/env.example +15 -0
  37. package/templates/fastapi/app/__init__.py +1 -0
  38. package/templates/fastapi/app/config.py +12 -0
  39. package/templates/fastapi/app/database.py +16 -0
  40. package/templates/fastapi/app/models.py +13 -0
  41. package/templates/fastapi/main.py +22 -0
  42. package/templates/fastify/index.ts +40 -0
  43. package/templates/github/CODEOWNERS +10 -0
  44. package/templates/github/ISSUE_TEMPLATE/bug_report.md +39 -0
  45. package/templates/github/ISSUE_TEMPLATE/feature_request.md +23 -0
  46. package/templates/github/PULL_REQUEST_TEMPLATE.md +25 -0
  47. package/templates/gitignore/node.gitignore +41 -0
  48. package/templates/gitignore/python.gitignore +49 -0
  49. package/templates/multi-api/README.md +60 -0
  50. package/templates/multi-api/gitignore +28 -0
  51. package/templates/multi-api/node-api/drizzle.config.ts +10 -0
  52. package/templates/multi-api/node-api/package-simple.json +13 -0
  53. package/templates/multi-api/node-api/package.json +16 -0
  54. package/templates/multi-api/node-api/src/db/index.ts +13 -0
  55. package/templates/multi-api/node-api/src/db/schema.ts +9 -0
  56. package/templates/multi-api/node-api/src/index-simple.ts +36 -0
  57. package/templates/multi-api/node-api/src/index.ts +50 -0
  58. package/templates/multi-api/node-api/tsconfig.json +20 -0
  59. package/templates/multi-api/python-api/app/__init__.py +1 -0
  60. package/templates/multi-api/python-api/app/config.py +12 -0
  61. package/templates/multi-api/python-api/app/database.py +16 -0
  62. package/templates/multi-api/python-api/app/models.py +13 -0
  63. package/templates/multi-api/python-api/main-simple.py +25 -0
  64. package/templates/multi-api/python-api/main.py +44 -0
  65. package/templates/multi-api/python-api/requirements-simple.txt +3 -0
  66. package/templates/multi-api/python-api/requirements.txt +8 -0
  67. package/templates/next/globals.css +126 -0
  68. package/templates/next/layout.tsx +34 -0
  69. package/templates/next/next.config.static.ts +10 -0
  70. package/templates/next/page-fullstack.tsx +120 -0
  71. package/templates/next/page.tsx +72 -0
  72. package/templates/presets.json +581 -0
  73. package/templates/ruff.toml +30 -0
  74. package/templates/tsconfig.base.json +17 -0
  75. package/templates/vite/index.css +127 -0
  76. package/templates/vite/vite.config.ts +7 -0
  77. package/templates/worker/py/cron.py +53 -0
  78. package/templates/worker/py/worker.py +95 -0
  79. package/templates/worker/py/workflow.py +73 -0
  80. package/templates/worker/ts/cron.ts +49 -0
  81. package/templates/worker/ts/worker.ts +84 -0
  82. package/templates/worker/ts/workflow.ts +67 -0
@@ -0,0 +1,127 @@
1
+ @import "tailwindcss";
2
+ @plugin "@tailwindcss/typography";
3
+
4
+ /*
5
+ * Brutalist Design Defaults
6
+ * - Black background, white text
7
+ * - No rounded corners
8
+ * - High contrast borders
9
+ * - No gradients or shadows
10
+ */
11
+
12
+ :root {
13
+ --background: #000000;
14
+ --foreground: #ffffff;
15
+ --border: #ffffff;
16
+ --muted: #888888;
17
+ }
18
+
19
+ * {
20
+ border-radius: 0 !important;
21
+ }
22
+
23
+ html {
24
+ color-scheme: dark;
25
+ }
26
+
27
+ body {
28
+ background: var(--background);
29
+ color: var(--foreground);
30
+ font-family: system-ui, -apple-system, sans-serif;
31
+ margin: 0;
32
+ }
33
+
34
+ /* Links */
35
+ a {
36
+ color: var(--foreground);
37
+ text-decoration: underline;
38
+ }
39
+
40
+ a:hover {
41
+ text-decoration: none;
42
+ }
43
+
44
+ /* Buttons - brutalist style */
45
+ button,
46
+ [role="button"],
47
+ input[type="submit"],
48
+ input[type="button"] {
49
+ background: var(--foreground);
50
+ color: var(--background);
51
+ border: 1px solid var(--foreground);
52
+ padding: 0.75rem 1.5rem;
53
+ font-weight: 600;
54
+ cursor: pointer;
55
+ transition: all 0.15s ease;
56
+ }
57
+
58
+ button:hover,
59
+ [role="button"]:hover,
60
+ input[type="submit"]:hover,
61
+ input[type="button"]:hover {
62
+ background: transparent;
63
+ color: var(--foreground);
64
+ }
65
+
66
+ /* Secondary/outline buttons */
67
+ button.secondary,
68
+ .btn-secondary {
69
+ background: transparent;
70
+ color: var(--foreground);
71
+ }
72
+
73
+ button.secondary:hover,
74
+ .btn-secondary:hover {
75
+ background: var(--foreground);
76
+ color: var(--background);
77
+ }
78
+
79
+ /* Inputs */
80
+ input,
81
+ textarea,
82
+ select {
83
+ background: transparent;
84
+ border: 1px solid var(--foreground);
85
+ color: var(--foreground);
86
+ padding: 0.75rem;
87
+ }
88
+
89
+ input::placeholder,
90
+ textarea::placeholder {
91
+ color: var(--muted);
92
+ }
93
+
94
+ input:focus,
95
+ textarea:focus,
96
+ select:focus {
97
+ outline: none;
98
+ border-color: var(--foreground);
99
+ box-shadow: 0 0 0 1px var(--foreground);
100
+ }
101
+
102
+ /* Cards/containers */
103
+ .card,
104
+ [class*="card"] {
105
+ background: transparent;
106
+ border: 1px solid var(--foreground);
107
+ padding: 1.5rem;
108
+ }
109
+
110
+ /* Typography - dark theme overrides */
111
+ .prose {
112
+ --tw-prose-body: var(--foreground);
113
+ --tw-prose-headings: var(--foreground);
114
+ --tw-prose-links: var(--foreground);
115
+ --tw-prose-bold: var(--foreground);
116
+ --tw-prose-counters: var(--muted);
117
+ --tw-prose-bullets: var(--muted);
118
+ --tw-prose-hr: var(--foreground);
119
+ --tw-prose-quotes: var(--foreground);
120
+ --tw-prose-quote-borders: var(--foreground);
121
+ --tw-prose-captions: var(--muted);
122
+ --tw-prose-code: var(--foreground);
123
+ --tw-prose-pre-code: var(--foreground);
124
+ --tw-prose-pre-bg: rgba(255, 255, 255, 0.05);
125
+ --tw-prose-th-borders: var(--foreground);
126
+ --tw-prose-td-borders: var(--muted);
127
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+ import tailwindcss from "@tailwindcss/vite";
4
+
5
+ export default defineConfig({
6
+ plugins: [react(), tailwindcss()],
7
+ });
@@ -0,0 +1,53 @@
1
+ """
2
+ Cron Job
3
+
4
+ Scheduled task that runs at specified intervals.
5
+ Executes once and exits.
6
+ """
7
+
8
+ import sys
9
+ import time
10
+ from datetime import datetime
11
+
12
+ from dotenv import load_dotenv
13
+
14
+ load_dotenv()
15
+
16
+
17
+ def run_cron_job() -> None:
18
+ """Main cron job logic."""
19
+ start_time = time.time()
20
+ print(f"Cron job started at {datetime.now().isoformat()}")
21
+
22
+ try:
23
+ # TODO: Add your scheduled task logic here
24
+ # Examples:
25
+ # - Clean up old records
26
+ # - Send scheduled notifications
27
+ # - Generate reports
28
+ # - Sync data between systems
29
+
30
+ print("Executing scheduled task...")
31
+
32
+ # Placeholder: simulate work
33
+ time.sleep(1)
34
+
35
+ print("Scheduled task completed successfully")
36
+
37
+ except Exception as e:
38
+ print(f"Cron job failed: {e}")
39
+ raise
40
+
41
+ finally:
42
+ duration = time.time() - start_time
43
+ print(f"Cron job finished in {duration:.2f}s")
44
+
45
+
46
+ if __name__ == "__main__":
47
+ try:
48
+ run_cron_job()
49
+ print("Cron job exiting successfully")
50
+ sys.exit(0)
51
+ except Exception as e:
52
+ print(f"Cron job exiting with error: {e}")
53
+ sys.exit(1)
@@ -0,0 +1,95 @@
1
+ """
2
+ Background Worker
3
+
4
+ Long-running background process for async tasks.
5
+ Runs continuously and processes work items.
6
+ """
7
+
8
+ import os
9
+ import signal
10
+ import sys
11
+ import time
12
+ from dataclasses import dataclass
13
+ from typing import Any
14
+
15
+ from dotenv import load_dotenv
16
+
17
+ load_dotenv()
18
+
19
+ POLL_INTERVAL = 5 # seconds
20
+
21
+
22
+ @dataclass
23
+ class WorkItem:
24
+ id: str
25
+ data: Any
26
+
27
+
28
+ # Graceful shutdown flag
29
+ shutdown_requested = False
30
+
31
+
32
+ def signal_handler(signum, frame):
33
+ """Handle shutdown signals gracefully."""
34
+ global shutdown_requested
35
+ print(f"Received signal {signum}, shutting down gracefully...")
36
+ shutdown_requested = True
37
+
38
+
39
+ def process_work_item(item: WorkItem) -> None:
40
+ """Process a single work item."""
41
+ print(f"Processing work item: {item.id}")
42
+
43
+ # TODO: Add your processing logic here
44
+ # Example: fetch from queue, process data, update database
45
+
46
+ time.sleep(0.1) # Simulate work
47
+
48
+ print(f"Completed work item: {item.id}")
49
+
50
+
51
+ def fetch_work_items() -> list[WorkItem]:
52
+ """Fetch pending work items."""
53
+ # TODO: Implement your work item fetching logic
54
+ # Example: poll a database, queue, or API
55
+
56
+ # Placeholder: return empty list (no work)
57
+ return []
58
+
59
+
60
+ def run_worker() -> None:
61
+ """Main worker loop."""
62
+ print("Worker started")
63
+ print(f"Poll interval: {POLL_INTERVAL}s")
64
+
65
+ while not shutdown_requested:
66
+ try:
67
+ items = fetch_work_items()
68
+
69
+ for item in items:
70
+ if shutdown_requested:
71
+ break
72
+ process_work_item(item)
73
+
74
+ if not items:
75
+ # No work, wait before polling again
76
+ time.sleep(POLL_INTERVAL)
77
+
78
+ except Exception as e:
79
+ print(f"Worker error: {e}")
80
+ # Wait before retrying on error
81
+ time.sleep(POLL_INTERVAL)
82
+
83
+ print("Worker shutdown complete")
84
+
85
+
86
+ if __name__ == "__main__":
87
+ # Register signal handlers
88
+ signal.signal(signal.SIGTERM, signal_handler)
89
+ signal.signal(signal.SIGINT, signal_handler)
90
+
91
+ try:
92
+ run_worker()
93
+ except Exception as e:
94
+ print(f"Fatal worker error: {e}")
95
+ sys.exit(1)
@@ -0,0 +1,73 @@
1
+ """
2
+ Render Workflow
3
+
4
+ Uses the Render SDK to define distributed tasks.
5
+ See: https://pypi.org/project/render-sdk/
6
+ """
7
+
8
+ import asyncio
9
+ import logging
10
+
11
+ from dotenv import load_dotenv
12
+ from render_sdk import Retry, Workflows
13
+
14
+ load_dotenv()
15
+
16
+ logging.basicConfig(level=logging.INFO)
17
+ logger = logging.getLogger(__name__)
18
+
19
+ # Retry configuration
20
+ retry = Retry(max_retries=3, wait_duration_ms=1000, backoff_scaling=1.5)
21
+
22
+ # Initialize Workflows app
23
+ app = Workflows(
24
+ default_retry=retry,
25
+ default_timeout=300,
26
+ auto_start=True,
27
+ )
28
+
29
+
30
+ @app.task
31
+ def square(a: int) -> int:
32
+ """Square a number (subtask)."""
33
+ logger.info(f"Computing square of {a}")
34
+ return a * a
35
+
36
+
37
+ @app.task
38
+ async def add_squares(a: int, b: int) -> int:
39
+ """Add the squares of two numbers using subtasks."""
40
+ logger.info(f"Computing add_squares: {a}, {b}")
41
+
42
+ result1 = await square(a)
43
+ result2 = await square(b)
44
+
45
+ total = result1 + result2
46
+ logger.info(f"Total: {total}")
47
+ return total
48
+
49
+
50
+ @app.task
51
+ async def process_data(data: str) -> str:
52
+ """Process data."""
53
+ logger.info(f"Processing data: {data}")
54
+
55
+ # TODO: Add your data processing logic here
56
+ result = data.upper()
57
+
58
+ logger.info(f"Processed result: {result}")
59
+ return result
60
+
61
+
62
+ @app.task
63
+ async def fan_out(items: list[str]) -> list[str]:
64
+ """Process multiple items in parallel using subtasks."""
65
+ logger.info(f"Processing {len(items)} items in parallel")
66
+
67
+ tasks = [process_data(item) for item in items]
68
+ results = await asyncio.gather(*tasks)
69
+
70
+ return list(results)
71
+
72
+
73
+ # Task server starts automatically with auto_start=True
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Cron Job
3
+ *
4
+ * Scheduled task that runs at specified intervals.
5
+ * Executes once and exits.
6
+ */
7
+
8
+ import "dotenv/config";
9
+
10
+ /**
11
+ * Main cron job logic
12
+ */
13
+ async function runCronJob(): Promise<void> {
14
+ const startTime = Date.now();
15
+ console.log(`Cron job started at ${new Date().toISOString()}`);
16
+
17
+ try {
18
+ // TODO: Add your scheduled task logic here
19
+ // Examples:
20
+ // - Clean up old records
21
+ // - Send scheduled notifications
22
+ // - Generate reports
23
+ // - Sync data between systems
24
+
25
+ console.log("Executing scheduled task...");
26
+
27
+ // Placeholder: simulate work
28
+ await new Promise((resolve) => setTimeout(resolve, 1000));
29
+
30
+ console.log("Scheduled task completed successfully");
31
+ } catch (error) {
32
+ console.error("Cron job failed:", error);
33
+ throw error;
34
+ } finally {
35
+ const duration = Date.now() - startTime;
36
+ console.log(`Cron job finished in ${duration}ms`);
37
+ }
38
+ }
39
+
40
+ // Run the cron job
41
+ runCronJob()
42
+ .then(() => {
43
+ console.log("Cron job exiting successfully");
44
+ process.exit(0);
45
+ })
46
+ .catch((error) => {
47
+ console.error("Cron job exiting with error:", error);
48
+ process.exit(1);
49
+ });
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Background Worker
3
+ *
4
+ * Long-running background process for async tasks.
5
+ * Runs continuously and processes work items.
6
+ */
7
+
8
+ import "dotenv/config";
9
+
10
+ const POLL_INTERVAL = 5000; // 5 seconds
11
+
12
+ interface WorkItem {
13
+ id: string;
14
+ data: unknown;
15
+ }
16
+
17
+ /**
18
+ * Process a single work item
19
+ */
20
+ async function processWorkItem(item: WorkItem): Promise<void> {
21
+ console.log(`Processing work item: ${item.id}`);
22
+
23
+ // TODO: Add your processing logic here
24
+ // Example: fetch from queue, process data, update database
25
+
26
+ await new Promise((resolve) => setTimeout(resolve, 100)); // Simulate work
27
+
28
+ console.log(`Completed work item: ${item.id}`);
29
+ }
30
+
31
+ /**
32
+ * Fetch pending work items
33
+ */
34
+ async function fetchWorkItems(): Promise<WorkItem[]> {
35
+ // TODO: Implement your work item fetching logic
36
+ // Example: poll a database, queue, or API
37
+
38
+ // Placeholder: return empty array (no work)
39
+ return [];
40
+ }
41
+
42
+ /**
43
+ * Main worker loop
44
+ */
45
+ async function runWorker(): Promise<void> {
46
+ console.log("Worker started");
47
+ console.log(`Poll interval: ${POLL_INTERVAL}ms`);
48
+
49
+ while (true) {
50
+ try {
51
+ const items = await fetchWorkItems();
52
+
53
+ for (const item of items) {
54
+ await processWorkItem(item);
55
+ }
56
+
57
+ if (items.length === 0) {
58
+ // No work, wait before polling again
59
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
60
+ }
61
+ } catch (error) {
62
+ console.error("Worker error:", error);
63
+ // Wait before retrying on error
64
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
65
+ }
66
+ }
67
+ }
68
+
69
+ // Handle graceful shutdown
70
+ process.on("SIGTERM", () => {
71
+ console.log("SIGTERM received, shutting down gracefully...");
72
+ process.exit(0);
73
+ });
74
+
75
+ process.on("SIGINT", () => {
76
+ console.log("SIGINT received, shutting down gracefully...");
77
+ process.exit(0);
78
+ });
79
+
80
+ // Start the worker
81
+ runWorker().catch((error) => {
82
+ console.error("Fatal worker error:", error);
83
+ process.exit(1);
84
+ });
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Render Workflow
3
+ *
4
+ * Uses the Render SDK to define distributed tasks.
5
+ * See: https://github.com/render-oss/sdk
6
+ */
7
+
8
+ import "dotenv/config";
9
+ import { task, type Retry } from "@renderinc/sdk/workflows";
10
+
11
+ // Retry configuration
12
+ const retry: Retry = {
13
+ maxRetries: 3,
14
+ waitDurationMs: 1000,
15
+ factor: 1.5,
16
+ };
17
+
18
+ /**
19
+ * Simple task that squares a number (subtask)
20
+ */
21
+ const square = task({ name: "square" }, function square(a: number): number {
22
+ console.log(`Calculating square of ${a}`);
23
+ return a * a;
24
+ });
25
+
26
+ /**
27
+ * Async task that adds two squared numbers
28
+ */
29
+ task(
30
+ {
31
+ name: "addSquares",
32
+ timeoutSeconds: 300,
33
+ retry,
34
+ },
35
+ async function addSquares(a: number, b: number): Promise<number> {
36
+ console.log(`Adding squares of ${a} and ${b}`);
37
+
38
+ const result1 = await square(a);
39
+ const result2 = await square(b);
40
+
41
+ const sum = result1 + result2;
42
+ console.log(`Result: ${result1} + ${result2} = ${sum}`);
43
+ return sum;
44
+ },
45
+ );
46
+
47
+ /**
48
+ * Task that processes data
49
+ */
50
+ task(
51
+ {
52
+ name: "processData",
53
+ timeoutSeconds: 300,
54
+ retry,
55
+ },
56
+ async function processData(data: string): Promise<string> {
57
+ console.log(`Processing data: ${data}`);
58
+
59
+ // TODO: Add your data processing logic here
60
+ const result = data.toUpperCase();
61
+
62
+ console.log(`Processed result: ${result}`);
63
+ return result;
64
+ },
65
+ );
66
+
67
+ // Task server starts automatically when RENDER_SDK_SOCKET_PATH is set