@helloleo/plugins 0.2.1 → 0.2.3
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.js +6 -4
- package/dist/templates/tanstack-start-2026-06-18/src/components/error-component.tsx +47 -0
- package/dist/templates/tanstack-start-2026-06-18/src/router.tsx +4 -0
- package/package.json +1 -1
- package/src/templates/tanstack-start-2026-06-18/src/components/error-component.tsx +47 -0
- package/src/templates/tanstack-start-2026-06-18/src/router.tsx +4 -0
- package/src/tools/setup-authentication/auth-files.ts +2 -1
- package/src/tools/setup-netsuite.ts +4 -3
package/dist/index.js
CHANGED
|
@@ -25013,9 +25013,10 @@ function buildAuth() {
|
|
|
25013
25013
|
${envFields}
|
|
25014
25014
|
}
|
|
25015
25015
|
|
|
25016
|
+
// HELLOLEO_URL is injected by the platform as a bare host, no scheme.
|
|
25016
25017
|
return betterAuth({
|
|
25017
25018
|
secret: e.BETTER_AUTH_SECRET,
|
|
25018
|
-
baseURL: e.HELLOLEO_URL
|
|
25019
|
+
baseURL: e.HELLOLEO_URL ? \`https://\${e.HELLOLEO_URL}\` : 'http://localhost:3000',
|
|
25019
25020
|
database: drizzleAdapter(db, { provider: 'sqlite', schema }),
|
|
25020
25021
|
emailAndPassword: {
|
|
25021
25022
|
enabled: ${hasPassword},
|
|
@@ -25581,9 +25582,10 @@ function stripTrailingSlash(s: string) {
|
|
|
25581
25582
|
export function appOrigin(request: Request) {
|
|
25582
25583
|
// 1) Explicit override wins (set by the platform per environment).
|
|
25583
25584
|
if (nsEnv.PUBLIC_APP_URL) return stripTrailingSlash(nsEnv.PUBLIC_APP_URL)
|
|
25584
|
-
// 2) HELLOLEO_URL is injected on every deploy (the app's canonical origin
|
|
25585
|
-
// it's set even when the NetSuite
|
|
25586
|
-
|
|
25585
|
+
// 2) HELLOLEO_URL is injected on every deploy (the app's canonical origin,
|
|
25586
|
+
// a bare host with no scheme), so it's set even when the NetSuite
|
|
25587
|
+
// wizard's PUBLIC_APP_URL pin wasn't.
|
|
25588
|
+
if (nsEnv.HELLOLEO_URL) return \`https://\${stripTrailingSlash(nsEnv.HELLOLEO_URL)}\`
|
|
25587
25589
|
// 3) Preview/prod proxies rewrite Host, so trust the forwarded/original host
|
|
25588
25590
|
// they set (HelloLeo's nginx sends X-Original-Host) \u2014 that's the public URL
|
|
25589
25591
|
// the browser loaded, not an internal upstream host.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { useRouterState } from '@tanstack/react-router'
|
|
3
|
+
import { Button } from '@/components/ui/button'
|
|
4
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
5
|
+
|
|
6
|
+
// Rendered by the router's defaultErrorComponent for any uncaught render or
|
|
7
|
+
// loader error. Per-route `errorComponent` options override it. Keep this
|
|
8
|
+
// component free of app dependencies (toasts, auth, etc.) -- it must still
|
|
9
|
+
// render when the rest of the app is broken.
|
|
10
|
+
export function DefaultErrorComponent({ error }: { error: Error }) {
|
|
11
|
+
const pathname = useRouterState({ select: (s) => s.location.pathname })
|
|
12
|
+
const [copied, setCopied] = useState(false)
|
|
13
|
+
|
|
14
|
+
async function copyForLeo() {
|
|
15
|
+
// Blank lines + fenced stack so the report keeps its structure when
|
|
16
|
+
// pasted into a markdown-rendering chat.
|
|
17
|
+
const report = [
|
|
18
|
+
'My app threw an error, please fix it:',
|
|
19
|
+
`Page: ${pathname}`,
|
|
20
|
+
`Error: ${error.message}`,
|
|
21
|
+
['Stack:', '```', error.stack ?? '(no stack trace)', '```'].join('\n'),
|
|
22
|
+
].join('\n\n')
|
|
23
|
+
|
|
24
|
+
await navigator.clipboard.writeText(report)
|
|
25
|
+
setCopied(true)
|
|
26
|
+
setTimeout(() => setCopied(false), 2000)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div className="min-h-screen flex items-center justify-center bg-background p-4">
|
|
31
|
+
<Card className="w-full max-w-lg">
|
|
32
|
+
<CardHeader>
|
|
33
|
+
<CardTitle>Something went wrong</CardTitle>
|
|
34
|
+
</CardHeader>
|
|
35
|
+
<CardContent className="space-y-4">
|
|
36
|
+
<pre className="text-sm text-destructive whitespace-pre-wrap break-words rounded-md bg-muted p-3">
|
|
37
|
+
{error.message}
|
|
38
|
+
</pre>
|
|
39
|
+
<Button onClick={copyForLeo}>{copied ? 'Copied!' : 'Copy error'}</Button>
|
|
40
|
+
<p className="text-sm text-muted-foreground">
|
|
41
|
+
Paste the copied error to Leo and it will help you fix it.
|
|
42
|
+
</p>
|
|
43
|
+
</CardContent>
|
|
44
|
+
</Card>
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
@@ -2,6 +2,7 @@ import { QueryClient } from '@tanstack/react-query'
|
|
|
2
2
|
import { createRouter as createTanStackRouter } from '@tanstack/react-router'
|
|
3
3
|
import { routerWithQueryClient } from '@tanstack/react-router-with-query'
|
|
4
4
|
import { routeTree } from './routeTree.gen'
|
|
5
|
+
import { DefaultErrorComponent } from '@/components/error-component'
|
|
5
6
|
|
|
6
7
|
// TanStack Start calls getRouter() on both server and client. routerWithQueryClient
|
|
7
8
|
// wires the QueryClient into the router context and handles SSR dehydration /
|
|
@@ -15,6 +16,9 @@ export function getRouter() {
|
|
|
15
16
|
routeTree,
|
|
16
17
|
context: { queryClient },
|
|
17
18
|
scrollRestoration: true,
|
|
19
|
+
// Catches uncaught render/loader errors on any route. Routes can still
|
|
20
|
+
// set their own `errorComponent` to override this.
|
|
21
|
+
defaultErrorComponent: DefaultErrorComponent,
|
|
18
22
|
defaultPreload: 'intent',
|
|
19
23
|
// With React Query we never want loader data to be stale -- the loader runs
|
|
20
24
|
// on every preload/visit and React Query owns caching from there.
|
package/package.json
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { useRouterState } from '@tanstack/react-router'
|
|
3
|
+
import { Button } from '@/components/ui/button'
|
|
4
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
5
|
+
|
|
6
|
+
// Rendered by the router's defaultErrorComponent for any uncaught render or
|
|
7
|
+
// loader error. Per-route `errorComponent` options override it. Keep this
|
|
8
|
+
// component free of app dependencies (toasts, auth, etc.) -- it must still
|
|
9
|
+
// render when the rest of the app is broken.
|
|
10
|
+
export function DefaultErrorComponent({ error }: { error: Error }) {
|
|
11
|
+
const pathname = useRouterState({ select: (s) => s.location.pathname })
|
|
12
|
+
const [copied, setCopied] = useState(false)
|
|
13
|
+
|
|
14
|
+
async function copyForLeo() {
|
|
15
|
+
// Blank lines + fenced stack so the report keeps its structure when
|
|
16
|
+
// pasted into a markdown-rendering chat.
|
|
17
|
+
const report = [
|
|
18
|
+
'My app threw an error, please fix it:',
|
|
19
|
+
`Page: ${pathname}`,
|
|
20
|
+
`Error: ${error.message}`,
|
|
21
|
+
['Stack:', '```', error.stack ?? '(no stack trace)', '```'].join('\n'),
|
|
22
|
+
].join('\n\n')
|
|
23
|
+
|
|
24
|
+
await navigator.clipboard.writeText(report)
|
|
25
|
+
setCopied(true)
|
|
26
|
+
setTimeout(() => setCopied(false), 2000)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div className="min-h-screen flex items-center justify-center bg-background p-4">
|
|
31
|
+
<Card className="w-full max-w-lg">
|
|
32
|
+
<CardHeader>
|
|
33
|
+
<CardTitle>Something went wrong</CardTitle>
|
|
34
|
+
</CardHeader>
|
|
35
|
+
<CardContent className="space-y-4">
|
|
36
|
+
<pre className="text-sm text-destructive whitespace-pre-wrap break-words rounded-md bg-muted p-3">
|
|
37
|
+
{error.message}
|
|
38
|
+
</pre>
|
|
39
|
+
<Button onClick={copyForLeo}>{copied ? 'Copied!' : 'Copy error'}</Button>
|
|
40
|
+
<p className="text-sm text-muted-foreground">
|
|
41
|
+
Paste the copied error to Leo and it will help you fix it.
|
|
42
|
+
</p>
|
|
43
|
+
</CardContent>
|
|
44
|
+
</Card>
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
@@ -2,6 +2,7 @@ import { QueryClient } from '@tanstack/react-query'
|
|
|
2
2
|
import { createRouter as createTanStackRouter } from '@tanstack/react-router'
|
|
3
3
|
import { routerWithQueryClient } from '@tanstack/react-router-with-query'
|
|
4
4
|
import { routeTree } from './routeTree.gen'
|
|
5
|
+
import { DefaultErrorComponent } from '@/components/error-component'
|
|
5
6
|
|
|
6
7
|
// TanStack Start calls getRouter() on both server and client. routerWithQueryClient
|
|
7
8
|
// wires the QueryClient into the router context and handles SSR dehydration /
|
|
@@ -15,6 +16,9 @@ export function getRouter() {
|
|
|
15
16
|
routeTree,
|
|
16
17
|
context: { queryClient },
|
|
17
18
|
scrollRestoration: true,
|
|
19
|
+
// Catches uncaught render/loader errors on any route. Routes can still
|
|
20
|
+
// set their own `errorComponent` to override this.
|
|
21
|
+
defaultErrorComponent: DefaultErrorComponent,
|
|
18
22
|
defaultPreload: 'intent',
|
|
19
23
|
// With React Query we never want loader data to be stale -- the loader runs
|
|
20
24
|
// on every preload/visit and React Query owns caching from there.
|
|
@@ -70,9 +70,10 @@ function buildAuth() {
|
|
|
70
70
|
${envFields}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// HELLOLEO_URL is injected by the platform as a bare host, no scheme.
|
|
73
74
|
return betterAuth({
|
|
74
75
|
secret: e.BETTER_AUTH_SECRET,
|
|
75
|
-
baseURL: e.HELLOLEO_URL
|
|
76
|
+
baseURL: e.HELLOLEO_URL ? \`https://\${e.HELLOLEO_URL}\` : 'http://localhost:3000',
|
|
76
77
|
database: drizzleAdapter(db, { provider: 'sqlite', schema }),
|
|
77
78
|
emailAndPassword: {
|
|
78
79
|
enabled: ${hasPassword},
|
|
@@ -142,9 +142,10 @@ function stripTrailingSlash(s: string) {
|
|
|
142
142
|
export function appOrigin(request: Request) {
|
|
143
143
|
// 1) Explicit override wins (set by the platform per environment).
|
|
144
144
|
if (nsEnv.PUBLIC_APP_URL) return stripTrailingSlash(nsEnv.PUBLIC_APP_URL)
|
|
145
|
-
// 2) HELLOLEO_URL is injected on every deploy (the app's canonical origin
|
|
146
|
-
// it's set even when the NetSuite
|
|
147
|
-
|
|
145
|
+
// 2) HELLOLEO_URL is injected on every deploy (the app's canonical origin,
|
|
146
|
+
// a bare host with no scheme), so it's set even when the NetSuite
|
|
147
|
+
// wizard's PUBLIC_APP_URL pin wasn't.
|
|
148
|
+
if (nsEnv.HELLOLEO_URL) return \`https://\${stripTrailingSlash(nsEnv.HELLOLEO_URL)}\`
|
|
148
149
|
// 3) Preview/prod proxies rewrite Host, so trust the forwarded/original host
|
|
149
150
|
// they set (HelloLeo's nginx sends X-Original-Host) — that's the public URL
|
|
150
151
|
// the browser loaded, not an internal upstream host.
|