rari 0.7.6 → 0.7.7

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/cli.mjs CHANGED
@@ -143,10 +143,112 @@ function getPlatformName() {
143
143
  function getDeploymentConfig() {
144
144
  return {
145
145
  port: process.env.PORT || process.env.RSC_PORT || "3000",
146
- mode: process.env.NODE_ENV === "production" ? "production" : "development",
146
+ mode: process.env.NODE_ENV || "production",
147
147
  host: isPlatformEnvironment() ? "0.0.0.0" : "127.0.0.1"
148
148
  };
149
149
  }
150
+ async function runViteBuild() {
151
+ const { existsSync: existsSync$1, rmSync } = await import("node:fs");
152
+ const { resolve: resolve$1 } = await import("node:path");
153
+ const { spawn: spawn$1 } = await import("node:child_process");
154
+ const distPath = resolve$1(process.cwd(), "dist");
155
+ if (existsSync$1(distPath)) {
156
+ logInfo("Cleaning dist folder...");
157
+ rmSync(distPath, {
158
+ recursive: true,
159
+ force: true
160
+ });
161
+ }
162
+ logInfo("Type checking...");
163
+ const typecheckProcess = spawn$1("npx", ["tsgo"], {
164
+ stdio: "inherit",
165
+ cwd: process.cwd(),
166
+ shell: true
167
+ });
168
+ await new Promise((resolve$2, reject) => {
169
+ typecheckProcess.on("exit", (code) => {
170
+ if (code === 0) {
171
+ logSuccess("Type check passed");
172
+ resolve$2();
173
+ } else {
174
+ logError(`Type check failed with code ${code}`);
175
+ reject(/* @__PURE__ */ new Error(`Type check failed with code ${code}`));
176
+ }
177
+ });
178
+ typecheckProcess.on("error", reject);
179
+ });
180
+ logInfo("Building for production...");
181
+ const buildProcess = spawn$1("npx", ["vite", "build"], {
182
+ stdio: "inherit",
183
+ cwd: process.cwd(),
184
+ shell: true
185
+ });
186
+ await new Promise((resolve$2, reject) => {
187
+ buildProcess.on("exit", (code) => {
188
+ if (code === 0) {
189
+ logSuccess("Build complete");
190
+ resolve$2();
191
+ } else {
192
+ logError(`Build failed with code ${code}`);
193
+ reject(/* @__PURE__ */ new Error(`Build failed with code ${code}`));
194
+ }
195
+ });
196
+ buildProcess.on("error", reject);
197
+ });
198
+ }
199
+ async function runViteDev() {
200
+ const { existsSync: existsSync$1 } = await import("node:fs");
201
+ const { resolve: resolve$1 } = await import("node:path");
202
+ const { spawn: spawn$1 } = await import("node:child_process");
203
+ if (!existsSync$1(resolve$1(process.cwd(), "dist"))) {
204
+ logInfo("First run detected - building project...");
205
+ const buildProcess = spawn$1("npx", [
206
+ "vite",
207
+ "build",
208
+ "--mode",
209
+ "development"
210
+ ], {
211
+ stdio: "inherit",
212
+ cwd: process.cwd(),
213
+ shell: true
214
+ });
215
+ await new Promise((resolve$2, reject) => {
216
+ buildProcess.on("exit", (code) => {
217
+ if (code === 0) {
218
+ logSuccess("Initial build complete");
219
+ resolve$2();
220
+ } else {
221
+ logError(`Build failed with code ${code}`);
222
+ reject(/* @__PURE__ */ new Error(`Build failed with code ${code}`));
223
+ }
224
+ });
225
+ buildProcess.on("error", reject);
226
+ });
227
+ }
228
+ logInfo("Starting Vite dev server...");
229
+ const viteProcess = spawn$1("npx", ["vite"], {
230
+ stdio: "inherit",
231
+ cwd: process.cwd(),
232
+ shell: true
233
+ });
234
+ const shutdown = () => {
235
+ logInfo("Shutting down dev server...");
236
+ viteProcess.kill("SIGTERM");
237
+ };
238
+ process.on("SIGINT", shutdown);
239
+ process.on("SIGTERM", shutdown);
240
+ viteProcess.on("error", (error) => {
241
+ logError(`Failed to start Vite: ${error.message}`);
242
+ process.exit(1);
243
+ });
244
+ viteProcess.on("exit", (code) => {
245
+ if (code !== 0 && code !== null) {
246
+ logError(`Vite exited with code ${code}`);
247
+ process.exit(code);
248
+ }
249
+ });
250
+ return new Promise(() => {});
251
+ }
150
252
  async function startRustServer() {
151
253
  let binaryPath;
152
254
  try {
@@ -206,7 +308,7 @@ async function deployToRailway() {
206
308
  logError(`Already running in ${getPlatformName()} environment. Use "rari start" instead.`);
207
309
  process.exit(1);
208
310
  }
209
- const { createRailwayDeployment } = await import("./railway-Dqty_DxF.mjs");
311
+ const { createRailwayDeployment } = await import("./railway-D_JxHvQD.mjs");
210
312
  await createRailwayDeployment();
211
313
  }
212
314
  async function deployToRender() {
@@ -227,23 +329,34 @@ async function main() {
227
329
  console.warn(`${colors.bold("rari CLI")}
228
330
 
229
331
  ${colors.bold("Usage:")}
230
- ${colors.cyan("rari start")} Start the rari server
231
- ${colors.cyan("rari deploy railway")} Setup Railway deployment
232
- ${colors.cyan("rari deploy render")} Setup Render deployment
233
- ${colors.cyan("rari help")} Show this help message
332
+ ${colors.cyan("rari dev")} Start the development server with Vite
333
+ ${colors.cyan("rari build")} Build for production
334
+ ${colors.cyan("rari start")} Start the rari server (defaults to production)
335
+ ${colors.cyan("rari deploy railway")} Setup Railway deployment
336
+ ${colors.cyan("rari deploy render")} Setup Render deployment
337
+ ${colors.cyan("rari help")} Show this help message
234
338
 
235
339
  ${colors.bold("Environment Variables:")}
236
- ${colors.yellow("PORT")} Server port (default: 3000)
237
- ${colors.yellow("RSC_PORT")} Alternative server port
238
- ${colors.yellow("NODE_ENV")} Environment (development/production)
239
- ${colors.yellow("RUST_LOG")} Rust logging level (default: info)
340
+ ${colors.yellow("PORT")} Server port (default: 3000)
341
+ ${colors.yellow("RSC_PORT")} Alternative server port
342
+ ${colors.yellow("NODE_ENV")} Environment (default: production for start, development for dev)
343
+ ${colors.yellow("RUST_LOG")} Rust logging level (default: info)
240
344
 
241
345
  ${colors.bold("Examples:")}
242
- ${colors.gray("# Start development server on port 3000")}
346
+ ${colors.gray("# Start development server with Vite")}
347
+ ${colors.cyan("rari dev")}
348
+
349
+ ${colors.gray("# Build for production")}
350
+ ${colors.cyan("rari build")}
351
+
352
+ ${colors.gray("# Start production server (default)")}
243
353
  ${colors.cyan("rari start")}
244
354
 
355
+ ${colors.gray("# Start in development mode")}
356
+ ${colors.cyan("NODE_ENV=development rari start")}
357
+
245
358
  ${colors.gray("# Start production server on port 8080")}
246
- ${colors.cyan("PORT=8080 NODE_ENV=production rari start")}
359
+ ${colors.cyan("PORT=8080 rari start")}
247
360
 
248
361
  ${colors.gray("# Setup Railway deployment")}
249
362
  ${colors.cyan("rari deploy railway")}
@@ -269,12 +382,21 @@ ${colors.bold("Binary Resolution:")}
269
382
  3. Install from source with Cargo
270
383
 
271
384
  ${colors.bold("Notes:")}
385
+ - 'rari start' defaults to production mode unless NODE_ENV is set
386
+ - 'rari dev' runs in development mode with Vite hot reload
387
+ - 'rari build' cleans, type checks, and builds for production
272
388
  - Platform binary is automatically detected and used
273
389
  - Platform deployment is automatically detected and configured
274
390
  - Use Ctrl+C to stop the server gracefully
275
391
 
276
392
  `);
277
393
  break;
394
+ case "dev":
395
+ await runViteDev();
396
+ break;
397
+ case "build":
398
+ await runViteBuild();
399
+ break;
278
400
  case "start":
279
401
  await startRustServer();
280
402
  break;
@@ -48,29 +48,24 @@ async function createRailwayDeployment() {
48
48
  logError(`Failed to update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
49
49
  process.exit(1);
50
50
  }
51
- const railwayConfig = {
52
- $schema: "https://railway.app/railway.schema.json",
53
- build: { builder: "RAILPACK" },
54
- deploy: {
55
- startCommand: "npm start",
56
- healthcheckPath: "/",
57
- healthcheckTimeout: 300,
58
- restartPolicyType: "ALWAYS"
59
- },
60
- environments: { production: { variables: {
61
- NODE_ENV: "production",
62
- RUST_LOG: "info",
63
- RAILPACK_DEPLOY_APT_PACKAGES: "libfontconfig1"
64
- } } }
65
- };
66
- const railwayJsonPath = join(cwd, "railway.json");
67
- if (existsSync(railwayJsonPath)) {
68
- logWarning("railway.json already exists, backing up to railway.json.backup");
69
- const existingConfig = readFileSync(railwayJsonPath, "utf-8");
70
- writeFileSync(join(cwd, "railway.json.backup"), existingConfig);
51
+ const railwayConfig = `[build]
52
+ builder = "RAILPACK"
53
+
54
+ [deploy]
55
+ startCommand = "npm start"
56
+ healthcheckPath = "/"
57
+ healthcheckTimeout = 300
58
+ restartPolicyType = "ON_FAILURE"
59
+ restartPolicyMaxRetries = 3
60
+ `;
61
+ const railwayTomlPath = join(cwd, "railway.toml");
62
+ if (existsSync(railwayTomlPath)) {
63
+ logWarning("railway.toml already exists, backing up to railway.toml.backup");
64
+ const existingConfig = readFileSync(railwayTomlPath, "utf-8");
65
+ writeFileSync(join(cwd, "railway.toml.backup"), existingConfig);
71
66
  }
72
- writeFileSync(railwayJsonPath, `${JSON.stringify(railwayConfig, null, 2)}\n`);
73
- logSuccess("Created railway.json configuration");
67
+ writeFileSync(railwayTomlPath, railwayConfig);
68
+ logSuccess("Created railway.toml configuration");
74
69
  const gitignorePath = join(cwd, ".gitignore");
75
70
  const railwayGitignoreEntries = [
76
71
  "",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rari",
3
3
  "type": "module",
4
- "version": "0.7.6",
4
+ "version": "0.7.7",
5
5
  "description": "Runtime Accelerated Rendering Infrastructure (rari)",
6
6
  "author": "Ryan Skinner",
7
7
  "license": "MIT",
@@ -93,16 +93,16 @@
93
93
  "picocolors": "^1.1.1"
94
94
  },
95
95
  "optionalDependencies": {
96
- "rari-darwin-arm64": "0.7.6",
97
- "rari-darwin-x64": "0.7.6",
98
- "rari-linux-arm64": "0.7.6",
99
- "rari-linux-x64": "0.7.6",
100
- "rari-win32-x64": "0.7.6"
96
+ "rari-darwin-arm64": "0.7.7",
97
+ "rari-darwin-x64": "0.7.7",
98
+ "rari-linux-arm64": "0.7.7",
99
+ "rari-linux-x64": "0.7.7",
100
+ "rari-win32-x64": "0.7.7"
101
101
  },
102
102
  "devDependencies": {
103
- "@types/node": "^25.0.9",
103
+ "@types/node": "^25.0.10",
104
104
  "@types/react": "^19.2.9",
105
- "@typescript/native-preview": "^7.0.0-dev.20260120.1",
105
+ "@typescript/native-preview": "^7.0.0-dev.20260123.3",
106
106
  "chokidar": "^5.0.0",
107
107
  "oxlint": "^1.41.0",
108
108
  "rolldown-vite": "^7.3.1",
package/src/cli.ts CHANGED
@@ -81,12 +81,128 @@ function getPlatformName(): string {
81
81
 
82
82
  function getDeploymentConfig() {
83
83
  const port = process.env.PORT || process.env.RSC_PORT || '3000'
84
- const mode = process.env.NODE_ENV === 'production' ? 'production' : 'development'
84
+ const mode = process.env.NODE_ENV || 'production'
85
85
  const host = isPlatformEnvironment() ? '0.0.0.0' : '127.0.0.1'
86
86
 
87
87
  return { port, mode, host }
88
88
  }
89
89
 
90
+ async function runViteBuild() {
91
+ const { existsSync, rmSync } = await import('node:fs')
92
+ const { resolve } = await import('node:path')
93
+ const { spawn } = await import('node:child_process')
94
+
95
+ const distPath = resolve(process.cwd(), 'dist')
96
+
97
+ if (existsSync(distPath)) {
98
+ logInfo('Cleaning dist folder...')
99
+ rmSync(distPath, { recursive: true, force: true })
100
+ }
101
+
102
+ logInfo('Type checking...')
103
+ const typecheckProcess = spawn('npx', ['tsgo'], {
104
+ stdio: 'inherit',
105
+ cwd: process.cwd(),
106
+ shell: true,
107
+ })
108
+
109
+ await new Promise<void>((resolve, reject) => {
110
+ typecheckProcess.on('exit', (code) => {
111
+ if (code === 0) {
112
+ logSuccess('Type check passed')
113
+ resolve()
114
+ }
115
+ else {
116
+ logError(`Type check failed with code ${code}`)
117
+ reject(new Error(`Type check failed with code ${code}`))
118
+ }
119
+ })
120
+ typecheckProcess.on('error', reject)
121
+ })
122
+
123
+ logInfo('Building for production...')
124
+ const buildProcess = spawn('npx', ['vite', 'build'], {
125
+ stdio: 'inherit',
126
+ cwd: process.cwd(),
127
+ shell: true,
128
+ })
129
+
130
+ await new Promise<void>((resolve, reject) => {
131
+ buildProcess.on('exit', (code) => {
132
+ if (code === 0) {
133
+ logSuccess('Build complete')
134
+ resolve()
135
+ }
136
+ else {
137
+ logError(`Build failed with code ${code}`)
138
+ reject(new Error(`Build failed with code ${code}`))
139
+ }
140
+ })
141
+ buildProcess.on('error', reject)
142
+ })
143
+ }
144
+
145
+ async function runViteDev() {
146
+ const { existsSync } = await import('node:fs')
147
+ const { resolve } = await import('node:path')
148
+ const { spawn } = await import('node:child_process')
149
+
150
+ const distPath = resolve(process.cwd(), 'dist')
151
+
152
+ if (!existsSync(distPath)) {
153
+ logInfo('First run detected - building project...')
154
+
155
+ const buildProcess = spawn('npx', ['vite', 'build', '--mode', 'development'], {
156
+ stdio: 'inherit',
157
+ cwd: process.cwd(),
158
+ shell: true,
159
+ })
160
+
161
+ await new Promise<void>((resolve, reject) => {
162
+ buildProcess.on('exit', (code) => {
163
+ if (code === 0) {
164
+ logSuccess('Initial build complete')
165
+ resolve()
166
+ }
167
+ else {
168
+ logError(`Build failed with code ${code}`)
169
+ reject(new Error(`Build failed with code ${code}`))
170
+ }
171
+ })
172
+ buildProcess.on('error', reject)
173
+ })
174
+ }
175
+
176
+ logInfo('Starting Vite dev server...')
177
+ const viteProcess = spawn('npx', ['vite'], {
178
+ stdio: 'inherit',
179
+ cwd: process.cwd(),
180
+ shell: true,
181
+ })
182
+
183
+ const shutdown = () => {
184
+ logInfo('Shutting down dev server...')
185
+ viteProcess.kill('SIGTERM')
186
+ }
187
+
188
+ process.on('SIGINT', shutdown)
189
+ process.on('SIGTERM', shutdown)
190
+
191
+ viteProcess.on('error', (error: Error) => {
192
+ logError(`Failed to start Vite: ${error.message}`)
193
+ process.exit(1)
194
+ })
195
+
196
+ viteProcess.on('exit', (code: number) => {
197
+ if (code !== 0 && code !== null) {
198
+ logError(`Vite exited with code ${code}`)
199
+ process.exit(code)
200
+ }
201
+ })
202
+
203
+ return new Promise(() => { })
204
+ }
205
+
90
206
  async function startRustServer(): Promise<void> {
91
207
  let binaryPath: string
92
208
 
@@ -184,23 +300,34 @@ async function main() {
184
300
  console.warn(`${colors.bold('rari CLI')}
185
301
 
186
302
  ${colors.bold('Usage:')}
187
- ${colors.cyan('rari start')} Start the rari server
188
- ${colors.cyan('rari deploy railway')} Setup Railway deployment
189
- ${colors.cyan('rari deploy render')} Setup Render deployment
190
- ${colors.cyan('rari help')} Show this help message
303
+ ${colors.cyan('rari dev')} Start the development server with Vite
304
+ ${colors.cyan('rari build')} Build for production
305
+ ${colors.cyan('rari start')} Start the rari server (defaults to production)
306
+ ${colors.cyan('rari deploy railway')} Setup Railway deployment
307
+ ${colors.cyan('rari deploy render')} Setup Render deployment
308
+ ${colors.cyan('rari help')} Show this help message
191
309
 
192
310
  ${colors.bold('Environment Variables:')}
193
- ${colors.yellow('PORT')} Server port (default: 3000)
194
- ${colors.yellow('RSC_PORT')} Alternative server port
195
- ${colors.yellow('NODE_ENV')} Environment (development/production)
196
- ${colors.yellow('RUST_LOG')} Rust logging level (default: info)
311
+ ${colors.yellow('PORT')} Server port (default: 3000)
312
+ ${colors.yellow('RSC_PORT')} Alternative server port
313
+ ${colors.yellow('NODE_ENV')} Environment (default: production for start, development for dev)
314
+ ${colors.yellow('RUST_LOG')} Rust logging level (default: info)
197
315
 
198
316
  ${colors.bold('Examples:')}
199
- ${colors.gray('# Start development server on port 3000')}
317
+ ${colors.gray('# Start development server with Vite')}
318
+ ${colors.cyan('rari dev')}
319
+
320
+ ${colors.gray('# Build for production')}
321
+ ${colors.cyan('rari build')}
322
+
323
+ ${colors.gray('# Start production server (default)')}
200
324
  ${colors.cyan('rari start')}
201
325
 
326
+ ${colors.gray('# Start in development mode')}
327
+ ${colors.cyan('NODE_ENV=development rari start')}
328
+
202
329
  ${colors.gray('# Start production server on port 8080')}
203
- ${colors.cyan('PORT=8080 NODE_ENV=production rari start')}
330
+ ${colors.cyan('PORT=8080 rari start')}
204
331
 
205
332
  ${colors.gray('# Setup Railway deployment')}
206
333
  ${colors.cyan('rari deploy railway')}
@@ -226,6 +353,9 @@ ${colors.bold('Binary Resolution:')}
226
353
  3. Install from source with Cargo
227
354
 
228
355
  ${colors.bold('Notes:')}
356
+ - 'rari start' defaults to production mode unless NODE_ENV is set
357
+ - 'rari dev' runs in development mode with Vite hot reload
358
+ - 'rari build' cleans, type checks, and builds for production
229
359
  - Platform binary is automatically detected and used
230
360
  - Platform deployment is automatically detected and configured
231
361
  - Use Ctrl+C to stop the server gracefully
@@ -233,6 +363,14 @@ ${colors.bold('Notes:')}
233
363
  `)
234
364
  break
235
365
 
366
+ case 'dev':
367
+ await runViteDev()
368
+ break
369
+
370
+ case 'build':
371
+ await runViteBuild()
372
+ break
373
+
236
374
  case 'start':
237
375
  await startRustServer()
238
376
  break
@@ -63,37 +63,26 @@ export async function createRailwayDeployment() {
63
63
  process.exit(1)
64
64
  }
65
65
 
66
- const railwayConfig = {
67
- $schema: 'https://railway.app/railway.schema.json',
68
- build: {
69
- builder: 'RAILPACK',
70
- },
71
- deploy: {
72
- startCommand: 'npm start',
73
- healthcheckPath: '/',
74
- healthcheckTimeout: 300,
75
- restartPolicyType: 'ALWAYS',
76
- },
77
- environments: {
78
- production: {
79
- variables: {
80
- NODE_ENV: 'production',
81
- RUST_LOG: 'info',
82
- RAILPACK_DEPLOY_APT_PACKAGES: 'libfontconfig1',
83
- },
84
- },
85
- },
86
- }
66
+ const railwayConfig = `[build]
67
+ builder = "RAILPACK"
68
+
69
+ [deploy]
70
+ startCommand = "npm start"
71
+ healthcheckPath = "/"
72
+ healthcheckTimeout = 300
73
+ restartPolicyType = "ON_FAILURE"
74
+ restartPolicyMaxRetries = 3
75
+ `
87
76
 
88
- const railwayJsonPath = join(cwd, 'railway.json')
89
- if (existsSync(railwayJsonPath)) {
90
- logWarning('railway.json already exists, backing up to railway.json.backup')
91
- const existingConfig = readFileSync(railwayJsonPath, 'utf-8')
92
- writeFileSync(join(cwd, 'railway.json.backup'), existingConfig)
77
+ const railwayTomlPath = join(cwd, 'railway.toml')
78
+ if (existsSync(railwayTomlPath)) {
79
+ logWarning('railway.toml already exists, backing up to railway.toml.backup')
80
+ const existingConfig = readFileSync(railwayTomlPath, 'utf-8')
81
+ writeFileSync(join(cwd, 'railway.toml.backup'), existingConfig)
93
82
  }
94
83
 
95
- writeFileSync(railwayJsonPath, `${JSON.stringify(railwayConfig, null, 2)}\n`)
96
- logSuccess('Created railway.json configuration')
84
+ writeFileSync(railwayTomlPath, railwayConfig)
85
+ logSuccess('Created railway.toml configuration')
97
86
 
98
87
  const gitignorePath = join(cwd, '.gitignore')
99
88
  const railwayGitignoreEntries = [
@@ -112,15 +112,28 @@ if (typeof window !== 'undefined') {
112
112
  if (Array.isArray(element)) {
113
113
  if (element.length >= 4 && element[0] === '$') {
114
114
  const [, tag, , props] = element
115
- const children = props && props.children ? rscToHtml(props.children) : ''
115
+ let innerHTML = null
116
+ let children = ''
116
117
 
117
118
  let attrs = ''
118
119
  if (props) {
119
120
  for (const [key, value] of Object.entries(props)) {
120
- if (key !== 'children' && key !== '~boundaryId') {
121
+ if (key === 'dangerouslySetInnerHTML' && value && typeof value === 'object' && '__html' in value) {
122
+ innerHTML = value.__html
123
+ }
124
+ else if (key !== 'children' && key !== '~boundaryId') {
121
125
  const attrName = key === 'className' ? 'class' : key
122
126
 
123
- if (typeof value === 'string') {
127
+ if (key === 'style' && typeof value === 'object') {
128
+ const styleStr = Object.entries(value)
129
+ .map(([k, v]) => {
130
+ const kebabKey = k.replace(/([A-Z])/g, '-$1').toLowerCase()
131
+ return `${kebabKey}:${v}`
132
+ })
133
+ .join(';')
134
+ attrs += ` style="${styleStr}"`
135
+ }
136
+ else if (typeof value === 'string') {
124
137
  attrs += ` ${attrName}="${value.replace(/"/g, '&quot;')}"`
125
138
  }
126
139
  else if (typeof value === 'boolean' && value) {
@@ -128,9 +141,12 @@ if (typeof window !== 'undefined') {
128
141
  }
129
142
  }
130
143
  }
144
+
145
+ if (innerHTML === null && props.children)
146
+ children = rscToHtml(props.children)
131
147
  }
132
148
 
133
- return `<${tag}${attrs}>${children}</${tag}>`
149
+ return `<${tag}${attrs}>${innerHTML !== null ? innerHTML : children}</${tag}>`
134
150
  }
135
151
 
136
152
  return element.map(rscToHtml).join('')