@goliapkg/sentori-next 0.1.0 → 0.2.1
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/README.md +33 -6
- package/lib/app-router.d.ts +48 -0
- package/lib/app-router.d.ts.map +1 -0
- package/lib/app-router.js +77 -0
- package/lib/app-router.js.map +1 -0
- package/package.json +9 -5
- package/src/app-router.ts +80 -0
package/README.md
CHANGED
|
@@ -64,11 +64,16 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
64
64
|
```tsx
|
|
65
65
|
// app/error.tsx
|
|
66
66
|
'use client'
|
|
67
|
-
import {
|
|
68
|
-
|
|
69
|
-
export default function Error({
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
import { useReportNextError } from '@goliapkg/sentori-next/app-router'
|
|
68
|
+
|
|
69
|
+
export default function Error({
|
|
70
|
+
error,
|
|
71
|
+
reset,
|
|
72
|
+
}: {
|
|
73
|
+
error: Error & { digest?: string }
|
|
74
|
+
reset: () => void
|
|
75
|
+
}) {
|
|
76
|
+
useReportNextError(error) // captureError once per error instance
|
|
72
77
|
return (
|
|
73
78
|
<div>
|
|
74
79
|
<h2>Something went wrong</h2>
|
|
@@ -78,7 +83,28 @@ export default function Error({ error, reset }: { error: Error; reset: () => voi
|
|
|
78
83
|
}
|
|
79
84
|
```
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
`useReportNextError` calls `captureError` once per error instance
|
|
87
|
+
and picks up Next's `error.digest` as a tag so the dashboard can
|
|
88
|
+
correlate the client report with the server error.
|
|
89
|
+
|
|
90
|
+
For a global catch-all, drop the same component into
|
|
91
|
+
`app/global-error.tsx`.
|
|
92
|
+
|
|
93
|
+
### Navigation breadcrumbs (any layout)
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
// app/Shell.tsx — client wrapper mounted from app/layout.tsx
|
|
97
|
+
'use client'
|
|
98
|
+
import { useNextRouter } from '@goliapkg/sentori-next/app-router'
|
|
99
|
+
|
|
100
|
+
export function Shell({ children }: { children: React.ReactNode }) {
|
|
101
|
+
useNextRouter() // nav breadcrumb on every pathname change
|
|
102
|
+
return <>{children}</>
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
First mount does not emit a breadcrumb; only real pathname
|
|
107
|
+
transitions are recorded.
|
|
82
108
|
|
|
83
109
|
## What gets captured
|
|
84
110
|
|
|
@@ -102,6 +128,7 @@ the same signature. `serverInit()` is Node-only because Edge lacks
|
|
|
102
128
|
| `@goliapkg/sentori-next/client` | App Router client components, `clientInit`, `SentoriProvider`, `<SentoriErrorBoundary>`, hooks |
|
|
103
129
|
| `@goliapkg/sentori-next/server` | `instrumentation.ts`, `serverInit`, `onRequestError` |
|
|
104
130
|
| `@goliapkg/sentori-next/instrumentation` | one-line `instrumentation.ts` re-export |
|
|
131
|
+
| `@goliapkg/sentori-next/app-router` | `useNextRouter`, `useReportNextError` — client-only App Router hooks |
|
|
105
132
|
|
|
106
133
|
## Versioning
|
|
107
134
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscribe to App Router pathname transitions and push a `nav`
|
|
3
|
+
* breadcrumb on every change. Mount once in a layout's client
|
|
4
|
+
* component (e.g. a `<Shell>` in `app/layout.tsx`):
|
|
5
|
+
*
|
|
6
|
+
* 'use client'
|
|
7
|
+
* import { useNextRouter } from '@goliapkg/sentori-next/app-router'
|
|
8
|
+
* export function Shell({ children }: { children: React.ReactNode }) {
|
|
9
|
+
* useNextRouter()
|
|
10
|
+
* return children
|
|
11
|
+
* }
|
|
12
|
+
*
|
|
13
|
+
* First mount does NOT emit a breadcrumb — only real transitions.
|
|
14
|
+
*
|
|
15
|
+
* Intentionally does not read `useSearchParams()` — that hook
|
|
16
|
+
* requires a Suspense boundary in Next.js 14+ which complicates
|
|
17
|
+
* adoption. Pathname alone covers the breadcrumb story.
|
|
18
|
+
*/
|
|
19
|
+
export declare function useNextRouter(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Capture an error from an App Router `error.tsx` file. Idiomatic
|
|
22
|
+
* usage:
|
|
23
|
+
*
|
|
24
|
+
* // app/error.tsx
|
|
25
|
+
* 'use client'
|
|
26
|
+
* import { useReportNextError } from '@goliapkg/sentori-next/app-router'
|
|
27
|
+
* export default function ErrorPage({ error, reset }: {
|
|
28
|
+
* error: Error & { digest?: string }
|
|
29
|
+
* reset: () => void
|
|
30
|
+
* }) {
|
|
31
|
+
* useReportNextError(error)
|
|
32
|
+
* return (
|
|
33
|
+
* <div>
|
|
34
|
+
* <h2>Something went wrong.</h2>
|
|
35
|
+
* <button onClick={reset}>Try again</button>
|
|
36
|
+
* </div>
|
|
37
|
+
* )
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* The hook calls captureError exactly once per error instance
|
|
41
|
+
* (subsequent renders with the same error are no-ops). Picks up
|
|
42
|
+
* Next's `digest` field as a tag so the dashboard can correlate
|
|
43
|
+
* the client report with the server error.
|
|
44
|
+
*/
|
|
45
|
+
export declare function useReportNextError(error: Error & {
|
|
46
|
+
digest?: string;
|
|
47
|
+
}): void;
|
|
48
|
+
//# sourceMappingURL=app-router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-router.d.ts","sourceRoot":"","sources":["../src/app-router.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAWpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAY3E"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// App Router helpers for Next.js 14+. Imports from `next/navigation`
|
|
2
|
+
// (Next-side), so this module is client-only and is published under
|
|
3
|
+
// the `/app-router` subpath so the server bundle never tries to load
|
|
4
|
+
// `next/navigation` during instrumentation.
|
|
5
|
+
'use client';
|
|
6
|
+
import { addBreadcrumb, captureError } from '@goliapkg/sentori-javascript';
|
|
7
|
+
import { usePathname } from 'next/navigation';
|
|
8
|
+
import { useEffect, useRef } from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* Subscribe to App Router pathname transitions and push a `nav`
|
|
11
|
+
* breadcrumb on every change. Mount once in a layout's client
|
|
12
|
+
* component (e.g. a `<Shell>` in `app/layout.tsx`):
|
|
13
|
+
*
|
|
14
|
+
* 'use client'
|
|
15
|
+
* import { useNextRouter } from '@goliapkg/sentori-next/app-router'
|
|
16
|
+
* export function Shell({ children }: { children: React.ReactNode }) {
|
|
17
|
+
* useNextRouter()
|
|
18
|
+
* return children
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* First mount does NOT emit a breadcrumb — only real transitions.
|
|
22
|
+
*
|
|
23
|
+
* Intentionally does not read `useSearchParams()` — that hook
|
|
24
|
+
* requires a Suspense boundary in Next.js 14+ which complicates
|
|
25
|
+
* adoption. Pathname alone covers the breadcrumb story.
|
|
26
|
+
*/
|
|
27
|
+
export function useNextRouter() {
|
|
28
|
+
const pathname = usePathname();
|
|
29
|
+
const prevRef = useRef(null);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const prev = prevRef.current;
|
|
32
|
+
if (prev !== null && prev !== pathname) {
|
|
33
|
+
addBreadcrumb({ data: { from: prev, to: pathname }, type: 'nav' });
|
|
34
|
+
}
|
|
35
|
+
prevRef.current = pathname;
|
|
36
|
+
}, [pathname]);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Capture an error from an App Router `error.tsx` file. Idiomatic
|
|
40
|
+
* usage:
|
|
41
|
+
*
|
|
42
|
+
* // app/error.tsx
|
|
43
|
+
* 'use client'
|
|
44
|
+
* import { useReportNextError } from '@goliapkg/sentori-next/app-router'
|
|
45
|
+
* export default function ErrorPage({ error, reset }: {
|
|
46
|
+
* error: Error & { digest?: string }
|
|
47
|
+
* reset: () => void
|
|
48
|
+
* }) {
|
|
49
|
+
* useReportNextError(error)
|
|
50
|
+
* return (
|
|
51
|
+
* <div>
|
|
52
|
+
* <h2>Something went wrong.</h2>
|
|
53
|
+
* <button onClick={reset}>Try again</button>
|
|
54
|
+
* </div>
|
|
55
|
+
* )
|
|
56
|
+
* }
|
|
57
|
+
*
|
|
58
|
+
* The hook calls captureError exactly once per error instance
|
|
59
|
+
* (subsequent renders with the same error are no-ops). Picks up
|
|
60
|
+
* Next's `digest` field as a tag so the dashboard can correlate
|
|
61
|
+
* the client report with the server error.
|
|
62
|
+
*/
|
|
63
|
+
export function useReportNextError(error) {
|
|
64
|
+
const seenRef = useRef(null);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (seenRef.current === error)
|
|
67
|
+
return;
|
|
68
|
+
seenRef.current = error;
|
|
69
|
+
captureError(error, {
|
|
70
|
+
tags: {
|
|
71
|
+
'next.digest': error.digest ?? '',
|
|
72
|
+
source: 'next.error.tsx',
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}, [error]);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=app-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-router.js","sourceRoot":"","sources":["../src/app-router.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,oEAAoE;AACpE,qEAAqE;AACrE,4CAA4C;AAE5C,YAAY,CAAA;AAEZ,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAEzC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,OAAO,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAA;IAE3C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAA;QAC5B,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvC,aAAa,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QACpE,CAAC;QACD,OAAO,CAAC,OAAO,GAAG,QAAQ,CAAA;IAC5B,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAkC;IACnE,MAAM,OAAO,GAAG,MAAM,CAAe,IAAI,CAAC,CAAA;IAC1C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK;YAAE,OAAM;QACrC,OAAO,CAAC,OAAO,GAAG,KAAK,CAAA;QACvB,YAAY,CAAC,KAAK,EAAE;YAClB,IAAI,EAAE;gBACJ,aAAa,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;gBACjC,MAAM,EAAE,gBAAgB;aACzB;SACF,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goliapkg/sentori-next",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "Next.js adapter for Sentori — instrumentation.ts hooks, App Router error boundary, env-driven provider built on @goliapkg/sentori-react.",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Next.js adapter for Sentori — instrumentation.ts hooks, App Router error boundary, navigation tracing, env-driven provider built on @goliapkg/sentori-react.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://sentori.golia.jp",
|
|
7
7
|
"repository": {
|
|
@@ -38,6 +38,10 @@
|
|
|
38
38
|
"./instrumentation": {
|
|
39
39
|
"types": "./lib/instrumentation.d.ts",
|
|
40
40
|
"default": "./lib/instrumentation.js"
|
|
41
|
+
},
|
|
42
|
+
"./app-router": {
|
|
43
|
+
"types": "./lib/app-router.d.ts",
|
|
44
|
+
"default": "./lib/app-router.js"
|
|
41
45
|
}
|
|
42
46
|
},
|
|
43
47
|
"files": [
|
|
@@ -56,9 +60,9 @@
|
|
|
56
60
|
"react": ">=18"
|
|
57
61
|
},
|
|
58
62
|
"dependencies": {
|
|
59
|
-
"@goliapkg/sentori-core": "0.
|
|
60
|
-
"@goliapkg/sentori-javascript": "0.
|
|
61
|
-
"@goliapkg/sentori-react": "0.1
|
|
63
|
+
"@goliapkg/sentori-core": "0.3.0",
|
|
64
|
+
"@goliapkg/sentori-javascript": "0.3.1",
|
|
65
|
+
"@goliapkg/sentori-react": "0.4.1"
|
|
62
66
|
},
|
|
63
67
|
"devDependencies": {
|
|
64
68
|
"@types/bun": "latest",
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// App Router helpers for Next.js 14+. Imports from `next/navigation`
|
|
2
|
+
// (Next-side), so this module is client-only and is published under
|
|
3
|
+
// the `/app-router` subpath so the server bundle never tries to load
|
|
4
|
+
// `next/navigation` during instrumentation.
|
|
5
|
+
|
|
6
|
+
'use client'
|
|
7
|
+
|
|
8
|
+
import { addBreadcrumb, captureError } from '@goliapkg/sentori-javascript'
|
|
9
|
+
import { usePathname } from 'next/navigation'
|
|
10
|
+
import { useEffect, useRef } from 'react'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Subscribe to App Router pathname transitions and push a `nav`
|
|
14
|
+
* breadcrumb on every change. Mount once in a layout's client
|
|
15
|
+
* component (e.g. a `<Shell>` in `app/layout.tsx`):
|
|
16
|
+
*
|
|
17
|
+
* 'use client'
|
|
18
|
+
* import { useNextRouter } from '@goliapkg/sentori-next/app-router'
|
|
19
|
+
* export function Shell({ children }: { children: React.ReactNode }) {
|
|
20
|
+
* useNextRouter()
|
|
21
|
+
* return children
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* First mount does NOT emit a breadcrumb — only real transitions.
|
|
25
|
+
*
|
|
26
|
+
* Intentionally does not read `useSearchParams()` — that hook
|
|
27
|
+
* requires a Suspense boundary in Next.js 14+ which complicates
|
|
28
|
+
* adoption. Pathname alone covers the breadcrumb story.
|
|
29
|
+
*/
|
|
30
|
+
export function useNextRouter(): void {
|
|
31
|
+
const pathname = usePathname()
|
|
32
|
+
const prevRef = useRef<null | string>(null)
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const prev = prevRef.current
|
|
36
|
+
if (prev !== null && prev !== pathname) {
|
|
37
|
+
addBreadcrumb({ data: { from: prev, to: pathname }, type: 'nav' })
|
|
38
|
+
}
|
|
39
|
+
prevRef.current = pathname
|
|
40
|
+
}, [pathname])
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Capture an error from an App Router `error.tsx` file. Idiomatic
|
|
45
|
+
* usage:
|
|
46
|
+
*
|
|
47
|
+
* // app/error.tsx
|
|
48
|
+
* 'use client'
|
|
49
|
+
* import { useReportNextError } from '@goliapkg/sentori-next/app-router'
|
|
50
|
+
* export default function ErrorPage({ error, reset }: {
|
|
51
|
+
* error: Error & { digest?: string }
|
|
52
|
+
* reset: () => void
|
|
53
|
+
* }) {
|
|
54
|
+
* useReportNextError(error)
|
|
55
|
+
* return (
|
|
56
|
+
* <div>
|
|
57
|
+
* <h2>Something went wrong.</h2>
|
|
58
|
+
* <button onClick={reset}>Try again</button>
|
|
59
|
+
* </div>
|
|
60
|
+
* )
|
|
61
|
+
* }
|
|
62
|
+
*
|
|
63
|
+
* The hook calls captureError exactly once per error instance
|
|
64
|
+
* (subsequent renders with the same error are no-ops). Picks up
|
|
65
|
+
* Next's `digest` field as a tag so the dashboard can correlate
|
|
66
|
+
* the client report with the server error.
|
|
67
|
+
*/
|
|
68
|
+
export function useReportNextError(error: Error & { digest?: string }): void {
|
|
69
|
+
const seenRef = useRef<Error | null>(null)
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (seenRef.current === error) return
|
|
72
|
+
seenRef.current = error
|
|
73
|
+
captureError(error, {
|
|
74
|
+
tags: {
|
|
75
|
+
'next.digest': error.digest ?? '',
|
|
76
|
+
source: 'next.error.tsx',
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
}, [error])
|
|
80
|
+
}
|