mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
Use remix vite:dev in development
This commit is contained in:
parent
1809aa89d7
commit
18f1983097
2
.gitignore
vendored
2
.gitignore
vendored
@ -39,4 +39,4 @@ modelfiles
|
||||
site
|
||||
|
||||
# commit file ignore
|
||||
app/commit.json
|
||||
app/commit.json
|
||||
|
@ -1,4 +1,9 @@
|
||||
import * as Sentry from '@sentry/remix';
|
||||
import { sentryHandleError } from '~/lib/sentry';
|
||||
|
||||
/**
|
||||
* Using our conditional Sentry implementation instead of direct import
|
||||
* This avoids loading Sentry in development environments
|
||||
*/
|
||||
import type { AppLoadContext, EntryContext } from '@remix-run/cloudflare';
|
||||
import { RemixServer } from '@remix-run/react';
|
||||
import { isbot } from 'isbot';
|
||||
@ -7,7 +12,7 @@ import { renderHeadToString } from 'remix-island';
|
||||
import { Head } from './root';
|
||||
import { themeStore } from '~/lib/stores/theme';
|
||||
|
||||
export const handleError = Sentry.sentryHandleError;
|
||||
export const handleError = sentryHandleError;
|
||||
|
||||
export default async function handleRequest(
|
||||
request: Request,
|
||||
@ -26,10 +31,11 @@ export default async function handleRequest(
|
||||
},
|
||||
});
|
||||
|
||||
// @ts-ignore - Fix for incompatible EntryContext types between different remix versions
|
||||
const head = renderHeadToString({ request, remixContext, Head });
|
||||
|
||||
const body = new ReadableStream({
|
||||
start(controller) {
|
||||
const head = renderHeadToString({ request, remixContext, Head });
|
||||
|
||||
controller.enqueue(
|
||||
new Uint8Array(
|
||||
new TextEncoder().encode(
|
||||
|
@ -5,7 +5,7 @@ import type { ContentBlockParam, MessageParam } from '@anthropic-ai/sdk/resource
|
||||
import type { FileMap } from './stream-text';
|
||||
import { StreamingMessageParser } from '~/lib/runtime/message-parser';
|
||||
import { extractRelativePath } from '~/utils/diff';
|
||||
import { wrapWithSpan, getCurrentSpan } from '~/lib/.server/otel';
|
||||
import { wrapWithSpan, getCurrentSpan } from '~/lib/.server/otel-wrapper';
|
||||
|
||||
const Model = 'claude-3-7-sonnet-20250219';
|
||||
const MaxMessageTokens = 8192;
|
||||
|
142
app/lib/.server/otel-wrapper.ts
Normal file
142
app/lib/.server/otel-wrapper.ts
Normal file
@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Conditional OpenTelemetry implementation
|
||||
* In development: Uses mock implementations that do nothing
|
||||
* In production: Uses the real OpenTelemetry implementation
|
||||
*/
|
||||
|
||||
import type { AppLoadContext } from '@remix-run/cloudflare';
|
||||
|
||||
// Function to check if we're in development environment
|
||||
const isDevelopment = (): boolean => process.env.NODE_ENV === 'development';
|
||||
|
||||
// Types to match the original implementation
|
||||
type Attributes = Record<string, any>;
|
||||
|
||||
type SpanOptions = {
|
||||
name: string;
|
||||
attrs?: Attributes;
|
||||
};
|
||||
|
||||
// Mock implementations for development
|
||||
const mockImplementations = {
|
||||
ensureOpenTelemetryInitialized: (_context: AppLoadContext) => {
|
||||
console.log('[DEV MODE - OpenTelemetry not loaded]: Skipping initialization');
|
||||
},
|
||||
|
||||
wrapWithSpan: <Args extends any[], T>(
|
||||
opts: SpanOptions,
|
||||
fn: (...args: Args) => Promise<T>
|
||||
): ((...args: Args) => Promise<T>) => {
|
||||
// In development, just pass through the function without tracing
|
||||
return fn;
|
||||
},
|
||||
|
||||
getCurrentSpan: () => {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Using a let variable so we can cache the imports in production
|
||||
let otelModule: any = null;
|
||||
|
||||
// Helper to load the module once
|
||||
const getOtelModule = async () => {
|
||||
if (!otelModule && !isDevelopment()) {
|
||||
try {
|
||||
otelModule = await import('./otel');
|
||||
} catch (e) {
|
||||
console.error('Error loading OpenTelemetry:', e);
|
||||
// Return null to indicate failure
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return otelModule;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure OpenTelemetry is initialized
|
||||
* In development: Does nothing
|
||||
* In production: Initializes OpenTelemetry
|
||||
*/
|
||||
export function ensureOpenTelemetryInitialized(context: AppLoadContext): void {
|
||||
if (isDevelopment()) {
|
||||
// Use mock in development
|
||||
mockImplementations.ensureOpenTelemetryInitialized(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// In production, initialize (this will happen asynchronously)
|
||||
if (otelModule) {
|
||||
// If module is already loaded, use it directly
|
||||
otelModule.ensureOpenTelemetryInitialized(context);
|
||||
} else {
|
||||
// Otherwise trigger the async load and initialize when ready
|
||||
getOtelModule().then(module => {
|
||||
if (module) {
|
||||
module.ensureOpenTelemetryInitialized(context);
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error('Failed to initialize OpenTelemetry:', e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a function with a span for tracing
|
||||
* In development: Just returns the original function
|
||||
* In production: Wraps the function with a span
|
||||
*/
|
||||
export function wrapWithSpan<Args extends any[], T>(
|
||||
opts: SpanOptions,
|
||||
fn: (...args: Args) => Promise<T>
|
||||
): ((...args: Args) => Promise<T>) {
|
||||
if (isDevelopment()) {
|
||||
// In development, just pass through without tracing
|
||||
return fn;
|
||||
}
|
||||
|
||||
// In production, create a wrapper function
|
||||
return (...args: Args) => {
|
||||
// If module is already loaded, use it directly
|
||||
if (otelModule) {
|
||||
return otelModule.wrapWithSpan(opts, fn)(...args);
|
||||
}
|
||||
|
||||
// Otherwise trigger the async load for future calls
|
||||
getOtelModule().then(() => {
|
||||
// Module will be available for future calls
|
||||
}).catch(e => {
|
||||
console.error('Failed to load OpenTelemetry module:', e);
|
||||
});
|
||||
|
||||
// For the current call, just use the function directly
|
||||
return fn(...args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current span
|
||||
* In development: Returns null
|
||||
* In production: Returns the current span from OpenTelemetry
|
||||
*/
|
||||
export function getCurrentSpan(): any {
|
||||
if (isDevelopment()) {
|
||||
// In development, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
// If module is already loaded, use it directly
|
||||
if (otelModule) {
|
||||
return otelModule.getCurrentSpan();
|
||||
}
|
||||
|
||||
// Otherwise trigger the async load for future calls
|
||||
getOtelModule().then(() => {
|
||||
// Module will be available for future calls
|
||||
}).catch(e => {
|
||||
console.error('Failed to load OpenTelemetry module:', e);
|
||||
});
|
||||
|
||||
// For the current call, return null
|
||||
return null;
|
||||
}
|
39
app/lib/sentry.ts
Normal file
39
app/lib/sentry.ts
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Conditional Sentry implementation
|
||||
* In development: Uses a mock implementation that logs to console
|
||||
* In production: Uses the real Sentry implementation
|
||||
*/
|
||||
|
||||
// Function to check if we're in development environment
|
||||
const isDevelopment = (): boolean => process.env.NODE_ENV === 'development';
|
||||
|
||||
/**
|
||||
* Error handler function - wraps Sentry's error handling
|
||||
* In development, it just logs the error and returns it
|
||||
* In production, it sends the error to Sentry
|
||||
*/
|
||||
export function sentryHandleError(error: Error): Error {
|
||||
if (isDevelopment()) {
|
||||
// In development, just log the error
|
||||
console.error('[DEV MODE - Sentry not loaded]:', error);
|
||||
return error;
|
||||
}
|
||||
|
||||
try {
|
||||
/**
|
||||
* In production, dynamically import and use Sentry
|
||||
* This code only executes in production, so the import will never run in dev
|
||||
*/
|
||||
import('@sentry/remix')
|
||||
.then((sentry) => {
|
||||
sentry.captureException(error);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to load Sentry:', e);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Error while capturing exception:', e);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
@ -3,7 +3,7 @@ import { ChatStreamController } from '~/utils/chatStreamController';
|
||||
import { assert } from '~/lib/replay/ReplayProtocolClient';
|
||||
import { getStreamTextArguments, type FileMap, type Messages } from '~/lib/.server/llm/stream-text';
|
||||
import { chatAnthropic, type AnthropicApiKey } from '~/lib/.server/llm/chat-anthropic';
|
||||
import { ensureOpenTelemetryInitialized } from '~/lib/.server/otel';
|
||||
import { ensureOpenTelemetryInitialized } from '~/lib/.server/otel-wrapper';
|
||||
|
||||
export async function action(args: ActionFunctionArgs) {
|
||||
return chatAction(args);
|
||||
|
18
app/routes/api.health.ts
Normal file
18
app/routes/api.health.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import type { LoaderFunctionArgs } from '@remix-run/cloudflare';
|
||||
|
||||
export const loader = async ({ request: _request }: LoaderFunctionArgs) => {
|
||||
// Return a simple 200 OK response with some basic health information
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
status: 'healthy',
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: process.uptime(),
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
@ -156,4 +156,4 @@
|
||||
"@opentelemetry/context-async-hooks@1.30.1": "patches/@opentelemetry__context-async-hooks@1.30.1.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -165,7 +165,7 @@ importers:
|
||||
version: 8.55.0
|
||||
'@sentry/remix':
|
||||
specifier: ^8
|
||||
version: 8.55.0(@opentelemetry/context-async-hooks@1.30.1(patch_hash=k7tq4qcxof3n2buu2yqtrqhjhu)(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@remix-run/node@2.15.0(typescript@5.8.0-beta))(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(react@18.3.1)
|
||||
version: 8.55.0(@opentelemetry/context-async-hooks@1.30.1(patch_hash=k7tq4qcxof3n2buu2yqtrqhjhu)(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@remix-run/node@2.16.0(typescript@5.8.0-beta))(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(react@18.3.1)
|
||||
'@sentry/vite-plugin':
|
||||
specifier: ^3.1.2
|
||||
version: 3.2.0
|
||||
@ -267,10 +267,10 @@ importers:
|
||||
version: 4.0.0
|
||||
remix-island:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(@remix-run/server-runtime@2.15.0(typescript@5.8.0-beta))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
version: 0.2.0(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(@remix-run/server-runtime@2.16.0(typescript@5.8.0-beta))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
remix-utils:
|
||||
specifier: ^7.7.0
|
||||
version: 7.7.0(@remix-run/cloudflare@2.15.0(@cloudflare/workers-types@4.20241127.0)(typescript@5.8.0-beta))(@remix-run/node@2.15.0(typescript@5.8.0-beta))(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(@remix-run/router@1.21.0)(react@18.3.1)(zod@3.23.8)
|
||||
version: 7.7.0(@remix-run/cloudflare@2.15.0(@cloudflare/workers-types@4.20241127.0)(typescript@5.8.0-beta))(@remix-run/node@2.16.0(typescript@5.8.0-beta))(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(@remix-run/router@1.23.0)(react@18.3.1)(zod@3.23.8)
|
||||
shiki:
|
||||
specifier: ^1.24.0
|
||||
version: 1.24.0
|
||||
@ -2415,6 +2415,15 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
'@remix-run/node@2.16.0':
|
||||
resolution: {integrity: sha512-9yYBYCHYO1+bIScGAtOy5/r4BoTS8E5lpQmjWP99UxSCSiKHPEO76V9Z8mmmarTNis/FPN+sUwfmbQWNHLA2vw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
typescript: ^5.1.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
'@remix-run/react@2.15.0':
|
||||
resolution: {integrity: sha512-puqDbi9N/WfaUhzDnw2pACXtCB7ukrtFJ9ILwpEuhlaTBpjefifJ89igokW+tt1ePphIFMivAm/YspcbZdCQsA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
@ -2430,6 +2439,10 @@ packages:
|
||||
resolution: {integrity: sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
'@remix-run/router@1.23.0':
|
||||
resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
'@remix-run/server-runtime@2.15.0':
|
||||
resolution: {integrity: sha512-FuM8vAg1sPskf4wn0ivbuj/7s9Qdh2wnKu+sVXqYz0a95gH5b73TuMzk6n3NMSkFVKKc6+UmlG1WLYre7L2LTg==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
@ -2439,6 +2452,15 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
'@remix-run/server-runtime@2.16.0':
|
||||
resolution: {integrity: sha512-gbuc4slxPi+pT47MrUYprX/wCuDlYL6H3LHZSvimWO1kDCBt8oefHzdHDPjLi4B1xzqXZomswTbuJzpZ7xRRTg==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
typescript: ^5.1.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
'@remix-run/web-blob@3.1.0':
|
||||
resolution: {integrity: sha512-owGzFLbqPH9PlKb8KvpNJ0NO74HWE2euAn61eEiyCXX/oteoVzTVSN8mpLgDjaxBf2btj5/nUllSUgpyd6IH6g==}
|
||||
|
||||
@ -9274,6 +9296,18 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 5.8.0-beta
|
||||
|
||||
'@remix-run/node@2.16.0(typescript@5.8.0-beta)':
|
||||
dependencies:
|
||||
'@remix-run/server-runtime': 2.16.0(typescript@5.8.0-beta)
|
||||
'@remix-run/web-fetch': 4.4.2
|
||||
'@web3-storage/multipart-parser': 1.0.0
|
||||
cookie-signature: 1.2.2
|
||||
source-map-support: 0.5.21
|
||||
stream-slice: 0.1.2
|
||||
undici: 6.21.0
|
||||
optionalDependencies:
|
||||
typescript: 5.8.0-beta
|
||||
|
||||
'@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta)':
|
||||
dependencies:
|
||||
'@remix-run/router': 1.21.0
|
||||
@ -9288,6 +9322,8 @@ snapshots:
|
||||
|
||||
'@remix-run/router@1.21.0': {}
|
||||
|
||||
'@remix-run/router@1.23.0': {}
|
||||
|
||||
'@remix-run/server-runtime@2.15.0(typescript@5.8.0-beta)':
|
||||
dependencies:
|
||||
'@remix-run/router': 1.21.0
|
||||
@ -9300,6 +9336,18 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 5.8.0-beta
|
||||
|
||||
'@remix-run/server-runtime@2.16.0(typescript@5.8.0-beta)':
|
||||
dependencies:
|
||||
'@remix-run/router': 1.23.0
|
||||
'@types/cookie': 0.6.0
|
||||
'@web3-storage/multipart-parser': 1.0.0
|
||||
cookie: 0.6.0
|
||||
set-cookie-parser: 2.7.1
|
||||
source-map: 0.7.4
|
||||
turbo-stream: 2.4.0
|
||||
optionalDependencies:
|
||||
typescript: 5.8.0-beta
|
||||
|
||||
'@remix-run/web-blob@3.1.0':
|
||||
dependencies:
|
||||
'@remix-run/web-stream': 1.1.0
|
||||
@ -9585,10 +9633,10 @@ snapshots:
|
||||
hoist-non-react-statics: 3.3.2
|
||||
react: 18.3.1
|
||||
|
||||
'@sentry/remix@8.55.0(@opentelemetry/context-async-hooks@1.30.1(patch_hash=k7tq4qcxof3n2buu2yqtrqhjhu)(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@remix-run/node@2.15.0(typescript@5.8.0-beta))(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(react@18.3.1)':
|
||||
'@sentry/remix@8.55.0(@opentelemetry/context-async-hooks@1.30.1(patch_hash=k7tq4qcxof3n2buu2yqtrqhjhu)(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@remix-run/node@2.16.0(typescript@5.8.0-beta))(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@remix-run/node': 2.15.0(typescript@5.8.0-beta)
|
||||
'@remix-run/node': 2.16.0(typescript@5.8.0-beta)
|
||||
'@remix-run/react': 2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta)
|
||||
'@remix-run/router': 1.21.0
|
||||
'@sentry/cli': 2.42.1
|
||||
@ -13625,21 +13673,21 @@ snapshots:
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
unified: 11.0.5
|
||||
|
||||
remix-island@0.2.0(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(@remix-run/server-runtime@2.15.0(typescript@5.8.0-beta))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
remix-island@0.2.0(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(@remix-run/server-runtime@2.16.0(typescript@5.8.0-beta))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@remix-run/react': 2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta)
|
||||
'@remix-run/server-runtime': 2.15.0(typescript@5.8.0-beta)
|
||||
'@remix-run/server-runtime': 2.16.0(typescript@5.8.0-beta)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
remix-utils@7.7.0(@remix-run/cloudflare@2.15.0(@cloudflare/workers-types@4.20241127.0)(typescript@5.8.0-beta))(@remix-run/node@2.15.0(typescript@5.8.0-beta))(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(@remix-run/router@1.21.0)(react@18.3.1)(zod@3.23.8):
|
||||
remix-utils@7.7.0(@remix-run/cloudflare@2.15.0(@cloudflare/workers-types@4.20241127.0)(typescript@5.8.0-beta))(@remix-run/node@2.16.0(typescript@5.8.0-beta))(@remix-run/react@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta))(@remix-run/router@1.23.0)(react@18.3.1)(zod@3.23.8):
|
||||
dependencies:
|
||||
type-fest: 4.30.0
|
||||
optionalDependencies:
|
||||
'@remix-run/cloudflare': 2.15.0(@cloudflare/workers-types@4.20241127.0)(typescript@5.8.0-beta)
|
||||
'@remix-run/node': 2.15.0(typescript@5.8.0-beta)
|
||||
'@remix-run/node': 2.16.0(typescript@5.8.0-beta)
|
||||
'@remix-run/react': 2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.0-beta)
|
||||
'@remix-run/router': 1.21.0
|
||||
'@remix-run/router': 1.23.0
|
||||
react: 18.3.1
|
||||
zod: 3.23.8
|
||||
|
||||
|
@ -16,7 +16,7 @@ let commitJson = {
|
||||
|
||||
console.log(`
|
||||
★═══════════════════════════════════════★
|
||||
B O L T . D I Y
|
||||
NUT.NEW
|
||||
⚡️ Welcome ⚡️
|
||||
★═══════════════════════════════════════★
|
||||
`);
|
||||
|
Loading…
Reference in New Issue
Block a user