Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
77eb630
chore(deps): bump dependencies across workspace
skiniks Mar 17, 2026
bb02ea0
refactor: reorganize deployment and streaming setup code
skiniks Mar 17, 2026
2a82dcc
feat(fetch): add cache tags support to fetch operations
skiniks Mar 17, 2026
e66b13e
refactor: consolidate deployment and utility functions
skiniks Mar 17, 2026
22a0e5d
refactor(runtime): consolidate React globals and streaming setup
skiniks Mar 18, 2026
7ffde77
refactor(module_reload): remove stats and history tracking
skiniks Mar 18, 2026
616fe8d
refactor: consolidate React globals and improve fetch cache handling
skiniks Mar 18, 2026
f9c5fab
refactor: improve React setup and error handling across runtime
skiniks Mar 18, 2026
d87730c
fix: add defensive checks and improve path resolution logic
skiniks Mar 18, 2026
c07ba98
refactor: improve React JSX handling and image optimization logic
skiniks Mar 18, 2026
e4d9f17
refactor: improve JSX handling, fetch caching, and proxy utilities
skiniks Mar 18, 2026
915b642
refactor(ClientRouter): move route ref update before state change
skiniks Mar 18, 2026
9a512d5
refactor: optimize React JSX handling and image component logic
skiniks Mar 18, 2026
fe1bf3b
refactor: add defensive type checks and improve null handling
skiniks Mar 18, 2026
52aa1fe
refactor: consolidate JSX delegate creation and improve component res…
skiniks Mar 18, 2026
d93a3d1
refactor: improve JSX delegate creation and component ID resolution
skiniks Mar 18, 2026
1e519ff
refactor: add defensive checks and improve component resolution
skiniks Mar 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 44 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ tokio = { version = "1.50.0", features = [
"process"
] }
anyhow = "1.0.102"
clap = { version = "4.5.60", features = [ "derive" ] }
clap = { version = "4.6.0", features = [ "derive" ] }
colored = "3.1.1"
serde = { version = "1.0.228", features = [ "derive" ] }
serde_json = "1.0.149"
Expand Down
10 changes: 5 additions & 5 deletions crates/rari/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ governor = "0.10.4"
colored = { workspace = true }
url = "2.5.8"
urlencoding = "2.1.3"
tokio-tungstenite = "0.28.0"
tungstenite = "0.28.0"
tokio-tungstenite = "0.29.0"
tungstenite = "0.29.0"

# === Utilities ===
bytes = "1.11.1"
Expand All @@ -146,7 +146,7 @@ uuid = { version = "1.22.0", features = [ "v4" ] }
thiserror = "2.0.18"

# === Image Processing & Layout ===
image = { version = "0.25.9", default-features = false, features = [
image = { version = "0.25.10", default-features = false, features = [
"jpeg",
"png",
"gif",
Expand Down Expand Up @@ -196,7 +196,7 @@ windows-sys = { version = "=0.59.0", features = [
# === CLI & Logging ===
clap = { workspace = true }
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.22", features = [ "env-filter" ] }
tracing-subscriber = { version = "0.3.23", features = [ "env-filter" ] }

# === TLS & Crypto ===
rustls = { version = "=0.23.28", default-features = false, features = [
Expand All @@ -210,4 +210,4 @@ rand = "0.10.0"

[dev-dependencies]
tracing-test = "0.2.6"
tempfile = "3.26.0"
tempfile = "3.27.0"
2 changes: 1 addition & 1 deletion crates/rari/src/rsc/rendering/streaming/constants.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub const PROMISE_RESOLUTION_SCRIPT: &str = include_str!("js/promise_resolution.js");
pub const DEFERRED_EXECUTION_SCRIPT: &str = include_str!("js/deferred_execution.js");
pub const REACT_INIT_SCRIPT: &str = include_str!("js/react_init.js");
pub const STREAMING_REACT_SETUP_SCRIPT: &str = include_str!("js/streaming_react_setup.js");
pub const STREAMING_INIT_SCRIPT: &str = include_str!("js/streaming_init.js");
pub const PROMISE_TRACKING_INIT_SCRIPT: &str = include_str!("js/promise_tracking_init.js");
pub const COMPONENT_RENDER_SETUP_SCRIPT: &str = include_str!("js/component_render_setup.js");
Expand Down
10 changes: 8 additions & 2 deletions crates/rari/src/rsc/rendering/streaming/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,10 @@ impl StreamingRenderer {
) -> Result<PartialRenderResult, RariError> {
let react_init_result = self
.runtime
.execute_script("streaming-react-init".to_string(), REACT_INIT_SCRIPT.to_string())
.execute_script(
"streaming-react-init".to_string(),
STREAMING_REACT_SETUP_SCRIPT.to_string(),
)
.await?;

if let Some(available) = react_init_result.get("available").and_then(|v| v.as_bool()) {
Expand Down Expand Up @@ -883,7 +886,10 @@ impl StreamingRenderer {
) -> Result<PartialRenderResult, RariError> {
let react_init_result = self
.runtime
.execute_script("streaming-react-init".to_string(), REACT_INIT_SCRIPT.to_string())
.execute_script(
"streaming-react-init".to_string(),
STREAMING_REACT_SETUP_SCRIPT.to_string(),
)
.await
.map_err(|e| {
error!("Failed to execute React initialization script: {}", e);
Expand Down
1 change: 1 addition & 0 deletions crates/rari/src/runtime/ext/node/init_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ if (!globalThis.process) {
return '/'
}
},
// oxlint-disable-next-line @typescript-eslint/no-implied-eval
nextTick: fn => setTimeout(fn, 0),
platform: (() => {
try {
Expand Down
5 changes: 5 additions & 0 deletions crates/rari/src/runtime/ext/web/init_fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ async function fetchWithRustCache(input, init, meta) {
options.cacheTTLMs = String(revalidate * 1000)
}

const tags = init?.rari?.tags ?? init?.next?.tags
if (tags && Array.isArray(tags) && tags.length > 0) {
options.tags = JSON.stringify(tags)
}

const timeoutMs = init?.rari?.timeout ?? init?.fetchOptions?.timeout ?? 5000
options.timeout = String(typeof timeoutMs === 'number' && timeoutMs > 0 ? timeoutMs : 5000)

Expand Down
3 changes: 2 additions & 1 deletion crates/rari/src/runtime/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,8 @@ pub async fn op_fetch_with_cache(
"statusText": http_status_text(result.status),
"body": body_str,
"headers": headers_obj,
"cached": result.was_cached
"cached": result.was_cached,
"tags": result.tags
}))
}
Err(e) => {
Expand Down
14 changes: 12 additions & 2 deletions crates/rari/src/server/middleware/request_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct CachedFetchResult {
pub headers: HeaderMap,
pub cached_at: Instant,
pub was_cached: bool,
pub tags: Vec<String>,
}
type InFlightFetches =
Arc<DashMap<String, Arc<TokioMutex<Option<Result<CachedFetchResult, RariError>>>>>>;
Expand Down Expand Up @@ -77,7 +78,7 @@ impl RequestContext {
fn generate_cache_key(url: &str, options: &FxHashMap<String, String>) -> String {
let cache_relevant_options: FxHashMap<_, _> = options
.iter()
.filter(|(k, _)| !matches!(k.as_str(), "cacheTTLMs" | "timeout"))
.filter(|(k, _)| !matches!(k.as_str(), "cacheTTLMs" | "timeout" | "tags"))
.collect();

if cache_relevant_options.is_empty() {
Expand Down Expand Up @@ -113,6 +114,9 @@ impl RequestContext {
) -> Result<CachedFetchResult, RariError> {
let cache_key = Self::generate_cache_key(url, &options);

let tags: Vec<String> =
options.get("tags").and_then(|t| serde_json::from_str(t).ok()).unwrap_or_default();
Comment thread
skiniks marked this conversation as resolved.

{
let mut cache = self.fetch_cache.lock();
if let Some(cached) = cache.get(&cache_key) {
Expand Down Expand Up @@ -157,7 +161,11 @@ impl RequestContext {
cache_key: cache_key.clone(),
};

let fetch_result = self.perform_fetch(url, &options).await;
let mut fetch_result = self.perform_fetch(url, &options).await;

if let Ok(ref mut result) = fetch_result {
result.tags = tags;
}
Comment thread
skiniks marked this conversation as resolved.

*guard = Some(fetch_result.clone());

Expand Down Expand Up @@ -210,6 +218,7 @@ impl RequestContext {
headers,
cached_at: Instant::now(),
was_cached: false,
tags: Vec::new(),
})
}
}
Expand Down Expand Up @@ -240,6 +249,7 @@ mod tests {
headers: HeaderMap::new(),
cached_at: Instant::now(),
was_cached: false,
tags: Vec::new(),
};

let test_key = format!("https://test-{}.example.com", uuid::Uuid::new_v4());
Expand Down
2 changes: 1 addition & 1 deletion packages/create-rari-app/templates/default/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"@types/node": "^25.5.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@typescript/native-preview": "^7.0.0-dev.20260314.1",
"@typescript/native-preview": "^7.0.0-dev.20260317.1",
"tailwindcss": "^4.2.1",
"vite": "^8.0.0"
}
Expand Down
30 changes: 25 additions & 5 deletions packages/deploy/src/railway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import process from 'node:process'
import { styleText } from 'node:util'
import { ensureMinimumNodeEngine, logError, logInfo, logSuccess, logWarn } from './utils'

export async function createRailwayDeployment() {
const cwd = process.cwd()

logInfo('Creating Railway deployment configuration...')

function updatePackageJsonForRailway(cwd: string) {
const packageJsonPath = join(cwd, 'package.json')
if (!existsSync(packageJsonPath)) {
logError('No package.json found. Please run this command from your project root.')
Expand Down Expand Up @@ -45,7 +41,25 @@ export async function createRailwayDeployment() {
logError(`Failed to update package.json: ${error instanceof Error ? error.message : 'Unknown error'}`)
process.exit(1)
}
}

export async function createRailwayDeployment() {
const cwd = process.cwd()

logInfo('Creating Railway deployment configuration...')

updatePackageJsonForRailway(cwd)

createRailwayToml(cwd)

updateGitignoreForRailway(cwd)

updateReadmeForRailway(cwd)

printRailwaySuccessMessage()
}
Comment thread
skiniks marked this conversation as resolved.
Outdated

function createRailwayToml(cwd: string) {
const railwayConfig = `[build]
builder = "RAILPACK"

Expand All @@ -66,7 +80,9 @@ restartPolicyMaxRetries = 3

writeFileSync(railwayTomlPath, railwayConfig)
logSuccess('Created railway.toml configuration')
}

function updateGitignoreForRailway(cwd: string) {
const gitignorePath = join(cwd, '.gitignore')
const railwayGitignoreEntries = [
'',
Expand Down Expand Up @@ -121,7 +137,9 @@ tmp/
writeFileSync(gitignorePath, defaultGitignore)
logSuccess('Created .gitignore with Railway entries')
}
}

function updateReadmeForRailway(cwd: string) {
const readmePath = join(cwd, 'README.md')
const railwayReadmeSection = `
## 🚂 Deploy to Railway
Expand Down Expand Up @@ -194,7 +212,9 @@ Visit [http://localhost:3000](http://localhost:3000) to see your app.
writeFileSync(readmePath, defaultReadme)
logSuccess('Created README.md with Railway deployment instructions')
}
}

function printRailwaySuccessMessage() {
console.warn('')
logSuccess('Railway deployment setup complete! 🎉')
console.warn('')
Expand Down
Loading
Loading