@emeryld/create-rrroutes 0.1.9 → 0.1.11

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
@@ -86,7 +86,6 @@ function baseTsConfig() {
86
86
  extends: "../../tsconfig.base.json",
87
87
  compilerOptions: {
88
88
  outDir: "dist",
89
- rootDir: "src",
90
89
  types: ["vite/client"]
91
90
  },
92
91
  include: ["src/**/*", "vite.config.ts"]
@@ -1073,6 +1072,10 @@ async function scaffoldRoot(ctx) {
1073
1072
  if (ctx.targets.contract) {
1074
1073
  scripts["dev:contract"] = `npm run watch --workspace ${ctx.packageNames.contract}`;
1075
1074
  }
1075
+ const hasFullStack = ctx.targets.server && ctx.targets.client && ctx.targets.contract;
1076
+ if (hasFullStack) {
1077
+ scripts["dev:all"] = `concurrently "npm run dev:contract" "npm run dev:server" "npm run dev:client"`;
1078
+ }
1076
1079
  const highlights = ["- Shared contract package (RRRoutes registry + sockets)"];
1077
1080
  if (ctx.targets.server) {
1078
1081
  highlights.unshift(
@@ -1106,17 +1109,22 @@ async function scaffoldRoot(ctx) {
1106
1109
  quickstart.push(
1107
1110
  `${quickstart.length + 1}) Run dev servers:${ctx.targets.server ? `
1108
1111
  - API: \`npm run dev:server\`` : ""}${ctx.targets.client ? `
1109
- - Client: \`npm run dev:client\`` : ""}`
1112
+ - Client: \`npm run dev:client\`` : ""}${hasFullStack ? `
1113
+ - All: \`npm run dev:all\`` : ""}`
1110
1114
  );
1111
1115
  }
1116
+ const devDependencies = {
1117
+ typescript: "^5.9.3"
1118
+ };
1119
+ if (hasFullStack) {
1120
+ devDependencies["concurrently"] = "^8.2.0";
1121
+ }
1112
1122
  const pkgJson = {
1113
1123
  name: `${ctx.appSlug}-stack`,
1114
1124
  private: true,
1115
1125
  workspaces: ["packages/*"],
1116
1126
  scripts,
1117
- devDependencies: {
1118
- typescript: "^5.9.3"
1119
- }
1127
+ devDependencies
1120
1128
  };
1121
1129
  const files = {
1122
1130
  "package.json": formatJson(pkgJson),
@@ -1171,12 +1179,13 @@ async function scaffoldRoot(ctx) {
1171
1179
 
1172
1180
  // src/generators/server.ts
1173
1181
  var import_node_path5 = __toESM(require("path"), 1);
1182
+ var defaultDatabaseUrl = "postgresql://postgres:postgres@localhost:5432/rrroutes";
1174
1183
  function serverIndexTs() {
1175
1184
  return `import 'dotenv/config'
1176
1185
  import http from 'node:http'
1177
- import { app } from './http'
1178
- import { createSockets } from './socket'
1179
- import { prisma } from './prisma'
1186
+ import { app } from './http.js'
1187
+ import { createSockets } from './socket.js'
1188
+ import { prisma } from './prisma.js'
1180
1189
 
1181
1190
  async function main() {
1182
1191
  const PORT = Number.parseInt(process.env.PORT ?? '4000', 10)
@@ -1213,16 +1222,16 @@ main().catch(async (err) => {
1213
1222
  `;
1214
1223
  }
1215
1224
  function httpTs(contractImport) {
1216
- return `import express, { Router } from 'express'
1225
+ return `import express from 'express'
1217
1226
  import cors from 'cors'
1218
1227
  import { createRRRoute } from '@emeryld/rrroutes-server'
1219
1228
  import { registry } from '${contractImport}'
1220
- import { controllers, type RequestCtx } from './controllers'
1221
- import { prisma } from './prisma'
1229
+ import { controllers, type RequestCtx } from './controllers.js'
1230
+ import { prisma } from './prisma.js'
1222
1231
 
1223
1232
  const CORS_ORIGIN = process.env.CORS_ORIGIN ?? 'http://localhost:5173'
1224
1233
 
1225
- export const app: Router = express()
1234
+ export const app = express()
1226
1235
  app.use(cors({ origin: CORS_ORIGIN, credentials: true }))
1227
1236
  app.use(express.json())
1228
1237
 
@@ -1249,14 +1258,14 @@ export { routes }
1249
1258
  }
1250
1259
  function controllersTs(contractImport) {
1251
1260
  return `import { defineControllers } from '@emeryld/rrroutes-server'
1252
- import type { PrismaClient } from '@prisma/client'
1253
1261
  import { registry } from '${contractImport}'
1254
1262
 
1263
+ type PrismaCtx = typeof import('./prisma.js').prisma
1264
+
1255
1265
  export type RequestCtx = {
1256
- prisma: PrismaClient
1266
+ prisma: PrismaCtx
1257
1267
  requestId: string
1258
1268
  }
1259
-
1260
1269
  export const controllers = defineControllers<typeof registry, RequestCtx>()({
1261
1270
  'GET /api/health': {
1262
1271
  handler: async ({ ctx }) => {
@@ -1264,10 +1273,10 @@ export const controllers = defineControllers<typeof registry, RequestCtx>()({
1264
1273
  data: { note: 'GET health' },
1265
1274
  })
1266
1275
  return {
1267
- out:{
1268
- status: 'ok',
1269
- html: '<!doctype html><html><body><h1>healthy</h1></body></html>',
1270
- }
1276
+ out: {
1277
+ status: 'ok',
1278
+ html: '<!doctype html><html><body><h1>healthy</h1></body></html>',
1279
+ },
1271
1280
  }
1272
1281
  },
1273
1282
  },
@@ -1277,10 +1286,10 @@ export const controllers = defineControllers<typeof registry, RequestCtx>()({
1277
1286
  data: { note: body?.echo ?? 'POST health' },
1278
1287
  })
1279
1288
  return {
1280
- out:{
1281
- status: 'ok',
1282
- received: body?.echo ?? 'pong',
1283
- }
1289
+ out: {
1290
+ status: 'ok',
1291
+ received: body?.echo ?? 'pong',
1292
+ },
1284
1293
  }
1285
1294
  },
1286
1295
  },
@@ -1290,7 +1299,12 @@ export const controllers = defineControllers<typeof registry, RequestCtx>()({
1290
1299
  function socketTs(contractImport) {
1291
1300
  return `import { Server as SocketIOServer } from 'socket.io'
1292
1301
  import type { Server } from 'node:http'
1293
- import { createSocketConnections } from '@emeryld/rrroutes-server'
1302
+ import {
1303
+ createSocketConnections,
1304
+ type HandlerCtx,
1305
+ type SysServerEventMap,
1306
+ } from '@emeryld/rrroutes-server'
1307
+ import type { Payload } from '@emeryld/rrroutes-contract'
1294
1308
  import { socketConfig, socketEvents } from '${contractImport}'
1295
1309
 
1296
1310
  export function createSockets(
@@ -1302,40 +1316,51 @@ export function createSockets(
1302
1316
  path: opts.socketPath,
1303
1317
  })
1304
1318
 
1319
+ const sysHandlers: SysServerEventMap<
1320
+ typeof socketConfig,
1321
+ typeof socketEvents
1322
+ > = {
1323
+ 'sys:connect': async ({ socket, helper, complete }) => {
1324
+ helper.emit('health:connected', {
1325
+ socketId: socket.id,
1326
+ at: new Date().toISOString(),
1327
+ message: 'connected',
1328
+ })
1329
+ complete()
1330
+ },
1331
+ 'sys:disconnect': async ({ cleanup }) => cleanup(),
1332
+ 'sys:ping': async ({ ping }) => ({
1333
+ ok: true,
1334
+ receivedAt: new Date().toISOString(),
1335
+ echo: ping.note,
1336
+ }),
1337
+ 'sys:room_join': async ({ rooms, join }) => {
1338
+ await Promise.all(rooms.map((room) => join(room)))
1339
+ },
1340
+ 'sys:room_leave': async ({ rooms, leave }) => {
1341
+ await Promise.all(rooms.map((room) => leave(room)))
1342
+ },
1343
+ }
1344
+
1305
1345
  const sockets = createSocketConnections(io, socketEvents, {
1306
1346
  config: socketConfig,
1307
1347
  heartbeat: { enabled: true },
1308
- sys: {
1309
- 'sys:connect': async ({ socket, helper, complete }) => {
1310
- helper.emit('health:connected', {
1311
- socketId: socket.id,
1312
- at: new Date().toISOString(),
1313
- message: 'connected',
1314
- })
1315
- complete()
1316
- },
1317
- 'sys:disconnect': async ({ cleanup }) => cleanup(),
1318
- 'sys:ping': async ({ ping }) => ({
1319
- ok: true,
1320
- receivedAt: new Date().toISOString(),
1321
- echo: ping.note,
1322
- }),
1323
- 'sys:room_join': async ({ rooms, join }) => {
1324
- await Promise.all(rooms.map((room) => join(room)))
1325
- },
1326
- 'sys:room_leave': async ({ rooms, leave }) => {
1327
- await Promise.all(rooms.map((room) => leave(room)))
1328
- },
1329
- },
1348
+ sys: sysHandlers,
1330
1349
  })
1331
1350
 
1332
- sockets.on('health:ping', async (payload, ctx) => {
1333
- sockets.emit(
1334
- 'health:pong',
1335
- { ok: true, at: new Date().toISOString(), echo: payload.note },
1336
- ctx.socketId,
1337
- )
1338
- })
1351
+ sockets.on(
1352
+ 'health:ping',
1353
+ async (
1354
+ payload: Payload<typeof socketEvents, 'health:ping'>,
1355
+ ctx: HandlerCtx,
1356
+ ) => {
1357
+ sockets.emit(
1358
+ 'health:pong',
1359
+ { ok: true, at: new Date().toISOString(), echo: payload.note },
1360
+ ctx.socketId,
1361
+ )
1362
+ },
1363
+ )
1339
1364
 
1340
1365
  return sockets
1341
1366
  }
@@ -1372,11 +1397,10 @@ function serverEnv() {
1372
1397
  "NODE_ENV=development",
1373
1398
  "CORS_ORIGIN=http://localhost:5173",
1374
1399
  "SOCKET_PATH=/socket.io",
1375
- "DATABASE_URL=postgresql://postgres:postgres@localhost:5432/rrroutes"
1400
+ `DATABASE_URL=${defaultDatabaseUrl}`
1376
1401
  ].join("\n");
1377
1402
  }
1378
- var tsNodeLoaderRegistrationImport = 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./"));';
1379
- var nodemonExecCommand = `node --import '${tsNodeLoaderRegistrationImport}' ./src/index.ts`;
1403
+ var nodemonExecCommand = `node --no-warnings --loader ts-node/esm ./src/index.ts`;
1380
1404
  function nodemonJson() {
1381
1405
  return `${JSON.stringify(
1382
1406
  {
@@ -1438,7 +1462,7 @@ async function scaffoldServer(ctx) {
1438
1462
  dependencies: {
1439
1463
  [ctx.packageNames.contract]: "workspace:*",
1440
1464
  "@emeryld/rrroutes-server": "^2.4.1",
1441
- "@prisma/client": "^5.22.0",
1465
+ "@prisma/client": "^7.0.0",
1442
1466
  "socket.io": "^4.8.1",
1443
1467
  express: "^5.1.0",
1444
1468
  cors: "^2.8.5",
@@ -1447,8 +1471,9 @@ async function scaffoldServer(ctx) {
1447
1471
  },
1448
1472
  devDependencies: {
1449
1473
  "@types/express": "^5.0.6",
1474
+ "@types/cors": "^2.8.5",
1450
1475
  "@types/node": "^24.10.2",
1451
- prisma: "^5.22.0",
1476
+ prisma: "^7.0.0",
1452
1477
  typescript: "^5.9.3",
1453
1478
  "ts-node": "^10.9.2",
1454
1479
  nodemon: "^3.1.9"
@@ -1458,9 +1483,13 @@ async function scaffoldServer(ctx) {
1458
1483
  extends: "../../tsconfig.base.json",
1459
1484
  compilerOptions: {
1460
1485
  outDir: "dist",
1461
- rootDir: "src",
1462
1486
  declaration: true,
1463
- sourceMap: true
1487
+ sourceMap: true,
1488
+ module: "NodeNext",
1489
+ moduleResolution: "NodeNext",
1490
+ target: "ES2022",
1491
+ strict: true,
1492
+ skipLibCheck: true
1464
1493
  },
1465
1494
  include: ["src/**/*"]
1466
1495
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/generators/client.ts","../src/utils/fs.ts","../src/utils/log.ts","../src/generators/contract.ts","../src/generators/root.ts","../src/generators/server.ts","../src/utils/prompt.ts","../src/utils/run.ts","../src/utils/strings.ts"],"sourcesContent":["import path from 'node:path'\nimport { scaffoldClient } from './generators/client'\nimport { scaffoldContract } from './generators/contract'\nimport { scaffoldRoot } from './generators/root'\nimport { scaffoldServer } from './generators/server'\nimport { GeneratorContext, Targets, type ClientKind } from './types'\nimport { log } from './utils/log'\nimport { createPrompt } from './utils/prompt'\nimport { runCommand } from './utils/run'\nimport { slugify } from './utils/strings'\n\nfunction resolveTargets(choice: string): Targets {\n if (choice === 'all')\n return { client: true, server: true, contract: true } as const\n if (choice === 'client')\n return { client: true, server: false, contract: true } as const\n if (choice === 'server')\n return { client: false, server: true, contract: true } as const\n return { client: false, server: false, contract: true } as const\n}\n\nasync function gatherContext(): Promise<GeneratorContext> {\n const prompt = createPrompt()\n try {\n const projectName =\n (await prompt.text('Project name', 'rrroutes-starter')) ??\n 'rrroutes-starter'\n const appSlug = slugify(projectName)\n const targetDirInput =\n (await prompt.text('Target directory', `./${appSlug}`)) ?? `./${appSlug}`\n const rootDir = path.resolve(process.cwd(), targetDirInput)\n const scopeInput =\n (await prompt.text('NPM scope (without @)', appSlug)) ?? appSlug\n const packageScope = slugify(scopeInput)\n\n const selection = await prompt.select('What should we create?', [\n {\n label: 'Everything (contract + server + client)',\n value: 'all',\n },\n { label: 'Contract only', value: 'contract' },\n { label: 'Backend only', value: 'server' },\n { label: 'Frontend only', value: 'client' },\n ])\n const targets = resolveTargets(selection)\n\n let clientKind: ClientKind = 'react'\n if (targets.client) {\n clientKind = await prompt.select<ClientKind>(\n 'Frontend runtime',\n [\n { label: 'React (web, Vite)', value: 'react' },\n { label: 'React Native (Expo)', value: 'react-native' },\n ],\n 0,\n )\n }\n\n const packageNames = {\n contract: `@${packageScope}/contract`,\n server: `@${packageScope}/server`,\n client: `@${packageScope}/client`,\n }\n\n return {\n projectName,\n appSlug,\n packageScope,\n rootDir,\n clientKind,\n targets,\n packageNames,\n }\n } finally {\n prompt.close()\n }\n}\n\nasync function runPostScaffold(ctx: GeneratorContext) {\n if (process.env.CREATERRROUTES_SKIP_POSTINSTALL === '1') {\n log.warn('Skipping install/build steps (CREATERRROUTES_SKIP_POSTINSTALL=1).')\n return\n }\n\n const steps: { label: string; args: string[]; enabled: boolean }[] = [\n {\n label: 'Installing workspace dependencies (pnpm install)',\n args: ['install'],\n enabled: true,\n },\n {\n label: `Building shared contract (${ctx.packageNames.contract})`,\n args: ['--filter', ctx.packageNames.contract, 'build'],\n enabled: ctx.targets.contract,\n },\n {\n label: `Generating Prisma client for ${ctx.packageNames.server}`,\n args: ['--filter', ctx.packageNames.server, 'prisma:generate'],\n enabled: ctx.targets.server,\n },\n ]\n\n for (const step of steps) {\n if (!step.enabled) continue\n try {\n log.step(step.label)\n await runCommand('pnpm', step.args, ctx.rootDir)\n } catch (err) {\n log.warn(\n `Step failed (${step.label}). Run manually: pnpm ${step.args.join(' ')}\\n${String(err)}`,\n )\n break\n }\n }\n}\n\nasync function main() {\n const ctx = await gatherContext()\n log.info(`Scaffolding RRRoutes starter in ${ctx.rootDir}`)\n\n await scaffoldRoot(ctx)\n if (ctx.targets.contract) await scaffoldContract(ctx)\n if (ctx.targets.server) await scaffoldServer(ctx)\n if (ctx.targets.client) await scaffoldClient(ctx)\n\n await runPostScaffold(ctx)\n\n log.info('Done. Install dependencies and start hacking!')\n}\n\nmain().catch((err) => {\n log.error(err instanceof Error ? err.message : String(err))\n process.exit(1)\n})\n","import path from 'node:path'\nimport { GeneratorContext } from '../types'\nimport { ensureDir, writeFileForce, writeFileIfMissing } from '../utils/fs'\nimport { log } from '../utils/log'\n\nfunction baseTsConfig() {\n return {\n extends: '../../tsconfig.base.json',\n compilerOptions: {\n outDir: 'dist',\n rootDir: 'src',\n types: ['vite/client'],\n },\n include: ['src/**/*', 'vite.config.ts'],\n }\n}\n\nfunction viteConfig() {\n return `import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n plugins: [react()],\n})\n`\n}\n\nfunction queryClient(contractImport: string) {\n return `import { QueryClient } from '@tanstack/react-query'\nimport { createRouteClient } from '@emeryld/rrroutes-client'\nimport { registry } from '${contractImport}'\n\nconst baseUrl = import.meta.env.VITE_API_URL ?? 'http://localhost:4000'\n\nexport const queryClient = new QueryClient()\n\nexport const routeClient = createRouteClient({\n baseUrl,\n queryClient,\n environment: import.meta.env.MODE === 'production' ? 'production' : 'development',\n})\n\nexport const healthGet = routeClient.build(registry.byKey['GET /api/health'])\nexport const healthPost = routeClient.build(registry.byKey['POST /api/health'])\n`\n}\n\nfunction socketProvider(contractImport: string) {\n return `import React from 'react'\nimport { io, type Socket } from 'socket.io-client'\nimport {\n buildSocketProvider,\n type SocketClientOptions,\n} from '@emeryld/rrroutes-client'\nimport { socketConfig, socketEvents } from '${contractImport}'\n\nconst socketUrl = import.meta.env.VITE_SOCKET_URL ?? 'http://localhost:4000'\nconst socketPath = import.meta.env.VITE_SOCKET_PATH ?? '/socket.io'\n\nconst sysEvents: SocketClientOptions<\n typeof socketEvents,\n typeof socketConfig\n>['sys'] = {\n 'sys:connect': async ({ socket }) => {\n console.info('socket connected', socket.id)\n },\n 'sys:disconnect': async ({ reason }) => {\n console.info('socket disconnected', reason)\n },\n 'sys:reconnect': async ({ attempt, socket }) => {\n console.info('socket reconnect', attempt, socket?.id)\n },\n 'sys:connect_error': async ({ error }) => {\n console.warn('socket connect error', error)\n },\n 'sys:ping': () => ({\n note: 'client-heartbeat',\n sentAt: new Date().toISOString(),\n }),\n 'sys:pong': async ({ payload }) => {\n console.info('socket pong', payload)\n },\n 'sys:room_join': async ({ rooms }) => {\n console.info('joining rooms', rooms)\n return true\n },\n 'sys:room_leave': async ({ rooms }) => {\n console.info('leaving rooms', rooms)\n return true\n },\n}\n\nconst baseOptions: Omit<\n SocketClientOptions<typeof socketEvents, typeof socketConfig>,\n 'socket'\n> = {\n config: socketConfig,\n sys: sysEvents,\n environment: import.meta.env.MODE === 'production' ? 'production' : 'development',\n heartbeat: { intervalMs: 15_000, timeoutMs: 7_500 },\n debug: {\n connection: true,\n heartbeat: true,\n },\n}\n\nconst { SocketProvider, useSocketClient, useSocketConnection } =\n buildSocketProvider({\n events: socketEvents,\n options: baseOptions,\n })\n\nfunction getSocket(): Promise<Socket> {\n return Promise.resolve(\n io(socketUrl, {\n path: socketPath,\n transports: ['websocket'],\n }),\n )\n}\n\nexport const roomMeta = { room: 'health' }\n\nexport function AppSocketProvider(props: React.PropsWithChildren) {\n return (\n <SocketProvider\n getSocket={getSocket}\n destroyLeaveMeta={roomMeta}\n fallback={<p>Connecting socket…</p>}\n >\n {props.children}\n </SocketProvider>\n )\n}\n\nexport { useSocketClient, useSocketConnection }\n`\n}\n\nconst MAIN_TSX = `import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport App from './App'\nimport './styles.css'\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <App />\n </React.StrictMode>,\n)\n`\n\nfunction appTsx() {\n return `import React from 'react'\nimport { QueryClientProvider } from '@tanstack/react-query'\nimport { queryClient } from './lib/queryClient'\nimport { AppSocketProvider } from './lib/socket'\nimport { HealthPage } from './pages/HealthPage'\n\nexport default function App() {\n return (\n <QueryClientProvider client={queryClient}>\n <AppSocketProvider>\n <HealthPage />\n </AppSocketProvider>\n </QueryClientProvider>\n )\n}\n`\n}\n\nconst STYLES = `:root {\n font-family: 'Inter', system-ui, -apple-system, sans-serif;\n color: #0b1021;\n background: #f7f8fb;\n}\n\nbody {\n margin: 0;\n background: radial-gradient(circle at 20% 20%, #eef2ff, #f7f8fb 45%);\n min-height: 100vh;\n}\n\n.health {\n max-width: 960px;\n margin: 0 auto;\n padding: 32px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));\n gap: 16px;\n}\n\n.card {\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n padding: 16px;\n box-shadow: 0 8px 24px rgba(12, 18, 32, 0.05);\n}\n\nbutton {\n background: #0f172a;\n color: #fff;\n border: none;\n border-radius: 8px;\n padding: 10px 12px;\n cursor: pointer;\n font-weight: 600;\n}\n\nbutton.secondary {\n background: #e2e8f0;\n color: #0f172a;\n}\n\nbutton + button {\n margin-left: 8px;\n}\n\ntextarea {\n width: 100%;\n min-height: 80px;\n}\n\n.logs {\n font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo,\n monospace;\n background: #0f172a;\n color: #e2e8f0;\n padding: 12px;\n border-radius: 8px;\n min-height: 160px;\n white-space: pre-line;\n}\n`\n\nfunction healthPage(contractImport: string) {\n return `import React from 'react'\nimport { healthGet, healthPost } from '../lib/queryClient'\nimport { roomMeta, useSocketClient, useSocketConnection } from '../lib/socket'\n\nconst now = () => new Date().toLocaleTimeString()\n\nfunction useLogs() {\n const [logs, setLogs] = React.useState<string[]>([])\n return {\n logs,\n push: (msg: string) =>\n setLogs((prev) => [\\`[\\${now()}] \\${msg}\\`, ...prev].slice(0, 60)),\n clear: () => setLogs([]),\n }\n}\n\nexport function HealthPage() {\n const [echo, setEcho] = React.useState('hello rrroute')\n const httpGet = healthGet.useEndpoint()\n const httpPost = healthPost.useEndpoint()\n const socket = useSocketClient()\n const { logs, push, clear } = useLogs()\n\n useSocketConnection({\n event: 'health:connected',\n rooms: ['health'],\n joinMeta: roomMeta,\n leaveMeta: roomMeta,\n onMessage: (payload) => {\n push(\\`socket connected (\\${payload.socketId})\\`)\n },\n })\n\n useSocketConnection({\n event: 'health:pong',\n rooms: ['health'],\n joinMeta: roomMeta,\n leaveMeta: roomMeta,\n onMessage: (payload) => {\n push(\n \\`pong at \\${payload.at}\\${payload.echo ? \\` (echo: \\${payload.echo})\\` : ''}\\`,\n )\n },\n })\n\n return (\n <div className=\"health\">\n <h1>RRRoutes health sandbox</h1>\n <div className=\"grid\">\n <div className=\"card\">\n <h2>HTTP endpoints</h2>\n <p>GET and POST against the shared contract.</p>\n <div>\n <button onClick={() => httpGet.refetch()}>GET /health</button>\n {httpGet.error ? (\n <p style={{ color: 'crimson', marginTop: 6 }}>\n GET error: {String(httpGet.error)}\n </p>\n ) : null}\n </div>\n <div style={{ marginTop: 12 }}>\n <input\n value={echo}\n onChange={(e) => setEcho(e.target.value)}\n placeholder=\"echo payload\"\n style={{ width: '100%', padding: '8px' }}\n />\n <div style={{ marginTop: 8 }}>\n <button\n onClick={() =>\n httpPost.mutateAsync({ echo }).then(() => {\n push('POST /health ok')\n })\n }\n >\n POST /health\n </button>\n </div>\n {httpPost.error ? (\n <p style={{ color: 'crimson', marginTop: 6 }}>\n POST error: {String(httpPost.error)}\n </p>\n ) : null}\n </div>\n <div style={{ marginTop: 12 }}>\n <strong>GET data</strong>\n <pre>{JSON.stringify(httpGet.data, null, 2) ?? 'none'}</pre>\n <strong>POST data</strong>\n <pre>{JSON.stringify(httpPost.data, null, 2) ?? 'none'}</pre>\n </div>\n </div>\n\n <div className=\"card\">\n <h2>Socket</h2>\n <p>Connect, ping, and watch lifecycle events.</p>\n <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>\n <button onClick={() => socket.connect()}>Connect</button>\n <button className=\"secondary\" onClick={() => socket.disconnect()}>\n Disconnect\n </button>\n <button\n onClick={() =>\n socket.emit('health:ping', { note: 'ping from client' })\n }\n >\n Emit ping\n </button>\n <button\n className=\"secondary\"\n onClick={() => socket.joinRooms(['health'], roomMeta)}\n >\n Join room\n </button>\n <button\n className=\"secondary\"\n onClick={() => socket.leaveRooms(['health'], roomMeta)}\n >\n Leave room\n </button>\n </div>\n {httpGet.error || httpPost.error ? (\n <p style={{ color: 'crimson', marginTop: 8 }}>\n Check server logs; errors will also show above.\n </p>\n ) : null}\n </div>\n\n <div className=\"card\">\n <h2>Socket logs</h2>\n <button className=\"secondary\" onClick={clear}>\n Clear\n </button>\n <div className=\"logs\">\n {logs.length === 0 ? 'No messages yet' : logs.join('\\\\n')}\n </div>\n </div>\n </div>\n </div>\n )\n}\n`\n}\n\nfunction indexHtml() {\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>RRRoutes starter</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"></script>\n </body>\n</html>\n`\n}\n\nconst CLIENT_ENV = `VITE_API_URL=http://localhost:4000\nVITE_SOCKET_URL=http://localhost:4000\nVITE_SOCKET_PATH=/socket.io\n`\n\n// React Native / Expo template ------------------------------------------------\n\nfunction nativePackageJson(clientName: string, contractName: string) {\n return {\n name: clientName,\n version: '0.1.0',\n private: true,\n main: 'expo/AppEntry',\n scripts: {\n start: 'expo start',\n android: 'expo start --android',\n ios: 'expo start --ios',\n web: 'expo start --web',\n test: 'echo \"add tests\"',\n },\n dependencies: {\n [contractName]: 'workspace:*',\n '@emeryld/rrroutes-client': '^2.5.3',\n '@tanstack/react-query': '^5.90.12',\n expo: '~52.0.8',\n 'expo-constants': '~16.0.2',\n 'expo-status-bar': '~2.0.1',\n react: '18.3.1',\n 'react-native': '0.76.6',\n 'react-native-safe-area-context': '4.12.0',\n 'react-native-screens': '4.4.0',\n 'socket.io-client': '^4.8.3',\n zod: '^4.2.1',\n },\n devDependencies: {\n '@babel/core': '^7.25.2',\n '@types/react': '~18.2.79',\n '@types/react-native': '~0.73.0',\n typescript: '^5.9.3',\n },\n }\n}\n\nfunction nativeAppJson(appSlug: string) {\n return {\n expo: {\n name: `${appSlug}-client`,\n slug: `${appSlug}-client`,\n version: '0.1.0',\n orientation: 'portrait',\n scheme: appSlug,\n platforms: ['ios', 'android', 'web'],\n userInterfaceStyle: 'light',\n extra: {\n apiUrl: 'http://localhost:4000',\n socketUrl: 'http://localhost:4000',\n socketPath: '/socket.io',\n },\n experiments: {\n typedRoutes: false,\n },\n },\n }\n}\n\nconst NATIVE_BABEL = `module.exports = function (api) {\n api.cache(true)\n return {\n presets: ['babel-preset-expo'],\n }\n}\n`\n\nconst NATIVE_TS_CONFIG = {\n extends: '../../tsconfig.base.json',\n compilerOptions: {\n jsx: 'react-native',\n types: ['react-native', 'react'],\n },\n include: ['**/*.ts', '**/*.tsx'],\n exclude: ['node_modules', 'babel.config.js', 'metro.config.js'],\n}\n\nfunction nativeQueryClient(contractImport: string) {\n return `import Constants from 'expo-constants'\nimport { QueryClient } from '@tanstack/react-query'\nimport { createRouteClient } from '@emeryld/rrroutes-client'\nimport { registry } from '${contractImport}'\n\nconst { apiUrl } = (Constants.expoConfig?.extra ?? {}) as Record<string, string>\n\nexport const queryClient = new QueryClient()\n\nexport const routeClient = createRouteClient({\n baseUrl: apiUrl ?? 'http://localhost:4000',\n queryClient,\n})\n\nexport const healthGet = routeClient.build(registry.byKey['GET /api/health'])\nexport const healthPost = routeClient.build(registry.byKey['POST /api/health'])\n`\n}\n\nfunction nativeSocket(contractImport: string) {\n return `import React from 'react'\nimport Constants from 'expo-constants'\nimport { io, type Socket } from 'socket.io-client'\nimport {\n buildSocketProvider,\n type SocketClientOptions,\n} from '@emeryld/rrroutes-client'\nimport { socketConfig, socketEvents } from '${contractImport}'\n\nconst extras = (Constants.expoConfig?.extra ?? {}) as Record<string, string>\nconst socketUrl = extras.socketUrl ?? 'http://localhost:4000'\nconst socketPath = extras.socketPath ?? '/socket.io'\n\nconst sysEvents: SocketClientOptions<\n typeof socketEvents,\n typeof socketConfig\n>['sys'] = {\n 'sys:connect': async ({ socket }) => {\n console.log('socket connected', socket.id)\n },\n 'sys:disconnect': async ({ reason }) => console.log('disconnected', reason),\n 'sys:reconnect': async ({ attempt, socket }) =>\n console.log('reconnect', attempt, socket?.id),\n 'sys:connect_error': async ({ error }) =>\n console.warn('socket connect error', error),\n 'sys:ping': () => ({\n note: 'client-heartbeat',\n sentAt: new Date().toISOString(),\n }),\n 'sys:pong': async ({ payload }) => console.log('pong', payload),\n 'sys:room_join': async ({ rooms }) => {\n console.log('join rooms', rooms)\n return true\n },\n 'sys:room_leave': async ({ rooms }) => {\n console.log('leave rooms', rooms)\n return true\n },\n}\n\nconst baseOptions: Omit<\n SocketClientOptions<typeof socketEvents, typeof socketConfig>,\n 'socket'\n> = {\n config: socketConfig,\n sys: sysEvents,\n heartbeat: { intervalMs: 15_000, timeoutMs: 7_500 },\n debug: { connection: true },\n}\n\nconst { SocketProvider, useSocketClient, useSocketConnection } =\n buildSocketProvider({\n events: socketEvents,\n options: baseOptions,\n })\n\nfunction getSocket(): Promise<Socket> {\n return Promise.resolve(\n io(socketUrl, {\n path: socketPath,\n transports: ['websocket'],\n }),\n )\n}\n\nexport const roomMeta = { room: 'health' }\n\nexport function AppSocketProvider(props: React.PropsWithChildren) {\n return (\n <SocketProvider\n getSocket={getSocket}\n destroyLeaveMeta={roomMeta}\n fallback={<></>}\n >\n {props.children}\n </SocketProvider>\n )\n}\n\nexport { useSocketClient, useSocketConnection }\n`\n}\n\nfunction nativeAppTsx() {\n return `import React from 'react'\nimport { SafeAreaView, ScrollView, StatusBar, StyleSheet } from 'react-native'\nimport { QueryClientProvider } from '@tanstack/react-query'\nimport { queryClient } from './src/queryClient'\nimport { AppSocketProvider } from './src/socket'\nimport { HealthScreen } from './src/screens/HealthScreen'\n\nexport default function App() {\n return (\n <QueryClientProvider client={queryClient}>\n <AppSocketProvider>\n <StatusBar barStyle=\"dark-content\" />\n <SafeAreaView style={styles.container}>\n <ScrollView contentInsetAdjustmentBehavior=\"automatic\">\n <HealthScreen />\n </ScrollView>\n </SafeAreaView>\n </AppSocketProvider>\n </QueryClientProvider>\n )\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n padding: 16,\n backgroundColor: '#f4f5fb',\n },\n})\n`\n}\n\nfunction nativeHealthScreen(contractImport: string) {\n return `import React from 'react'\nimport {\n Button,\n StyleSheet,\n Text,\n TextInput,\n View,\n} from 'react-native'\nimport { healthGet, healthPost } from '../queryClient'\nimport { roomMeta, useSocketClient, useSocketConnection } from '../socket'\n\nconst now = () => new Date().toLocaleTimeString()\n\nfunction useLogs() {\n const [logs, setLogs] = React.useState<string[]>([])\n return {\n logs,\n push: (msg: string) =>\n setLogs((prev) => [\\`[\\${now()}] \\${msg}\\`, ...prev].slice(0, 60)),\n clear: () => setLogs([]),\n }\n}\n\nexport function HealthScreen() {\n const [echo, setEcho] = React.useState('hello rrroute')\n const httpGet = healthGet.useEndpoint()\n const httpPost = healthPost.useEndpoint()\n const socket = useSocketClient()\n const { logs, push, clear } = useLogs()\n\n useSocketConnection({\n event: 'health:connected',\n rooms: ['health'],\n joinMeta: roomMeta,\n leaveMeta: roomMeta,\n onMessage: (payload) => push(\\`connected \\${payload.socketId}\\`),\n })\n\n useSocketConnection({\n event: 'health:pong',\n rooms: ['health'],\n joinMeta: roomMeta,\n leaveMeta: roomMeta,\n onMessage: (payload) =>\n push(\\`pong at \\${payload.at}\\${payload.echo ? \\` (echo: \\${payload.echo})\\` : ''}\\`),\n })\n\n return (\n <View style={styles.card}>\n <Text style={styles.title}>RRRoutes health sandbox</Text>\n <View style={styles.section}>\n <Text style={styles.heading}>HTTP</Text>\n <Button title=\"GET /health\" onPress={() => httpGet.refetch()} />\n <View style={{ height: 12 }} />\n <TextInput\n style={styles.input}\n value={echo}\n onChangeText={setEcho}\n placeholder=\"echo payload\"\n />\n <Button\n title=\"POST /health\"\n onPress={() =>\n httpPost\n .mutateAsync({ echo })\n .then(() => push('POST /health ok'))\n }\n />\n <Text style={styles.label}>GET data</Text>\n <Text style={styles.code}>\n {JSON.stringify(httpGet.data ?? {}, null, 2)}\n </Text>\n <Text style={styles.label}>POST data</Text>\n <Text style={styles.code}>\n {JSON.stringify(httpPost.data ?? {}, null, 2)}\n </Text>\n </View>\n\n <View style={styles.section}>\n <Text style={styles.heading}>Socket</Text>\n <View style={styles.row}>\n <Button title=\"Connect\" onPress={() => socket.connect()} />\n <Button title=\"Disconnect\" onPress={() => socket.disconnect()} />\n </View>\n <View style={{ height: 8 }} />\n <Button\n title=\"Emit ping\"\n onPress={() => socket.emit('health:ping', { note: 'ping from app' })}\n />\n <View style={{ height: 8 }} />\n <View style={styles.row}>\n <Button\n title=\"Join room\"\n onPress={() => socket.joinRooms(['health'], roomMeta)}\n />\n <Button\n title=\"Leave room\"\n onPress={() => socket.leaveRooms(['health'], roomMeta)}\n />\n </View>\n </View>\n\n <View style={styles.section}>\n <Text style={styles.heading}>Socket logs</Text>\n <Button title=\"Clear logs\" onPress={clear} />\n <Text style={styles.code}>\n {logs.length === 0 ? 'No messages yet' : logs.join('\\\\n')}\n </Text>\n </View>\n </View>\n )\n}\n\nconst styles = StyleSheet.create({\n card: {\n backgroundColor: '#fff',\n borderRadius: 12,\n padding: 16,\n gap: 12,\n shadowColor: '#000',\n shadowOpacity: 0.05,\n shadowRadius: 8,\n },\n title: { fontSize: 20, fontWeight: '700' },\n section: { gap: 8 },\n heading: { fontWeight: '600', fontSize: 16 },\n row: { flexDirection: 'row', gap: 8, justifyContent: 'space-between' },\n input: {\n borderWidth: 1,\n borderColor: '#d0d4de',\n borderRadius: 8,\n padding: 8,\n },\n label: { marginTop: 6, fontWeight: '600' },\n code: {\n backgroundColor: '#0f172a',\n color: '#e2e8f0',\n padding: 8,\n borderRadius: 8,\n fontFamily: 'Courier',\n },\n})\n`\n}\n\nconst NATIVE_ENV = `API_URL=http://localhost:4000\nSOCKET_URL=http://localhost:4000\nSOCKET_PATH=/socket.io\n`\n\n// Scaffold orchestrator -------------------------------------------------------\n\nexport async function scaffoldClient(ctx: GeneratorContext) {\n return ctx.clientKind === 'react-native'\n ? scaffoldNativeClient(ctx)\n : scaffoldWebClient(ctx)\n}\n\nasync function scaffoldWebClient(ctx: GeneratorContext) {\n const baseDir = path.join(ctx.rootDir, 'packages', 'client')\n await ensureDir(path.join(baseDir, 'src', 'lib'))\n await ensureDir(path.join(baseDir, 'src', 'pages'))\n\n const pkgJson = {\n name: ctx.packageNames.client,\n version: '0.1.0',\n private: true,\n type: 'module',\n main: 'dist/index.js',\n scripts: {\n dev: 'vite',\n build: 'vite build',\n preview: 'vite preview',\n typecheck: 'tsc -p tsconfig.json --noEmit',\n },\n dependencies: {\n [ctx.packageNames.contract]: 'workspace:*',\n '@emeryld/rrroutes-client': '^2.5.3',\n '@tanstack/react-query': '^5.90.12',\n react: '^18.3.1',\n 'react-dom': '^18.3.1',\n 'socket.io-client': '^4.8.3',\n zod: '^4.2.1',\n },\n devDependencies: {\n '@types/react': '^18.3.27',\n '@types/react-dom': '^18.3.7',\n '@vitejs/plugin-react': '^4.3.4',\n typescript: '^5.9.3',\n vite: '^6.4.1',\n },\n }\n\n const files: Record<string, string> = {\n 'package.json': `${JSON.stringify(pkgJson, null, 2)}\\n`,\n 'tsconfig.json': `${JSON.stringify(baseTsConfig(), null, 2)}\\n`,\n 'vite.config.ts': viteConfig(),\n 'src/main.tsx': MAIN_TSX,\n 'src/App.tsx': appTsx(),\n 'src/lib/queryClient.ts': queryClient(ctx.packageNames.contract),\n 'src/lib/socket.tsx': socketProvider(ctx.packageNames.contract),\n 'src/pages/HealthPage.tsx': healthPage(ctx.packageNames.contract),\n 'src/styles.css': STYLES,\n 'src/env.d.ts': '/// <reference types=\"vite/client\" />\\n',\n 'index.html': indexHtml(),\n '.env': CLIENT_ENV,\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(baseDir, name)\n const writer = name === '.env' ? writeFileForce : writeFileIfMissing\n const result = await writer(fullPath, contents)\n const rel = path.relative(ctx.rootDir, fullPath)\n if (result === 'created' || result === undefined) log.created(rel)\n else log.skipped(rel)\n }\n}\n\nasync function scaffoldNativeClient(ctx: GeneratorContext) {\n const baseDir = path.join(ctx.rootDir, 'packages', 'client')\n await ensureDir(path.join(baseDir, 'src', 'screens'))\n\n const pkgJson = nativePackageJson(\n ctx.packageNames.client,\n ctx.packageNames.contract,\n )\n\n const files: Record<string, string> = {\n 'package.json': `${JSON.stringify(pkgJson, null, 2)}\\n`,\n 'tsconfig.json': `${JSON.stringify(NATIVE_TS_CONFIG, null, 2)}\\n`,\n 'app.json': `${JSON.stringify(nativeAppJson(ctx.appSlug), null, 2)}\\n`,\n 'babel.config.js': NATIVE_BABEL,\n 'App.tsx': nativeAppTsx(),\n 'src/queryClient.ts': nativeQueryClient(ctx.packageNames.contract),\n 'src/socket.tsx': nativeSocket(ctx.packageNames.contract),\n 'src/screens/HealthScreen.tsx': nativeHealthScreen(\n ctx.packageNames.contract,\n ),\n '.env': NATIVE_ENV,\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(baseDir, name)\n const writer = name === '.env' ? writeFileForce : writeFileIfMissing\n const result = await writer(fullPath, contents)\n const rel = path.relative(ctx.rootDir, fullPath)\n if (result === 'created' || result === undefined) log.created(rel)\n else log.skipped(rel)\n }\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nexport async function ensureDir(dir: string): Promise<void> {\n await fs.mkdir(dir, { recursive: true })\n}\n\nexport async function pathExists(target: string): Promise<boolean> {\n try {\n await fs.access(target)\n return true\n } catch {\n return false\n }\n}\n\nexport async function writeFileIfMissing(\n filePath: string,\n contents: string,\n): Promise<'created' | 'skipped'> {\n const dir = path.dirname(filePath)\n await ensureDir(dir)\n if (await pathExists(filePath)) {\n return 'skipped'\n }\n await fs.writeFile(filePath, contents, 'utf8')\n return 'created'\n}\n\nexport async function writeFileForce(\n filePath: string,\n contents: string,\n): Promise<void> {\n const dir = path.dirname(filePath)\n await ensureDir(dir)\n await fs.writeFile(filePath, contents, 'utf8')\n}\n","export const log = {\n info(msg: string) {\n console.log(msg)\n },\n step(msg: string) {\n console.log(`• ${msg}`)\n },\n created(target: string) {\n console.log(` created ${target}`)\n },\n skipped(target: string) {\n console.log(` skipped ${target} (already exists)`)\n },\n warn(msg: string) {\n console.warn(` warning: ${msg}`)\n },\n error(msg: string) {\n console.error(` error: ${msg}`)\n },\n}\n","import path from 'node:path'\nimport { GeneratorContext } from '../types'\nimport { ensureDir, writeFileIfMissing } from '../utils/fs'\nimport { log } from '../utils/log'\n\nconst CONTRACT_TS = `import { defineSocketEvents, finalize, resource } from '@emeryld/rrroutes-contract'\nimport { z } from 'zod'\n\nconst routes = resource('/api')\n .sub(\n resource('health')\n .get({\n outputSchema: z.object({\n status: z.literal('ok'),\n html: z.string().describe('Tiny HTML heartbeat'),\n }),\n description: 'Basic GET health probe for uptime + docs.',\n })\n .post({\n bodySchema: z.object({\n echo: z.string().optional(),\n }),\n outputSchema: z.object({\n status: z.literal('ok'),\n received: z.string().optional(),\n }),\n description: 'POST health probe that echoes a payload.',\n })\n .done(),\n )\n .done()\n\nexport const registry = finalize(routes)\n\nconst sockets = defineSocketEvents(\n {\n joinMetaMessage: z.object({ room: z.string().optional() }),\n leaveMetaMessage: z.object({ room: z.string().optional() }),\n pingPayload: z.object({\n note: z.string().default('ping'),\n sentAt: z.string(),\n }),\n pongPayload: z.object({\n ok: z.boolean(),\n receivedAt: z.string(),\n echo: z.string().optional(),\n }),\n },\n {\n 'health:connected': {\n message: z.object({\n socketId: z.string(),\n at: z.string(),\n message: z.string(),\n }),\n },\n 'health:ping': {\n message: z.object({\n note: z.string().default('ping'),\n }),\n },\n 'health:pong': {\n message: z.object({\n ok: z.literal(true),\n at: z.string(),\n echo: z.string().optional(),\n }),\n },\n },\n)\n\nexport const socketConfig = sockets.config\nexport const socketEvents = sockets.events\nexport type AppRegistry = typeof registry\n`\n\nexport async function scaffoldContract(ctx: GeneratorContext) {\n const baseDir = path.join(ctx.rootDir, 'packages', 'contract')\n await ensureDir(path.join(baseDir, 'src'))\n\n const pkgJson = {\n name: ctx.packageNames.contract,\n version: '0.1.0',\n private: false,\n type: 'module',\n main: 'dist/index.js',\n types: 'dist/index.d.ts',\n files: ['dist'],\n scripts: {\n build: 'tsc -p tsconfig.json',\n typecheck: 'tsc -p tsconfig.json --noEmit',\n watch: 'tsc -p tsconfig.json --watch --preserveWatchOutput',\n },\n dependencies: {\n '@emeryld/rrroutes-contract': '^2.5.2',\n zod: '^4.2.1',\n },\n devDependencies: {\n typescript: '^5.9.3',\n },\n }\n\n const tsconfig = {\n extends: '../../tsconfig.base.json',\n compilerOptions: {\n outDir: 'dist',\n rootDir: 'src',\n declaration: true,\n sourceMap: true,\n },\n include: ['src/**/*'],\n }\n\n const files: Record<string, string> = {\n 'package.json': `${JSON.stringify(pkgJson, null, 2)}\\n`,\n 'tsconfig.json': `${JSON.stringify(tsconfig, null, 2)}\\n`,\n 'src/index.ts': CONTRACT_TS,\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(baseDir, name)\n const result = await writeFileIfMissing(fullPath, contents)\n if (result === 'created') log.created(path.relative(ctx.rootDir, fullPath))\n else log.skipped(path.relative(ctx.rootDir, fullPath))\n }\n}\n","import path from 'node:path'\nimport { GeneratorContext } from '../types'\nimport { ensureDir, writeFileIfMissing } from '../utils/fs'\nimport { log } from '../utils/log'\n\nfunction formatJson(obj: unknown): string {\n return `${JSON.stringify(obj, null, 2)}\\n`\n}\n\nexport async function scaffoldRoot(ctx: GeneratorContext) {\n await ensureDir(ctx.rootDir)\n\n const paths: Record<string, string[]> = {}\n const addPaths = (pkgName: string, dir: string) => {\n const srcRoot = path.posix.join('packages', dir, 'src')\n paths[pkgName] = [path.posix.join(srcRoot, 'index.ts')]\n paths[`${pkgName}/*`] = [path.posix.join(srcRoot, '*')]\n }\n if (ctx.targets.contract) addPaths(ctx.packageNames.contract, 'contract')\n if (ctx.targets.server) addPaths(ctx.packageNames.server, 'server')\n if (ctx.targets.client) addPaths(ctx.packageNames.client, 'client')\n\n const scripts: Record<string, string> = {\n build: 'npm run build --workspaces',\n typecheck: 'npm run typecheck --workspaces --if-present',\n lint: 'npm run lint --workspaces --if-present',\n }\n if (ctx.targets.server) {\n scripts['dev:server'] = `npm run dev --workspace ${ctx.packageNames.server}`\n }\n if (ctx.targets.client) {\n scripts['dev:client'] = `npm run dev --workspace ${ctx.packageNames.client}`\n }\n if (ctx.targets.contract) {\n scripts['dev:contract'] = `npm run watch --workspace ${ctx.packageNames.contract}`\n }\n\n const highlights = ['- Shared contract package (RRRoutes registry + sockets)']\n if (ctx.targets.server) {\n highlights.unshift(\n '- Backend (Express + Socket.IO + RRRoutes server bindings)',\n )\n }\n if (ctx.targets.client) {\n highlights.splice(\n ctx.targets.server ? 1 : 0,\n 0,\n '- Frontend client (React or React Native) with React Query + sockets',\n )\n }\n\n const quickstart: string[] = ['1) Install deps: `npm install` (workspaces)']\n if (ctx.targets.server) {\n quickstart.push(\n `${quickstart.length + 1}) Backend env: edit \\`packages/server/.env\\``,\n )\n }\n if (ctx.targets.contract) {\n quickstart.push(\n `${quickstart.length + 1}) Optional: keep shared contract rebuilding via \\`npm run dev:contract\\``,\n )\n }\n if (ctx.targets.client) {\n quickstart.push(\n `${quickstart.length + 1}) Client env: edit \\`packages/client/.env\\``,\n )\n }\n if (ctx.targets.server || ctx.targets.client) {\n quickstart.push(\n `${quickstart.length + 1}) Run dev servers:${\n ctx.targets.server ? `\\n - API: \\`npm run dev:server\\`` : ''\n }${ctx.targets.client ? `\\n - Client: \\`npm run dev:client\\`` : ''}`,\n )\n }\n\n const pkgJson = {\n name: `${ctx.appSlug}-stack`,\n private: true,\n workspaces: ['packages/*'],\n scripts,\n devDependencies: {\n typescript: '^5.9.3',\n },\n }\n\n const files: Record<string, string> = {\n 'package.json': formatJson(pkgJson),\n 'pnpm-workspace.yaml': \"packages:\\n - 'packages/*'\\n\",\n 'tsconfig.base.json': formatJson({\n $schema: 'https://json.schemastore.org/tsconfig',\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n moduleResolution: 'Bundler',\n jsx: 'react-jsx',\n strict: true,\n skipLibCheck: true,\n resolveJsonModule: true,\n forceConsistentCasingInFileNames: true,\n sourceMap: true,\n baseUrl: '.',\n paths,\n },\n }),\n '.gitignore': [\n 'node_modules',\n 'dist',\n '.turbo',\n '.expo',\n '.DS_Store',\n '.env',\n '.env.local',\n 'npm-debug.log*',\n 'yarn-error.log',\n ].join('\\n'),\n README: [\n `# ${ctx.projectName} (RRRoutes starter)`,\n '',\n 'Generated via `create-rrroutes`. Includes:',\n ...highlights,\n '',\n '## Quickstart',\n ...quickstart,\n '',\n ctx.targets.server\n ? 'Dockerfile for the API lives in `packages/server/Dockerfile`.'\n : '',\n '',\n ]\n .filter(Boolean)\n .join('\\n'),\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(ctx.rootDir, name)\n const result = await writeFileIfMissing(fullPath, contents)\n if (result === 'created') log.created(path.relative(ctx.rootDir, fullPath))\n else log.skipped(path.relative(ctx.rootDir, fullPath))\n }\n}\n","import path from 'node:path'\nimport { GeneratorContext } from '../types'\nimport { ensureDir, writeFileForce, writeFileIfMissing } from '../utils/fs'\nimport { log } from '../utils/log'\n\nfunction serverIndexTs() {\n return `import 'dotenv/config'\nimport http from 'node:http'\nimport { app } from './http'\nimport { createSockets } from './socket'\nimport { prisma } from './prisma'\n\nasync function main() {\n const PORT = Number.parseInt(process.env.PORT ?? '4000', 10)\n const CORS_ORIGIN = process.env.CORS_ORIGIN ?? 'http://localhost:5173'\n const SOCKET_PATH = process.env.SOCKET_PATH ?? '/socket.io'\n\n await prisma.$connect()\n\n const httpServer = http.createServer(app)\n const sockets = createSockets(httpServer, {\n corsOrigin: CORS_ORIGIN,\n socketPath: SOCKET_PATH,\n })\n\n httpServer.listen(PORT, () => {\n console.log(\n \\`API listening on http://localhost:\\${PORT} (CORS origin: \\${CORS_ORIGIN})\\`,\n )\n })\n\n const shutdown = async () => {\n await sockets.destroy()\n await prisma.$disconnect()\n }\n process.on('SIGTERM', shutdown)\n process.on('SIGINT', shutdown)\n}\n\nmain().catch(async (err) => {\n console.error(err)\n await prisma.$disconnect().catch(() => {})\n process.exit(1)\n})\n`\n}\n\nfunction httpTs(contractImport: string) {\n return `import express, { Router } from 'express'\nimport cors from 'cors'\nimport { createRRRoute } from '@emeryld/rrroutes-server'\nimport { registry } from '${contractImport}'\nimport { controllers, type RequestCtx } from './controllers'\nimport { prisma } from './prisma'\n\nconst CORS_ORIGIN = process.env.CORS_ORIGIN ?? 'http://localhost:5173'\n\nexport const app: Router = express()\napp.use(cors({ origin: CORS_ORIGIN, credentials: true }))\napp.use(express.json())\n\napp.get('/', (_req, res) => {\n res.send('<h1>RRRoutes starter API</h1>')\n})\n\nconst routes = createRRRoute<RequestCtx>(app, {\n buildCtx: async () => ({\n requestId: Math.random().toString(36).slice(2),\n prisma,\n routesLogger: console,\n }),\n debug:\n process.env.NODE_ENV === 'development'\n ? { request: true, handler: true }\n : undefined,\n})\n\nroutes.registerControllers(registry, controllers)\nroutes.warnMissingControllers(registry, console)\nexport { routes }\n`\n}\n\nfunction controllersTs(contractImport: string) {\n return `import { defineControllers } from '@emeryld/rrroutes-server'\nimport type { PrismaClient } from '@prisma/client'\nimport { registry } from '${contractImport}'\n\nexport type RequestCtx = {\n prisma: PrismaClient\n requestId: string\n}\n\nexport const controllers = defineControllers<typeof registry, RequestCtx>()({\n 'GET /api/health': {\n handler: async ({ ctx }) => {\n await ctx.prisma.healthCheck.create({\n data: { note: 'GET health' },\n })\n return {\n out:{\n status: 'ok',\n html: '<!doctype html><html><body><h1>healthy</h1></body></html>',\n}\n }\n },\n },\n 'POST /api/health': {\n handler: async ({ ctx, body }) => {\n await ctx.prisma.healthCheck.create({\n data: { note: body?.echo ?? 'POST health' },\n })\n return {\n out:{\n status: 'ok',\n received: body?.echo ?? 'pong',\n}\n }\n },\n },\n})\n`\n}\n\nfunction socketTs(contractImport: string) {\n return `import { Server as SocketIOServer } from 'socket.io'\nimport type { Server } from 'node:http'\nimport { createSocketConnections } from '@emeryld/rrroutes-server'\nimport { socketConfig, socketEvents } from '${contractImport}'\n\nexport function createSockets(\n httpServer: Server,\n opts: { corsOrigin: string; socketPath: string },\n) {\n const io = new SocketIOServer(httpServer, {\n cors: { origin: opts.corsOrigin, credentials: true },\n path: opts.socketPath,\n })\n\n const sockets = createSocketConnections(io, socketEvents, {\n config: socketConfig,\n heartbeat: { enabled: true },\n sys: {\n 'sys:connect': async ({ socket, helper, complete }) => {\n helper.emit('health:connected', {\n socketId: socket.id,\n at: new Date().toISOString(),\n message: 'connected',\n })\n complete()\n },\n 'sys:disconnect': async ({ cleanup }) => cleanup(),\n 'sys:ping': async ({ ping }) => ({\n ok: true,\n receivedAt: new Date().toISOString(),\n echo: ping.note,\n }),\n 'sys:room_join': async ({ rooms, join }) => {\n await Promise.all(rooms.map((room) => join(room)))\n },\n 'sys:room_leave': async ({ rooms, leave }) => {\n await Promise.all(rooms.map((room) => leave(room)))\n },\n },\n })\n\n sockets.on('health:ping', async (payload, ctx) => {\n sockets.emit(\n 'health:pong',\n { ok: true, at: new Date().toISOString(), echo: payload.note },\n ctx.socketId,\n )\n })\n\n return sockets\n}\n`\n}\n\nfunction prismaTs() {\n return `import { PrismaClient } from '@prisma/client'\n\nexport const prisma = new PrismaClient({\n log: ['warn', 'error'],\n})\n`\n}\n\nfunction prismaSchema() {\n return `generator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel HealthCheck {\n id String @id @default(uuid())\n note String?\n createdAt DateTime @default(now())\n}\n`\n}\n\nfunction serverEnv() {\n return [\n 'PORT=4000',\n 'NODE_ENV=development',\n 'CORS_ORIGIN=http://localhost:5173',\n 'SOCKET_PATH=/socket.io',\n 'DATABASE_URL=postgresql://postgres:postgres@localhost:5432/rrroutes',\n ].join('\\n')\n}\n\nconst tsNodeLoaderRegistrationImport =\n 'data:text/javascript,import { register } from \"node:module\"; import { pathToFileURL } from \"node:url\"; register(\"ts-node/esm\", pathToFileURL(\"./\"));'\n\nexport const nodemonExecCommand = `node --import '${tsNodeLoaderRegistrationImport}' ./src/index.ts`\n\nfunction nodemonJson() {\n return `${JSON.stringify(\n {\n watch: ['src'],\n ext: 'ts',\n ignore: ['src/**/*.test.ts'],\n exec: nodemonExecCommand,\n },\n null,\n 2,\n )}\\n`\n}\n\nfunction dockerfile(serverName: string, contractName: string) {\n return `FROM node:20-alpine\nWORKDIR /app\n\n# Install workspace deps (hoists to /app/node_modules)\nCOPY package.json pnpm-workspace.yaml tsconfig.base.json ./\nCOPY packages/contract/package.json packages/contract/package.json\nCOPY packages/server/package.json packages/server/package.json\nCOPY packages/server/prisma/schema.prisma packages/server/prisma/schema.prisma\nRUN npm install\n\n# Copy source and build server + contract\nCOPY packages ./packages\n\n# Generate Prisma client\nRUN npx prisma generate --schema packages/server/prisma/schema.prisma\n\nRUN npm run build --workspace ${contractName} && npm run build --workspace ${serverName}\n\nEXPOSE 4000\nCMD [\"node\", \"packages/server/dist/index.js\"]\n`\n}\n\nexport async function scaffoldServer(ctx: GeneratorContext) {\n const baseDir = path.join(ctx.rootDir, 'packages', 'server')\n await ensureDir(path.join(baseDir, 'src'))\n await ensureDir(path.join(baseDir, 'prisma'))\n\n const pkgJson = {\n name: ctx.packageNames.server,\n version: '0.1.0',\n private: false,\n type: 'module',\n main: 'dist/index.js',\n types: 'dist/index.d.ts',\n files: ['dist'],\n scripts: {\n dev: 'nodemon --config nodemon.json',\n build: 'tsc -p tsconfig.json',\n typecheck: 'tsc -p tsconfig.json --noEmit',\n start: 'node dist/index.js',\n 'prisma:generate': 'prisma generate --schema prisma/schema.prisma',\n 'prisma:migrate':\n 'prisma migrate dev --schema prisma/schema.prisma --name init',\n 'db:start':\n 'docker run --name rrroutes-db -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=rrroutes -p 5432:5432 -d postgres:15 || docker start rrroutes-db',\n 'db:stop': 'docker stop rrroutes-db || true',\n },\n dependencies: {\n [ctx.packageNames.contract]: 'workspace:*',\n '@emeryld/rrroutes-server': '^2.4.1',\n '@prisma/client': '^5.22.0',\n 'socket.io': '^4.8.1',\n express: '^5.1.0',\n cors: '^2.8.5',\n dotenv: '^16.4.5',\n zod: '^4.2.1',\n },\n devDependencies: {\n '@types/express': '^5.0.6',\n '@types/node': '^24.10.2',\n prisma: '^5.22.0',\n typescript: '^5.9.3',\n 'ts-node': '^10.9.2',\n nodemon: '^3.1.9',\n },\n }\n\n const tsconfig = {\n extends: '../../tsconfig.base.json',\n compilerOptions: {\n outDir: 'dist',\n rootDir: 'src',\n declaration: true,\n sourceMap: true,\n },\n include: ['src/**/*'],\n }\n\n const files: Record<string, string> = {\n 'package.json': `${JSON.stringify(pkgJson, null, 2)}\\n`,\n 'tsconfig.json': `${JSON.stringify(tsconfig, null, 2)}\\n`,\n 'src/index.ts': serverIndexTs(),\n 'src/http.ts': httpTs(ctx.packageNames.contract),\n 'src/controllers.ts': controllersTs(ctx.packageNames.contract),\n 'src/socket.ts': socketTs(ctx.packageNames.contract),\n 'src/prisma.ts': prismaTs(),\n 'prisma/schema.prisma': prismaSchema(),\n '.env': `${serverEnv()}\\n`,\n 'nodemon.json': nodemonJson(),\n Dockerfile: dockerfile(ctx.packageNames.server, ctx.packageNames.contract),\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(baseDir, name)\n const writer =\n name === '.env'\n ? writeFileForce // allow updating env defaults\n : writeFileIfMissing\n const result = await writer(fullPath, contents)\n const rel = path.relative(ctx.rootDir, fullPath)\n if (result === 'created' || result === undefined) log.created(rel)\n else log.skipped(rel)\n }\n}\n","import { createInterface } from 'node:readline/promises'\nimport { stdin as input, stdout as output } from 'node:process'\n\ntype Option<T> = {\n label: string\n value: T\n}\n\nexport function createPrompt() {\n const rl = createInterface({ input, output })\n\n return {\n async text(message: string, fallback?: string) {\n const suffix = fallback ? ` (${fallback})` : ''\n const answer = (await rl.question(`${message}${suffix}: `)).trim()\n return answer.length > 0 ? answer : fallback\n },\n async confirm(message: string, fallback = true) {\n const suffix = fallback ? ' (Y/n)' : ' (y/N)'\n const answer = (await rl.question(`${message}${suffix}: `)).trim()\n if (!answer) return fallback\n return ['y', 'yes'].includes(answer.toLowerCase())\n },\n async select<T>(\n message: string,\n options: Option<T>[],\n fallbackIndex = 0,\n ) {\n console.log(message)\n options.forEach((opt, idx) =>\n console.log(` [${idx + 1}] ${opt.label}`),\n )\n const answer = (await rl.question(`Choose 1-${options.length}: `)).trim()\n const idx = Number.parseInt(answer, 10)\n const normalized =\n Number.isNaN(idx) || idx < 1 || idx > options.length\n ? fallbackIndex\n : idx - 1\n return options[normalized]!.value\n },\n close() {\n rl.close()\n },\n }\n}\n","import { spawn } from 'node:child_process'\n\nexport async function runCommand(\n cmd: string,\n args: string[],\n cwd: string,\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(cmd, args, {\n cwd,\n stdio: 'inherit',\n shell: process.platform === 'win32',\n })\n child.on('exit', (code) => {\n if (code === 0) resolve()\n else reject(new Error(`${cmd} ${args.join(' ')} exited with ${code}`))\n })\n child.on('error', (err) => reject(err))\n })\n}\n","export function slugify(input: string, fallback = 'rrroutes-app'): string {\n const slug = input\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n return slug.length > 0 ? slug : fallback\n}\n"],"mappings":"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","names":["import_node_path","import_node_path","fs","path","path","import_node_path","path","import_node_path","path","import_node_path","path","import_promises","input","output","idx","input","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/generators/client.ts","../src/utils/fs.ts","../src/utils/log.ts","../src/generators/contract.ts","../src/generators/root.ts","../src/generators/server.ts","../src/utils/prompt.ts","../src/utils/run.ts","../src/utils/strings.ts"],"sourcesContent":["import path from 'node:path'\nimport { scaffoldClient } from './generators/client'\nimport { scaffoldContract } from './generators/contract'\nimport { scaffoldRoot } from './generators/root'\nimport { scaffoldServer } from './generators/server'\nimport { GeneratorContext, Targets, type ClientKind } from './types'\nimport { log } from './utils/log'\nimport { createPrompt } from './utils/prompt'\nimport { runCommand } from './utils/run'\nimport { slugify } from './utils/strings'\n\nfunction resolveTargets(choice: string): Targets {\n if (choice === 'all')\n return { client: true, server: true, contract: true } as const\n if (choice === 'client')\n return { client: true, server: false, contract: true } as const\n if (choice === 'server')\n return { client: false, server: true, contract: true } as const\n return { client: false, server: false, contract: true } as const\n}\n\nasync function gatherContext(): Promise<GeneratorContext> {\n const prompt = createPrompt()\n try {\n const projectName =\n (await prompt.text('Project name', 'rrroutes-starter')) ??\n 'rrroutes-starter'\n const appSlug = slugify(projectName)\n const targetDirInput =\n (await prompt.text('Target directory', `./${appSlug}`)) ?? `./${appSlug}`\n const rootDir = path.resolve(process.cwd(), targetDirInput)\n const scopeInput =\n (await prompt.text('NPM scope (without @)', appSlug)) ?? appSlug\n const packageScope = slugify(scopeInput)\n\n const selection = await prompt.select('What should we create?', [\n {\n label: 'Everything (contract + server + client)',\n value: 'all',\n },\n { label: 'Contract only', value: 'contract' },\n { label: 'Backend only', value: 'server' },\n { label: 'Frontend only', value: 'client' },\n ])\n const targets = resolveTargets(selection)\n\n let clientKind: ClientKind = 'react'\n if (targets.client) {\n clientKind = await prompt.select<ClientKind>(\n 'Frontend runtime',\n [\n { label: 'React (web, Vite)', value: 'react' },\n { label: 'React Native (Expo)', value: 'react-native' },\n ],\n 0,\n )\n }\n\n const packageNames = {\n contract: `@${packageScope}/contract`,\n server: `@${packageScope}/server`,\n client: `@${packageScope}/client`,\n }\n\n return {\n projectName,\n appSlug,\n packageScope,\n rootDir,\n clientKind,\n targets,\n packageNames,\n }\n } finally {\n prompt.close()\n }\n}\n\nasync function runPostScaffold(ctx: GeneratorContext) {\n if (process.env.CREATERRROUTES_SKIP_POSTINSTALL === '1') {\n log.warn('Skipping install/build steps (CREATERRROUTES_SKIP_POSTINSTALL=1).')\n return\n }\n\n const steps: { label: string; args: string[]; enabled: boolean }[] = [\n {\n label: 'Installing workspace dependencies (pnpm install)',\n args: ['install'],\n enabled: true,\n },\n {\n label: `Building shared contract (${ctx.packageNames.contract})`,\n args: ['--filter', ctx.packageNames.contract, 'build'],\n enabled: ctx.targets.contract,\n },\n {\n label: `Generating Prisma client for ${ctx.packageNames.server}`,\n args: ['--filter', ctx.packageNames.server, 'prisma:generate'],\n enabled: ctx.targets.server,\n },\n ]\n\n for (const step of steps) {\n if (!step.enabled) continue\n try {\n log.step(step.label)\n await runCommand('pnpm', step.args, ctx.rootDir)\n } catch (err) {\n log.warn(\n `Step failed (${step.label}). Run manually: pnpm ${step.args.join(' ')}\\n${String(err)}`,\n )\n break\n }\n }\n}\n\nasync function main() {\n const ctx = await gatherContext()\n log.info(`Scaffolding RRRoutes starter in ${ctx.rootDir}`)\n\n await scaffoldRoot(ctx)\n if (ctx.targets.contract) await scaffoldContract(ctx)\n if (ctx.targets.server) await scaffoldServer(ctx)\n if (ctx.targets.client) await scaffoldClient(ctx)\n\n await runPostScaffold(ctx)\n\n log.info('Done. Install dependencies and start hacking!')\n}\n\nmain().catch((err) => {\n log.error(err instanceof Error ? err.message : String(err))\n process.exit(1)\n})\n","import path from 'node:path'\nimport { GeneratorContext } from '../types'\nimport { ensureDir, writeFileForce, writeFileIfMissing } from '../utils/fs'\nimport { log } from '../utils/log'\n\nfunction baseTsConfig() {\n return {\n extends: '../../tsconfig.base.json',\n compilerOptions: {\n outDir: 'dist',\n types: ['vite/client'],\n },\n include: ['src/**/*', 'vite.config.ts'],\n }\n}\n\nfunction viteConfig() {\n return `import { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n plugins: [react()],\n})\n`\n}\n\nfunction queryClient(contractImport: string) {\n return `import { QueryClient } from '@tanstack/react-query'\nimport { createRouteClient } from '@emeryld/rrroutes-client'\nimport { registry } from '${contractImport}'\n\nconst baseUrl = import.meta.env.VITE_API_URL ?? 'http://localhost:4000'\n\nexport const queryClient = new QueryClient()\n\nexport const routeClient = createRouteClient({\n baseUrl,\n queryClient,\n environment: import.meta.env.MODE === 'production' ? 'production' : 'development',\n})\n\nexport const healthGet = routeClient.build(registry.byKey['GET /api/health'])\nexport const healthPost = routeClient.build(registry.byKey['POST /api/health'])\n`\n}\n\nfunction socketProvider(contractImport: string) {\n return `import React from 'react'\nimport { io, type Socket } from 'socket.io-client'\nimport {\n buildSocketProvider,\n type SocketClientOptions,\n} from '@emeryld/rrroutes-client'\nimport { socketConfig, socketEvents } from '${contractImport}'\n\nconst socketUrl = import.meta.env.VITE_SOCKET_URL ?? 'http://localhost:4000'\nconst socketPath = import.meta.env.VITE_SOCKET_PATH ?? '/socket.io'\n\nconst sysEvents: SocketClientOptions<\n typeof socketEvents,\n typeof socketConfig\n>['sys'] = {\n 'sys:connect': async ({ socket }) => {\n console.info('socket connected', socket.id)\n },\n 'sys:disconnect': async ({ reason }) => {\n console.info('socket disconnected', reason)\n },\n 'sys:reconnect': async ({ attempt, socket }) => {\n console.info('socket reconnect', attempt, socket?.id)\n },\n 'sys:connect_error': async ({ error }) => {\n console.warn('socket connect error', error)\n },\n 'sys:ping': () => ({\n note: 'client-heartbeat',\n sentAt: new Date().toISOString(),\n }),\n 'sys:pong': async ({ payload }) => {\n console.info('socket pong', payload)\n },\n 'sys:room_join': async ({ rooms }) => {\n console.info('joining rooms', rooms)\n return true\n },\n 'sys:room_leave': async ({ rooms }) => {\n console.info('leaving rooms', rooms)\n return true\n },\n}\n\nconst baseOptions: Omit<\n SocketClientOptions<typeof socketEvents, typeof socketConfig>,\n 'socket'\n> = {\n config: socketConfig,\n sys: sysEvents,\n environment: import.meta.env.MODE === 'production' ? 'production' : 'development',\n heartbeat: { intervalMs: 15_000, timeoutMs: 7_500 },\n debug: {\n connection: true,\n heartbeat: true,\n },\n}\n\nconst { SocketProvider, useSocketClient, useSocketConnection } =\n buildSocketProvider({\n events: socketEvents,\n options: baseOptions,\n })\n\nfunction getSocket(): Promise<Socket> {\n return Promise.resolve(\n io(socketUrl, {\n path: socketPath,\n transports: ['websocket'],\n }),\n )\n}\n\nexport const roomMeta = { room: 'health' }\n\nexport function AppSocketProvider(props: React.PropsWithChildren) {\n return (\n <SocketProvider\n getSocket={getSocket}\n destroyLeaveMeta={roomMeta}\n fallback={<p>Connecting socket…</p>}\n >\n {props.children}\n </SocketProvider>\n )\n}\n\nexport { useSocketClient, useSocketConnection }\n`\n}\n\nconst MAIN_TSX = `import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport App from './App'\nimport './styles.css'\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <App />\n </React.StrictMode>,\n)\n`\n\nfunction appTsx() {\n return `import React from 'react'\nimport { QueryClientProvider } from '@tanstack/react-query'\nimport { queryClient } from './lib/queryClient'\nimport { AppSocketProvider } from './lib/socket'\nimport { HealthPage } from './pages/HealthPage'\n\nexport default function App() {\n return (\n <QueryClientProvider client={queryClient}>\n <AppSocketProvider>\n <HealthPage />\n </AppSocketProvider>\n </QueryClientProvider>\n )\n}\n`\n}\n\nconst STYLES = `:root {\n font-family: 'Inter', system-ui, -apple-system, sans-serif;\n color: #0b1021;\n background: #f7f8fb;\n}\n\nbody {\n margin: 0;\n background: radial-gradient(circle at 20% 20%, #eef2ff, #f7f8fb 45%);\n min-height: 100vh;\n}\n\n.health {\n max-width: 960px;\n margin: 0 auto;\n padding: 32px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));\n gap: 16px;\n}\n\n.card {\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n padding: 16px;\n box-shadow: 0 8px 24px rgba(12, 18, 32, 0.05);\n}\n\nbutton {\n background: #0f172a;\n color: #fff;\n border: none;\n border-radius: 8px;\n padding: 10px 12px;\n cursor: pointer;\n font-weight: 600;\n}\n\nbutton.secondary {\n background: #e2e8f0;\n color: #0f172a;\n}\n\nbutton + button {\n margin-left: 8px;\n}\n\ntextarea {\n width: 100%;\n min-height: 80px;\n}\n\n.logs {\n font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo,\n monospace;\n background: #0f172a;\n color: #e2e8f0;\n padding: 12px;\n border-radius: 8px;\n min-height: 160px;\n white-space: pre-line;\n}\n`\n\nfunction healthPage(contractImport: string) {\n return `import React from 'react'\nimport { healthGet, healthPost } from '../lib/queryClient'\nimport { roomMeta, useSocketClient, useSocketConnection } from '../lib/socket'\n\nconst now = () => new Date().toLocaleTimeString()\n\nfunction useLogs() {\n const [logs, setLogs] = React.useState<string[]>([])\n return {\n logs,\n push: (msg: string) =>\n setLogs((prev) => [\\`[\\${now()}] \\${msg}\\`, ...prev].slice(0, 60)),\n clear: () => setLogs([]),\n }\n}\n\nexport function HealthPage() {\n const [echo, setEcho] = React.useState('hello rrroute')\n const httpGet = healthGet.useEndpoint()\n const httpPost = healthPost.useEndpoint()\n const socket = useSocketClient()\n const { logs, push, clear } = useLogs()\n\n useSocketConnection({\n event: 'health:connected',\n rooms: ['health'],\n joinMeta: roomMeta,\n leaveMeta: roomMeta,\n onMessage: (payload) => {\n push(\\`socket connected (\\${payload.socketId})\\`)\n },\n })\n\n useSocketConnection({\n event: 'health:pong',\n rooms: ['health'],\n joinMeta: roomMeta,\n leaveMeta: roomMeta,\n onMessage: (payload) => {\n push(\n \\`pong at \\${payload.at}\\${payload.echo ? \\` (echo: \\${payload.echo})\\` : ''}\\`,\n )\n },\n })\n\n return (\n <div className=\"health\">\n <h1>RRRoutes health sandbox</h1>\n <div className=\"grid\">\n <div className=\"card\">\n <h2>HTTP endpoints</h2>\n <p>GET and POST against the shared contract.</p>\n <div>\n <button onClick={() => httpGet.refetch()}>GET /health</button>\n {httpGet.error ? (\n <p style={{ color: 'crimson', marginTop: 6 }}>\n GET error: {String(httpGet.error)}\n </p>\n ) : null}\n </div>\n <div style={{ marginTop: 12 }}>\n <input\n value={echo}\n onChange={(e) => setEcho(e.target.value)}\n placeholder=\"echo payload\"\n style={{ width: '100%', padding: '8px' }}\n />\n <div style={{ marginTop: 8 }}>\n <button\n onClick={() =>\n httpPost.mutateAsync({ echo }).then(() => {\n push('POST /health ok')\n })\n }\n >\n POST /health\n </button>\n </div>\n {httpPost.error ? (\n <p style={{ color: 'crimson', marginTop: 6 }}>\n POST error: {String(httpPost.error)}\n </p>\n ) : null}\n </div>\n <div style={{ marginTop: 12 }}>\n <strong>GET data</strong>\n <pre>{JSON.stringify(httpGet.data, null, 2) ?? 'none'}</pre>\n <strong>POST data</strong>\n <pre>{JSON.stringify(httpPost.data, null, 2) ?? 'none'}</pre>\n </div>\n </div>\n\n <div className=\"card\">\n <h2>Socket</h2>\n <p>Connect, ping, and watch lifecycle events.</p>\n <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>\n <button onClick={() => socket.connect()}>Connect</button>\n <button className=\"secondary\" onClick={() => socket.disconnect()}>\n Disconnect\n </button>\n <button\n onClick={() =>\n socket.emit('health:ping', { note: 'ping from client' })\n }\n >\n Emit ping\n </button>\n <button\n className=\"secondary\"\n onClick={() => socket.joinRooms(['health'], roomMeta)}\n >\n Join room\n </button>\n <button\n className=\"secondary\"\n onClick={() => socket.leaveRooms(['health'], roomMeta)}\n >\n Leave room\n </button>\n </div>\n {httpGet.error || httpPost.error ? (\n <p style={{ color: 'crimson', marginTop: 8 }}>\n Check server logs; errors will also show above.\n </p>\n ) : null}\n </div>\n\n <div className=\"card\">\n <h2>Socket logs</h2>\n <button className=\"secondary\" onClick={clear}>\n Clear\n </button>\n <div className=\"logs\">\n {logs.length === 0 ? 'No messages yet' : logs.join('\\\\n')}\n </div>\n </div>\n </div>\n </div>\n )\n}\n`\n}\n\nfunction indexHtml() {\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>RRRoutes starter</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"></script>\n </body>\n</html>\n`\n}\n\nconst CLIENT_ENV = `VITE_API_URL=http://localhost:4000\nVITE_SOCKET_URL=http://localhost:4000\nVITE_SOCKET_PATH=/socket.io\n`\n\n// React Native / Expo template ------------------------------------------------\n\nfunction nativePackageJson(clientName: string, contractName: string) {\n return {\n name: clientName,\n version: '0.1.0',\n private: true,\n main: 'expo/AppEntry',\n scripts: {\n start: 'expo start',\n android: 'expo start --android',\n ios: 'expo start --ios',\n web: 'expo start --web',\n test: 'echo \"add tests\"',\n },\n dependencies: {\n [contractName]: 'workspace:*',\n '@emeryld/rrroutes-client': '^2.5.3',\n '@tanstack/react-query': '^5.90.12',\n expo: '~52.0.8',\n 'expo-constants': '~16.0.2',\n 'expo-status-bar': '~2.0.1',\n react: '18.3.1',\n 'react-native': '0.76.6',\n 'react-native-safe-area-context': '4.12.0',\n 'react-native-screens': '4.4.0',\n 'socket.io-client': '^4.8.3',\n zod: '^4.2.1',\n },\n devDependencies: {\n '@babel/core': '^7.25.2',\n '@types/react': '~18.2.79',\n '@types/react-native': '~0.73.0',\n typescript: '^5.9.3',\n },\n }\n}\n\nfunction nativeAppJson(appSlug: string) {\n return {\n expo: {\n name: `${appSlug}-client`,\n slug: `${appSlug}-client`,\n version: '0.1.0',\n orientation: 'portrait',\n scheme: appSlug,\n platforms: ['ios', 'android', 'web'],\n userInterfaceStyle: 'light',\n extra: {\n apiUrl: 'http://localhost:4000',\n socketUrl: 'http://localhost:4000',\n socketPath: '/socket.io',\n },\n experiments: {\n typedRoutes: false,\n },\n },\n }\n}\n\nconst NATIVE_BABEL = `module.exports = function (api) {\n api.cache(true)\n return {\n presets: ['babel-preset-expo'],\n }\n}\n`\n\nconst NATIVE_TS_CONFIG = {\n extends: '../../tsconfig.base.json',\n compilerOptions: {\n jsx: 'react-native',\n types: ['react-native', 'react'],\n },\n include: ['**/*.ts', '**/*.tsx'],\n exclude: ['node_modules', 'babel.config.js', 'metro.config.js'],\n}\n\nfunction nativeQueryClient(contractImport: string) {\n return `import Constants from 'expo-constants'\nimport { QueryClient } from '@tanstack/react-query'\nimport { createRouteClient } from '@emeryld/rrroutes-client'\nimport { registry } from '${contractImport}'\n\nconst { apiUrl } = (Constants.expoConfig?.extra ?? {}) as Record<string, string>\n\nexport const queryClient = new QueryClient()\n\nexport const routeClient = createRouteClient({\n baseUrl: apiUrl ?? 'http://localhost:4000',\n queryClient,\n})\n\nexport const healthGet = routeClient.build(registry.byKey['GET /api/health'])\nexport const healthPost = routeClient.build(registry.byKey['POST /api/health'])\n`\n}\n\nfunction nativeSocket(contractImport: string) {\n return `import React from 'react'\nimport Constants from 'expo-constants'\nimport { io, type Socket } from 'socket.io-client'\nimport {\n buildSocketProvider,\n type SocketClientOptions,\n} from '@emeryld/rrroutes-client'\nimport { socketConfig, socketEvents } from '${contractImport}'\n\nconst extras = (Constants.expoConfig?.extra ?? {}) as Record<string, string>\nconst socketUrl = extras.socketUrl ?? 'http://localhost:4000'\nconst socketPath = extras.socketPath ?? '/socket.io'\n\nconst sysEvents: SocketClientOptions<\n typeof socketEvents,\n typeof socketConfig\n>['sys'] = {\n 'sys:connect': async ({ socket }) => {\n console.log('socket connected', socket.id)\n },\n 'sys:disconnect': async ({ reason }) => console.log('disconnected', reason),\n 'sys:reconnect': async ({ attempt, socket }) =>\n console.log('reconnect', attempt, socket?.id),\n 'sys:connect_error': async ({ error }) =>\n console.warn('socket connect error', error),\n 'sys:ping': () => ({\n note: 'client-heartbeat',\n sentAt: new Date().toISOString(),\n }),\n 'sys:pong': async ({ payload }) => console.log('pong', payload),\n 'sys:room_join': async ({ rooms }) => {\n console.log('join rooms', rooms)\n return true\n },\n 'sys:room_leave': async ({ rooms }) => {\n console.log('leave rooms', rooms)\n return true\n },\n}\n\nconst baseOptions: Omit<\n SocketClientOptions<typeof socketEvents, typeof socketConfig>,\n 'socket'\n> = {\n config: socketConfig,\n sys: sysEvents,\n heartbeat: { intervalMs: 15_000, timeoutMs: 7_500 },\n debug: { connection: true },\n}\n\nconst { SocketProvider, useSocketClient, useSocketConnection } =\n buildSocketProvider({\n events: socketEvents,\n options: baseOptions,\n })\n\nfunction getSocket(): Promise<Socket> {\n return Promise.resolve(\n io(socketUrl, {\n path: socketPath,\n transports: ['websocket'],\n }),\n )\n}\n\nexport const roomMeta = { room: 'health' }\n\nexport function AppSocketProvider(props: React.PropsWithChildren) {\n return (\n <SocketProvider\n getSocket={getSocket}\n destroyLeaveMeta={roomMeta}\n fallback={<></>}\n >\n {props.children}\n </SocketProvider>\n )\n}\n\nexport { useSocketClient, useSocketConnection }\n`\n}\n\nfunction nativeAppTsx() {\n return `import React from 'react'\nimport { SafeAreaView, ScrollView, StatusBar, StyleSheet } from 'react-native'\nimport { QueryClientProvider } from '@tanstack/react-query'\nimport { queryClient } from './src/queryClient'\nimport { AppSocketProvider } from './src/socket'\nimport { HealthScreen } from './src/screens/HealthScreen'\n\nexport default function App() {\n return (\n <QueryClientProvider client={queryClient}>\n <AppSocketProvider>\n <StatusBar barStyle=\"dark-content\" />\n <SafeAreaView style={styles.container}>\n <ScrollView contentInsetAdjustmentBehavior=\"automatic\">\n <HealthScreen />\n </ScrollView>\n </SafeAreaView>\n </AppSocketProvider>\n </QueryClientProvider>\n )\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n padding: 16,\n backgroundColor: '#f4f5fb',\n },\n})\n`\n}\n\nfunction nativeHealthScreen(contractImport: string) {\n return `import React from 'react'\nimport {\n Button,\n StyleSheet,\n Text,\n TextInput,\n View,\n} from 'react-native'\nimport { healthGet, healthPost } from '../queryClient'\nimport { roomMeta, useSocketClient, useSocketConnection } from '../socket'\n\nconst now = () => new Date().toLocaleTimeString()\n\nfunction useLogs() {\n const [logs, setLogs] = React.useState<string[]>([])\n return {\n logs,\n push: (msg: string) =>\n setLogs((prev) => [\\`[\\${now()}] \\${msg}\\`, ...prev].slice(0, 60)),\n clear: () => setLogs([]),\n }\n}\n\nexport function HealthScreen() {\n const [echo, setEcho] = React.useState('hello rrroute')\n const httpGet = healthGet.useEndpoint()\n const httpPost = healthPost.useEndpoint()\n const socket = useSocketClient()\n const { logs, push, clear } = useLogs()\n\n useSocketConnection({\n event: 'health:connected',\n rooms: ['health'],\n joinMeta: roomMeta,\n leaveMeta: roomMeta,\n onMessage: (payload) => push(\\`connected \\${payload.socketId}\\`),\n })\n\n useSocketConnection({\n event: 'health:pong',\n rooms: ['health'],\n joinMeta: roomMeta,\n leaveMeta: roomMeta,\n onMessage: (payload) =>\n push(\\`pong at \\${payload.at}\\${payload.echo ? \\` (echo: \\${payload.echo})\\` : ''}\\`),\n })\n\n return (\n <View style={styles.card}>\n <Text style={styles.title}>RRRoutes health sandbox</Text>\n <View style={styles.section}>\n <Text style={styles.heading}>HTTP</Text>\n <Button title=\"GET /health\" onPress={() => httpGet.refetch()} />\n <View style={{ height: 12 }} />\n <TextInput\n style={styles.input}\n value={echo}\n onChangeText={setEcho}\n placeholder=\"echo payload\"\n />\n <Button\n title=\"POST /health\"\n onPress={() =>\n httpPost\n .mutateAsync({ echo })\n .then(() => push('POST /health ok'))\n }\n />\n <Text style={styles.label}>GET data</Text>\n <Text style={styles.code}>\n {JSON.stringify(httpGet.data ?? {}, null, 2)}\n </Text>\n <Text style={styles.label}>POST data</Text>\n <Text style={styles.code}>\n {JSON.stringify(httpPost.data ?? {}, null, 2)}\n </Text>\n </View>\n\n <View style={styles.section}>\n <Text style={styles.heading}>Socket</Text>\n <View style={styles.row}>\n <Button title=\"Connect\" onPress={() => socket.connect()} />\n <Button title=\"Disconnect\" onPress={() => socket.disconnect()} />\n </View>\n <View style={{ height: 8 }} />\n <Button\n title=\"Emit ping\"\n onPress={() => socket.emit('health:ping', { note: 'ping from app' })}\n />\n <View style={{ height: 8 }} />\n <View style={styles.row}>\n <Button\n title=\"Join room\"\n onPress={() => socket.joinRooms(['health'], roomMeta)}\n />\n <Button\n title=\"Leave room\"\n onPress={() => socket.leaveRooms(['health'], roomMeta)}\n />\n </View>\n </View>\n\n <View style={styles.section}>\n <Text style={styles.heading}>Socket logs</Text>\n <Button title=\"Clear logs\" onPress={clear} />\n <Text style={styles.code}>\n {logs.length === 0 ? 'No messages yet' : logs.join('\\\\n')}\n </Text>\n </View>\n </View>\n )\n}\n\nconst styles = StyleSheet.create({\n card: {\n backgroundColor: '#fff',\n borderRadius: 12,\n padding: 16,\n gap: 12,\n shadowColor: '#000',\n shadowOpacity: 0.05,\n shadowRadius: 8,\n },\n title: { fontSize: 20, fontWeight: '700' },\n section: { gap: 8 },\n heading: { fontWeight: '600', fontSize: 16 },\n row: { flexDirection: 'row', gap: 8, justifyContent: 'space-between' },\n input: {\n borderWidth: 1,\n borderColor: '#d0d4de',\n borderRadius: 8,\n padding: 8,\n },\n label: { marginTop: 6, fontWeight: '600' },\n code: {\n backgroundColor: '#0f172a',\n color: '#e2e8f0',\n padding: 8,\n borderRadius: 8,\n fontFamily: 'Courier',\n },\n})\n`\n}\n\nconst NATIVE_ENV = `API_URL=http://localhost:4000\nSOCKET_URL=http://localhost:4000\nSOCKET_PATH=/socket.io\n`\n\n// Scaffold orchestrator -------------------------------------------------------\n\nexport async function scaffoldClient(ctx: GeneratorContext) {\n return ctx.clientKind === 'react-native'\n ? scaffoldNativeClient(ctx)\n : scaffoldWebClient(ctx)\n}\n\nasync function scaffoldWebClient(ctx: GeneratorContext) {\n const baseDir = path.join(ctx.rootDir, 'packages', 'client')\n await ensureDir(path.join(baseDir, 'src', 'lib'))\n await ensureDir(path.join(baseDir, 'src', 'pages'))\n\n const pkgJson = {\n name: ctx.packageNames.client,\n version: '0.1.0',\n private: true,\n type: 'module',\n main: 'dist/index.js',\n scripts: {\n dev: 'vite',\n build: 'vite build',\n preview: 'vite preview',\n typecheck: 'tsc -p tsconfig.json --noEmit',\n },\n dependencies: {\n [ctx.packageNames.contract]: 'workspace:*',\n '@emeryld/rrroutes-client': '^2.5.3',\n '@tanstack/react-query': '^5.90.12',\n react: '^18.3.1',\n 'react-dom': '^18.3.1',\n 'socket.io-client': '^4.8.3',\n zod: '^4.2.1',\n },\n devDependencies: {\n '@types/react': '^18.3.27',\n '@types/react-dom': '^18.3.7',\n '@vitejs/plugin-react': '^4.3.4',\n typescript: '^5.9.3',\n vite: '^6.4.1',\n },\n }\n\n const files: Record<string, string> = {\n 'package.json': `${JSON.stringify(pkgJson, null, 2)}\\n`,\n 'tsconfig.json': `${JSON.stringify(baseTsConfig(), null, 2)}\\n`,\n 'vite.config.ts': viteConfig(),\n 'src/main.tsx': MAIN_TSX,\n 'src/App.tsx': appTsx(),\n 'src/lib/queryClient.ts': queryClient(ctx.packageNames.contract),\n 'src/lib/socket.tsx': socketProvider(ctx.packageNames.contract),\n 'src/pages/HealthPage.tsx': healthPage(ctx.packageNames.contract),\n 'src/styles.css': STYLES,\n 'src/env.d.ts': '/// <reference types=\"vite/client\" />\\n',\n 'index.html': indexHtml(),\n '.env': CLIENT_ENV,\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(baseDir, name)\n const writer = name === '.env' ? writeFileForce : writeFileIfMissing\n const result = await writer(fullPath, contents)\n const rel = path.relative(ctx.rootDir, fullPath)\n if (result === 'created' || result === undefined) log.created(rel)\n else log.skipped(rel)\n }\n}\n\nasync function scaffoldNativeClient(ctx: GeneratorContext) {\n const baseDir = path.join(ctx.rootDir, 'packages', 'client')\n await ensureDir(path.join(baseDir, 'src', 'screens'))\n\n const pkgJson = nativePackageJson(\n ctx.packageNames.client,\n ctx.packageNames.contract,\n )\n\n const files: Record<string, string> = {\n 'package.json': `${JSON.stringify(pkgJson, null, 2)}\\n`,\n 'tsconfig.json': `${JSON.stringify(NATIVE_TS_CONFIG, null, 2)}\\n`,\n 'app.json': `${JSON.stringify(nativeAppJson(ctx.appSlug), null, 2)}\\n`,\n 'babel.config.js': NATIVE_BABEL,\n 'App.tsx': nativeAppTsx(),\n 'src/queryClient.ts': nativeQueryClient(ctx.packageNames.contract),\n 'src/socket.tsx': nativeSocket(ctx.packageNames.contract),\n 'src/screens/HealthScreen.tsx': nativeHealthScreen(\n ctx.packageNames.contract,\n ),\n '.env': NATIVE_ENV,\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(baseDir, name)\n const writer = name === '.env' ? writeFileForce : writeFileIfMissing\n const result = await writer(fullPath, contents)\n const rel = path.relative(ctx.rootDir, fullPath)\n if (result === 'created' || result === undefined) log.created(rel)\n else log.skipped(rel)\n }\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nexport async function ensureDir(dir: string): Promise<void> {\n await fs.mkdir(dir, { recursive: true })\n}\n\nexport async function pathExists(target: string): Promise<boolean> {\n try {\n await fs.access(target)\n return true\n } catch {\n return false\n }\n}\n\nexport async function writeFileIfMissing(\n filePath: string,\n contents: string,\n): Promise<'created' | 'skipped'> {\n const dir = path.dirname(filePath)\n await ensureDir(dir)\n if (await pathExists(filePath)) {\n return 'skipped'\n }\n await fs.writeFile(filePath, contents, 'utf8')\n return 'created'\n}\n\nexport async function writeFileForce(\n filePath: string,\n contents: string,\n): Promise<void> {\n const dir = path.dirname(filePath)\n await ensureDir(dir)\n await fs.writeFile(filePath, contents, 'utf8')\n}\n","export const log = {\n info(msg: string) {\n console.log(msg)\n },\n step(msg: string) {\n console.log(`• ${msg}`)\n },\n created(target: string) {\n console.log(` created ${target}`)\n },\n skipped(target: string) {\n console.log(` skipped ${target} (already exists)`)\n },\n warn(msg: string) {\n console.warn(` warning: ${msg}`)\n },\n error(msg: string) {\n console.error(` error: ${msg}`)\n },\n}\n","import path from 'node:path'\nimport { GeneratorContext } from '../types'\nimport { ensureDir, writeFileIfMissing } from '../utils/fs'\nimport { log } from '../utils/log'\n\nconst CONTRACT_TS = `import { defineSocketEvents, finalize, resource } from '@emeryld/rrroutes-contract'\nimport { z } from 'zod'\n\nconst routes = resource('/api')\n .sub(\n resource('health')\n .get({\n outputSchema: z.object({\n status: z.literal('ok'),\n html: z.string().describe('Tiny HTML heartbeat'),\n }),\n description: 'Basic GET health probe for uptime + docs.',\n })\n .post({\n bodySchema: z.object({\n echo: z.string().optional(),\n }),\n outputSchema: z.object({\n status: z.literal('ok'),\n received: z.string().optional(),\n }),\n description: 'POST health probe that echoes a payload.',\n })\n .done(),\n )\n .done()\n\nexport const registry = finalize(routes)\n\nconst sockets = defineSocketEvents(\n {\n joinMetaMessage: z.object({ room: z.string().optional() }),\n leaveMetaMessage: z.object({ room: z.string().optional() }),\n pingPayload: z.object({\n note: z.string().default('ping'),\n sentAt: z.string(),\n }),\n pongPayload: z.object({\n ok: z.boolean(),\n receivedAt: z.string(),\n echo: z.string().optional(),\n }),\n },\n {\n 'health:connected': {\n message: z.object({\n socketId: z.string(),\n at: z.string(),\n message: z.string(),\n }),\n },\n 'health:ping': {\n message: z.object({\n note: z.string().default('ping'),\n }),\n },\n 'health:pong': {\n message: z.object({\n ok: z.literal(true),\n at: z.string(),\n echo: z.string().optional(),\n }),\n },\n },\n)\n\nexport const socketConfig = sockets.config\nexport const socketEvents = sockets.events\nexport type AppRegistry = typeof registry\n`\n\nexport async function scaffoldContract(ctx: GeneratorContext) {\n const baseDir = path.join(ctx.rootDir, 'packages', 'contract')\n await ensureDir(path.join(baseDir, 'src'))\n\n const pkgJson = {\n name: ctx.packageNames.contract,\n version: '0.1.0',\n private: false,\n type: 'module',\n main: 'dist/index.js',\n types: 'dist/index.d.ts',\n files: ['dist'],\n scripts: {\n build: 'tsc -p tsconfig.json',\n typecheck: 'tsc -p tsconfig.json --noEmit',\n watch: 'tsc -p tsconfig.json --watch --preserveWatchOutput',\n },\n dependencies: {\n '@emeryld/rrroutes-contract': '^2.5.2',\n zod: '^4.2.1',\n },\n devDependencies: {\n typescript: '^5.9.3',\n },\n }\n\n const tsconfig = {\n extends: '../../tsconfig.base.json',\n compilerOptions: {\n outDir: 'dist',\n rootDir: 'src',\n declaration: true,\n sourceMap: true,\n },\n include: ['src/**/*'],\n }\n\n const files: Record<string, string> = {\n 'package.json': `${JSON.stringify(pkgJson, null, 2)}\\n`,\n 'tsconfig.json': `${JSON.stringify(tsconfig, null, 2)}\\n`,\n 'src/index.ts': CONTRACT_TS,\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(baseDir, name)\n const result = await writeFileIfMissing(fullPath, contents)\n if (result === 'created') log.created(path.relative(ctx.rootDir, fullPath))\n else log.skipped(path.relative(ctx.rootDir, fullPath))\n }\n}\n","import path from 'node:path'\nimport { GeneratorContext } from '../types'\nimport { ensureDir, writeFileIfMissing } from '../utils/fs'\nimport { log } from '../utils/log'\n\nfunction formatJson(obj: unknown): string {\n return `${JSON.stringify(obj, null, 2)}\\n`\n}\n\nexport async function scaffoldRoot(ctx: GeneratorContext) {\n await ensureDir(ctx.rootDir)\n\n const paths: Record<string, string[]> = {}\n const addPaths = (pkgName: string, dir: string) => {\n const srcRoot = path.posix.join('packages', dir, 'src')\n paths[pkgName] = [path.posix.join(srcRoot, 'index.ts')]\n paths[`${pkgName}/*`] = [path.posix.join(srcRoot, '*')]\n }\n if (ctx.targets.contract) addPaths(ctx.packageNames.contract, 'contract')\n if (ctx.targets.server) addPaths(ctx.packageNames.server, 'server')\n if (ctx.targets.client) addPaths(ctx.packageNames.client, 'client')\n\n const scripts: Record<string, string> = {\n build: 'npm run build --workspaces',\n typecheck: 'npm run typecheck --workspaces --if-present',\n lint: 'npm run lint --workspaces --if-present',\n }\n if (ctx.targets.server) {\n scripts['dev:server'] = `npm run dev --workspace ${ctx.packageNames.server}`\n }\n if (ctx.targets.client) {\n scripts['dev:client'] = `npm run dev --workspace ${ctx.packageNames.client}`\n }\n if (ctx.targets.contract) {\n scripts['dev:contract'] = `npm run watch --workspace ${ctx.packageNames.contract}`\n }\n const hasFullStack =\n ctx.targets.server && ctx.targets.client && ctx.targets.contract\n if (hasFullStack) {\n scripts[\n 'dev:all'\n ] = `concurrently \"npm run dev:contract\" \"npm run dev:server\" \"npm run dev:client\"`\n }\n\n const highlights = ['- Shared contract package (RRRoutes registry + sockets)']\n if (ctx.targets.server) {\n highlights.unshift(\n '- Backend (Express + Socket.IO + RRRoutes server bindings)',\n )\n }\n if (ctx.targets.client) {\n highlights.splice(\n ctx.targets.server ? 1 : 0,\n 0,\n '- Frontend client (React or React Native) with React Query + sockets',\n )\n }\n\n const quickstart: string[] = ['1) Install deps: `npm install` (workspaces)']\n if (ctx.targets.server) {\n quickstart.push(\n `${quickstart.length + 1}) Backend env: edit \\`packages/server/.env\\``,\n )\n }\n if (ctx.targets.contract) {\n quickstart.push(\n `${quickstart.length + 1}) Optional: keep shared contract rebuilding via \\`npm run dev:contract\\``,\n )\n }\n if (ctx.targets.client) {\n quickstart.push(\n `${quickstart.length + 1}) Client env: edit \\`packages/client/.env\\``,\n )\n }\n if (ctx.targets.server || ctx.targets.client) {\n quickstart.push(\n `${quickstart.length + 1}) Run dev servers:${\n ctx.targets.server ? `\\n - API: \\`npm run dev:server\\`` : ''\n }${ctx.targets.client ? `\\n - Client: \\`npm run dev:client\\`` : ''}${\n hasFullStack ? `\\n - All: \\`npm run dev:all\\`` : ''\n }`,\n )\n }\n\n const devDependencies: Record<string, string> = {\n typescript: '^5.9.3',\n }\n if (hasFullStack) {\n devDependencies['concurrently'] = '^8.2.0'\n }\n\n const pkgJson = {\n name: `${ctx.appSlug}-stack`,\n private: true,\n workspaces: ['packages/*'],\n scripts,\n devDependencies,\n }\n\n const files: Record<string, string> = {\n 'package.json': formatJson(pkgJson),\n 'pnpm-workspace.yaml': \"packages:\\n - 'packages/*'\\n\",\n 'tsconfig.base.json': formatJson({\n $schema: 'https://json.schemastore.org/tsconfig',\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n moduleResolution: 'Bundler',\n jsx: 'react-jsx',\n strict: true,\n skipLibCheck: true,\n resolveJsonModule: true,\n forceConsistentCasingInFileNames: true,\n sourceMap: true,\n baseUrl: '.',\n paths,\n },\n }),\n '.gitignore': [\n 'node_modules',\n 'dist',\n '.turbo',\n '.expo',\n '.DS_Store',\n '.env',\n '.env.local',\n 'npm-debug.log*',\n 'yarn-error.log',\n ].join('\\n'),\n README: [\n `# ${ctx.projectName} (RRRoutes starter)`,\n '',\n 'Generated via `create-rrroutes`. Includes:',\n ...highlights,\n '',\n '## Quickstart',\n ...quickstart,\n '',\n ctx.targets.server\n ? 'Dockerfile for the API lives in `packages/server/Dockerfile`.'\n : '',\n '',\n ]\n .filter(Boolean)\n .join('\\n'),\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(ctx.rootDir, name)\n const result = await writeFileIfMissing(fullPath, contents)\n if (result === 'created') log.created(path.relative(ctx.rootDir, fullPath))\n else log.skipped(path.relative(ctx.rootDir, fullPath))\n }\n}\n","import path from 'node:path'\nimport { GeneratorContext } from '../types'\nimport { ensureDir, writeFileForce, writeFileIfMissing } from '../utils/fs'\nimport { log } from '../utils/log'\n\nconst defaultDatabaseUrl =\n 'postgresql://postgres:postgres@localhost:5432/rrroutes'\n\nfunction serverIndexTs() {\n return `import 'dotenv/config'\nimport http from 'node:http'\nimport { app } from './http.js'\nimport { createSockets } from './socket.js'\nimport { prisma } from './prisma.js'\n\nasync function main() {\n const PORT = Number.parseInt(process.env.PORT ?? '4000', 10)\n const CORS_ORIGIN = process.env.CORS_ORIGIN ?? 'http://localhost:5173'\n const SOCKET_PATH = process.env.SOCKET_PATH ?? '/socket.io'\n\n await prisma.$connect()\n\n const httpServer = http.createServer(app)\n const sockets = createSockets(httpServer, {\n corsOrigin: CORS_ORIGIN,\n socketPath: SOCKET_PATH,\n })\n\n httpServer.listen(PORT, () => {\n console.log(\n \\`API listening on http://localhost:\\${PORT} (CORS origin: \\${CORS_ORIGIN})\\`,\n )\n })\n\n const shutdown = async () => {\n await sockets.destroy()\n await prisma.$disconnect()\n }\n process.on('SIGTERM', shutdown)\n process.on('SIGINT', shutdown)\n}\n\nmain().catch(async (err) => {\n console.error(err)\n await prisma.$disconnect().catch(() => {})\n process.exit(1)\n})\n`\n}\n\nfunction httpTs(contractImport: string) {\n return `import express from 'express'\nimport cors from 'cors'\nimport { createRRRoute } from '@emeryld/rrroutes-server'\nimport { registry } from '${contractImport}'\nimport { controllers, type RequestCtx } from './controllers.js'\nimport { prisma } from './prisma.js'\n\nconst CORS_ORIGIN = process.env.CORS_ORIGIN ?? 'http://localhost:5173'\n\nexport const app = express()\napp.use(cors({ origin: CORS_ORIGIN, credentials: true }))\napp.use(express.json())\n\napp.get('/', (_req, res) => {\n res.send('<h1>RRRoutes starter API</h1>')\n})\n\nconst routes = createRRRoute<RequestCtx>(app, {\n buildCtx: async () => ({\n requestId: Math.random().toString(36).slice(2),\n prisma,\n routesLogger: console,\n }),\n debug:\n process.env.NODE_ENV === 'development'\n ? { request: true, handler: true }\n : undefined,\n})\n\nroutes.registerControllers(registry, controllers)\nroutes.warnMissingControllers(registry, console)\nexport { routes }\n`\n}\n\nfunction controllersTs(contractImport: string) {\n return `import { defineControllers } from '@emeryld/rrroutes-server'\nimport { registry } from '${contractImport}'\n\ntype PrismaCtx = typeof import('./prisma.js').prisma\n\nexport type RequestCtx = {\n prisma: PrismaCtx\n requestId: string\n}\nexport const controllers = defineControllers<typeof registry, RequestCtx>()({\n 'GET /api/health': {\n handler: async ({ ctx }) => {\n await ctx.prisma.healthCheck.create({\n data: { note: 'GET health' },\n })\n return {\n out: {\n status: 'ok',\n html: '<!doctype html><html><body><h1>healthy</h1></body></html>',\n },\n }\n },\n },\n 'POST /api/health': {\n handler: async ({ ctx, body }) => {\n await ctx.prisma.healthCheck.create({\n data: { note: body?.echo ?? 'POST health' },\n })\n return {\n out: {\n status: 'ok',\n received: body?.echo ?? 'pong',\n },\n }\n },\n },\n})\n`\n}\n\nfunction socketTs(contractImport: string) {\n return `import { Server as SocketIOServer } from 'socket.io'\nimport type { Server } from 'node:http'\nimport {\n createSocketConnections,\n type HandlerCtx,\n type SysServerEventMap,\n} from '@emeryld/rrroutes-server'\nimport type { Payload } from '@emeryld/rrroutes-contract'\nimport { socketConfig, socketEvents } from '${contractImport}'\n\nexport function createSockets(\n httpServer: Server,\n opts: { corsOrigin: string; socketPath: string },\n) {\n const io = new SocketIOServer(httpServer, {\n cors: { origin: opts.corsOrigin, credentials: true },\n path: opts.socketPath,\n })\n\n const sysHandlers: SysServerEventMap<\n typeof socketConfig,\n typeof socketEvents\n > = {\n 'sys:connect': async ({ socket, helper, complete }) => {\n helper.emit('health:connected', {\n socketId: socket.id,\n at: new Date().toISOString(),\n message: 'connected',\n })\n complete()\n },\n 'sys:disconnect': async ({ cleanup }) => cleanup(),\n 'sys:ping': async ({ ping }) => ({\n ok: true,\n receivedAt: new Date().toISOString(),\n echo: ping.note,\n }),\n 'sys:room_join': async ({ rooms, join }) => {\n await Promise.all(rooms.map((room) => join(room)))\n },\n 'sys:room_leave': async ({ rooms, leave }) => {\n await Promise.all(rooms.map((room) => leave(room)))\n },\n }\n\n const sockets = createSocketConnections(io, socketEvents, {\n config: socketConfig,\n heartbeat: { enabled: true },\n sys: sysHandlers,\n })\n\n sockets.on(\n 'health:ping',\n async (\n payload: Payload<typeof socketEvents, 'health:ping'>,\n ctx: HandlerCtx,\n ) => {\n sockets.emit(\n 'health:pong',\n { ok: true, at: new Date().toISOString(), echo: payload.note },\n ctx.socketId,\n )\n },\n )\n\n return sockets\n}\n`\n}\n\nfunction prismaTs() {\n return `import { PrismaClient } from '@prisma/client'\n\nexport const prisma = new PrismaClient({\n log: ['warn', 'error'],\n})\n`\n}\n\nfunction prismaSchema() {\n return `generator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel HealthCheck {\n id String @id @default(uuid())\n note String?\n createdAt DateTime @default(now())\n}\n`\n}\n\nfunction serverEnv() {\n return [\n 'PORT=4000',\n 'NODE_ENV=development',\n 'CORS_ORIGIN=http://localhost:5173',\n 'SOCKET_PATH=/socket.io',\n `DATABASE_URL=${defaultDatabaseUrl}`,\n ].join('\\n')\n}\n\nexport const nodemonExecCommand = `node --no-warnings --loader ts-node/esm ./src/index.ts`\n\nfunction nodemonJson() {\n return `${JSON.stringify(\n {\n watch: ['src'],\n ext: 'ts',\n ignore: ['src/**/*.test.ts'],\n exec: nodemonExecCommand,\n },\n null,\n 2,\n )}\\n`\n}\n\nfunction dockerfile(serverName: string, contractName: string) {\n return `FROM node:20-alpine\nWORKDIR /app\n\n# Install workspace deps (hoists to /app/node_modules)\nCOPY package.json pnpm-workspace.yaml tsconfig.base.json ./\nCOPY packages/contract/package.json packages/contract/package.json\nCOPY packages/server/package.json packages/server/package.json\nCOPY packages/server/prisma/schema.prisma packages/server/prisma/schema.prisma\nRUN npm install\n\n# Copy source and build server + contract\nCOPY packages ./packages\n\n# Generate Prisma client\nRUN npx prisma generate --schema packages/server/prisma/schema.prisma\n\nRUN npm run build --workspace ${contractName} && npm run build --workspace ${serverName}\n\nEXPOSE 4000\nCMD [\"node\", \"packages/server/dist/index.js\"]\n`\n}\n\nexport async function scaffoldServer(ctx: GeneratorContext) {\n const baseDir = path.join(ctx.rootDir, 'packages', 'server')\n await ensureDir(path.join(baseDir, 'src'))\n await ensureDir(path.join(baseDir, 'prisma'))\n\n const pkgJson = {\n name: ctx.packageNames.server,\n version: '0.1.0',\n private: false,\n type: 'module',\n main: 'dist/index.js',\n types: 'dist/index.d.ts',\n files: ['dist'],\n scripts: {\n dev: 'nodemon --config nodemon.json',\n build: 'tsc -p tsconfig.json',\n typecheck: 'tsc -p tsconfig.json --noEmit',\n start: 'node dist/index.js',\n 'prisma:generate': 'prisma generate --schema prisma/schema.prisma',\n 'prisma:migrate':\n 'prisma migrate dev --schema prisma/schema.prisma --name init',\n 'db:start':\n 'docker run --name rrroutes-db -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=rrroutes -p 5432:5432 -d postgres:15 || docker start rrroutes-db',\n 'db:stop': 'docker stop rrroutes-db || true',\n },\n dependencies: {\n [ctx.packageNames.contract]: 'workspace:*',\n '@emeryld/rrroutes-server': '^2.4.1',\n '@prisma/client': '^7.0.0',\n 'socket.io': '^4.8.1',\n express: '^5.1.0',\n cors: '^2.8.5',\n dotenv: '^16.4.5',\n zod: '^4.2.1',\n },\n devDependencies: {\n '@types/express': '^5.0.6',\n '@types/cors': '^2.8.5',\n '@types/node': '^24.10.2',\n prisma: '^7.0.0',\n typescript: '^5.9.3',\n 'ts-node': '^10.9.2',\n nodemon: '^3.1.9',\n },\n }\n\n const tsconfig = {\n extends: '../../tsconfig.base.json',\n compilerOptions: {\n outDir: 'dist',\n declaration: true,\n sourceMap: true,\n\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n target: 'ES2022',\n strict: true,\n skipLibCheck: true,\n },\n include: ['src/**/*'],\n }\n\n const files: Record<string, string> = {\n 'package.json': `${JSON.stringify(pkgJson, null, 2)}\\n`,\n 'tsconfig.json': `${JSON.stringify(tsconfig, null, 2)}\\n`,\n 'src/index.ts': serverIndexTs(),\n 'src/http.ts': httpTs(ctx.packageNames.contract),\n 'src/controllers.ts': controllersTs(ctx.packageNames.contract),\n 'src/socket.ts': socketTs(ctx.packageNames.contract),\n 'src/prisma.ts': prismaTs(),\n 'prisma/schema.prisma': prismaSchema(),\n '.env': `${serverEnv()}\\n`,\n 'nodemon.json': nodemonJson(),\n Dockerfile: dockerfile(ctx.packageNames.server, ctx.packageNames.contract),\n }\n\n for (const [name, contents] of Object.entries(files)) {\n const fullPath = path.join(baseDir, name)\n const writer =\n name === '.env'\n ? writeFileForce // allow updating env defaults\n : writeFileIfMissing\n const result = await writer(fullPath, contents)\n const rel = path.relative(ctx.rootDir, fullPath)\n if (result === 'created' || result === undefined) log.created(rel)\n else log.skipped(rel)\n }\n}\n","import { createInterface } from 'node:readline/promises'\nimport { stdin as input, stdout as output } from 'node:process'\n\ntype Option<T> = {\n label: string\n value: T\n}\n\nexport function createPrompt() {\n const rl = createInterface({ input, output })\n\n return {\n async text(message: string, fallback?: string) {\n const suffix = fallback ? ` (${fallback})` : ''\n const answer = (await rl.question(`${message}${suffix}: `)).trim()\n return answer.length > 0 ? answer : fallback\n },\n async confirm(message: string, fallback = true) {\n const suffix = fallback ? ' (Y/n)' : ' (y/N)'\n const answer = (await rl.question(`${message}${suffix}: `)).trim()\n if (!answer) return fallback\n return ['y', 'yes'].includes(answer.toLowerCase())\n },\n async select<T>(\n message: string,\n options: Option<T>[],\n fallbackIndex = 0,\n ) {\n console.log(message)\n options.forEach((opt, idx) =>\n console.log(` [${idx + 1}] ${opt.label}`),\n )\n const answer = (await rl.question(`Choose 1-${options.length}: `)).trim()\n const idx = Number.parseInt(answer, 10)\n const normalized =\n Number.isNaN(idx) || idx < 1 || idx > options.length\n ? fallbackIndex\n : idx - 1\n return options[normalized]!.value\n },\n close() {\n rl.close()\n },\n }\n}\n","import { spawn } from 'node:child_process'\n\nexport async function runCommand(\n cmd: string,\n args: string[],\n cwd: string,\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(cmd, args, {\n cwd,\n stdio: 'inherit',\n shell: process.platform === 'win32',\n })\n child.on('exit', (code) => {\n if (code === 0) resolve()\n else reject(new Error(`${cmd} ${args.join(' ')} exited with ${code}`))\n })\n child.on('error', (err) => reject(err))\n })\n}\n","export function slugify(input: string, fallback = 'rrroutes-app'): string {\n const slug = input\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n return slug.length > 0 ? slug : fallback\n}\n"],"mappings":"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","names":["import_node_path","import_node_path","fs","path","path","import_node_path","path","import_node_path","path","import_node_path","path","import_promises","input","output","idx","input","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emeryld/create-rrroutes",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {