@real-router/logger-plugin 0.0.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/LICENSE +22 -0
- package/README.md +227 -0
- package/dist/cjs/index.d.ts +71 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/metafile-cjs.json +1 -0
- package/dist/esm/index.d.mts +71 -0
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/metafile-esm.json +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Oleg Ivanov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# @real-router/logger-plugin
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
5
|
+
|
|
6
|
+
A plugin for logging router events to the console. Provides transition timing display, parameter diff tracking, Performance API integration, and log grouping.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @real-router/logger-plugin
|
|
12
|
+
# or
|
|
13
|
+
pnpm add @real-router/logger-plugin
|
|
14
|
+
# or
|
|
15
|
+
yarn add @real-router/logger-plugin
|
|
16
|
+
# or
|
|
17
|
+
bun add @real-router/logger-plugin
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { createRouter } from "@real-router/core";
|
|
24
|
+
import { loggerPlugin } from "@real-router/logger-plugin";
|
|
25
|
+
|
|
26
|
+
const router = createRouter(routes);
|
|
27
|
+
|
|
28
|
+
// Use with default settings
|
|
29
|
+
router.usePlugin(loggerPlugin);
|
|
30
|
+
|
|
31
|
+
router.start();
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Console output:**
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Router started
|
|
38
|
+
▼ Router transition
|
|
39
|
+
Transition: home → users (1.23ms)
|
|
40
|
+
Transition success (1.23ms)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Fast transitions (<0.1ms) display in microseconds:**
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
Transition success (27.29μs)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## API
|
|
50
|
+
|
|
51
|
+
### `loggerPlugin`
|
|
52
|
+
|
|
53
|
+
Ready-to-use plugin instance with default settings.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { loggerPlugin } from "@real-router/logger-plugin";
|
|
57
|
+
|
|
58
|
+
router.usePlugin(loggerPlugin);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `loggerPluginFactory()`
|
|
62
|
+
|
|
63
|
+
Factory for creating a new plugin instance.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { loggerPluginFactory } from "@real-router/logger-plugin";
|
|
67
|
+
|
|
68
|
+
router.usePlugin(loggerPluginFactory());
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Default Configuration
|
|
72
|
+
|
|
73
|
+
The plugin uses the following default configuration:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
interface LoggerPluginConfig {
|
|
77
|
+
level: "all" | "transitions" | "errors" | "none"; // default: "all"
|
|
78
|
+
showTiming: boolean; // default: true
|
|
79
|
+
showParamsDiff: boolean; // default: true
|
|
80
|
+
usePerformanceMarks: boolean; // default: false
|
|
81
|
+
context: string; // default: "real-router-logger-plugin"
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `level`
|
|
86
|
+
|
|
87
|
+
Event logging level.
|
|
88
|
+
|
|
89
|
+
- `'all'` **(default)** - logs all events (router start/stop + transitions)
|
|
90
|
+
- `'transitions'` - only transition events (start/success/cancel/error)
|
|
91
|
+
- `'errors'` - only transition errors
|
|
92
|
+
- `'none'` - disables all logs
|
|
93
|
+
|
|
94
|
+
### `showTiming`
|
|
95
|
+
|
|
96
|
+
Display transition execution time with adaptive units.
|
|
97
|
+
|
|
98
|
+
- `true` **(default)** - show timing (μs for fast transitions <0.1ms, ms otherwise)
|
|
99
|
+
- `false` - hide timing
|
|
100
|
+
|
|
101
|
+
**Output examples:**
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
Transition success (15ms) // normal timing
|
|
105
|
+
Transition success (27.29μs) // fast transitions
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `showParamsDiff`
|
|
109
|
+
|
|
110
|
+
Show differences in route parameters when navigating within the same route.
|
|
111
|
+
|
|
112
|
+
- `true` **(default)** - show changed, added, and removed parameters
|
|
113
|
+
- `false` - don't show parameter changes
|
|
114
|
+
|
|
115
|
+
**Example output:**
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
▼ Router transition
|
|
119
|
+
Transition: users.view → users.view
|
|
120
|
+
Changed: { id: "123" → "456" }, Added: {"sort":"name"}
|
|
121
|
+
Transition success (2.15ms)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Diff types displayed:**
|
|
125
|
+
|
|
126
|
+
- **Changed** - parameters with different values
|
|
127
|
+
- **Added** - new parameters in target state
|
|
128
|
+
- **Removed** - parameters present in source but not in target
|
|
129
|
+
|
|
130
|
+
**When diff is shown:**
|
|
131
|
+
|
|
132
|
+
- ✅ Only when navigating within the same route (e.g., `users.view` → `users.view`)
|
|
133
|
+
- ✅ Only when parameters actually changed
|
|
134
|
+
- ❌ Not shown when navigating between different routes
|
|
135
|
+
- ❌ Not shown when parameters are identical
|
|
136
|
+
|
|
137
|
+
### `context`
|
|
138
|
+
|
|
139
|
+
Context name for logs. Useful when working with multiple routers.
|
|
140
|
+
|
|
141
|
+
- **Default:** `'logger-plugin'`
|
|
142
|
+
|
|
143
|
+
**Example output:**
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
[logger-plugin] Transition: dashboard → users
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Logged Events
|
|
150
|
+
|
|
151
|
+
### Router Lifecycle
|
|
152
|
+
|
|
153
|
+
**`onStart`** - called when router starts
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
Router started
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**`onStop`** - called when router stops
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
Router stopped
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Transition Events
|
|
166
|
+
|
|
167
|
+
**`onTransitionStart`** - transition begins
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
▼ Router transition
|
|
171
|
+
Transition: home → users
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**`onTransitionSuccess`** - transition completed successfully
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
Transition success (24ms)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**`onTransitionCancel`** - transition cancelled
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
Transition cancelled (12ms)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**`onTransitionError`** - transition error
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
Transition error: ROUTE_NOT_FOUND (8ms)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Log Grouping
|
|
193
|
+
|
|
194
|
+
Transition events are automatically grouped in the console for better readability:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
▼ Router transition
|
|
198
|
+
Transition: users → users.view
|
|
199
|
+
[middleware logs...]
|
|
200
|
+
[guard logs...]
|
|
201
|
+
Transition success (45ms)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
This helps organize logs when working with complex transitions, middleware, and guards.
|
|
205
|
+
|
|
206
|
+
## TypeScript
|
|
207
|
+
|
|
208
|
+
The plugin is fully typed:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import {
|
|
212
|
+
loggerPlugin,
|
|
213
|
+
loggerPluginFactory,
|
|
214
|
+
type LoggerPluginConfig,
|
|
215
|
+
type LogLevel,
|
|
216
|
+
} from "@real-router/logger-plugin";
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Related Packages
|
|
220
|
+
|
|
221
|
+
- [@real-router/core](https://www.npmjs.com/package/@real-router/core) — Core router
|
|
222
|
+
- [@real-router/react](https://www.npmjs.com/package/@real-router/react) — React integration
|
|
223
|
+
- [@real-router/browser-plugin](https://www.npmjs.com/package/@real-router/browser-plugin) — Browser history
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT © [Oleg Ivanov](https://github.com/greydragon888)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { PluginFactory } from '@real-router/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a logger plugin for real-router.
|
|
5
|
+
*
|
|
6
|
+
* Configuration is managed through the logger singleton.
|
|
7
|
+
*
|
|
8
|
+
* @returns Plugin factory function for real-router
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { loggerPluginFactory } from "@real-router/logger-plugin";
|
|
13
|
+
*
|
|
14
|
+
* router.usePlugin(loggerPluginFactory());
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* // Use with default configuration
|
|
20
|
+
* router.usePlugin(loggerPluginFactory());
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare function loggerPluginFactory(): PluginFactory;
|
|
24
|
+
/**
|
|
25
|
+
* Default logger plugin instance with standard configuration.
|
|
26
|
+
* Provided for backward compatibility with existing code.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Use default configuration
|
|
30
|
+
* router.usePlugin(loggerPlugin);
|
|
31
|
+
*/
|
|
32
|
+
declare const loggerPlugin: PluginFactory;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Logging level for router events.
|
|
36
|
+
* Controls which events are logged to the console.
|
|
37
|
+
*/
|
|
38
|
+
type LogLevel = "all" | "transitions" | "errors" | "none";
|
|
39
|
+
/**
|
|
40
|
+
* Configuration options for the logger plugin.
|
|
41
|
+
*/
|
|
42
|
+
interface LoggerPluginConfig {
|
|
43
|
+
/**
|
|
44
|
+
* Logging level - controls what router events to log.
|
|
45
|
+
*
|
|
46
|
+
* - 'all': Log all router events (default)
|
|
47
|
+
* - 'transitions': Log only transition-related events
|
|
48
|
+
* - 'errors': Log only transition errors
|
|
49
|
+
* - 'none': Disable all logging
|
|
50
|
+
*
|
|
51
|
+
* @default 'all'
|
|
52
|
+
*/
|
|
53
|
+
level?: LogLevel;
|
|
54
|
+
/**
|
|
55
|
+
* Show diff of changed route parameters between transitions.
|
|
56
|
+
* Only applies when navigating within the same route.
|
|
57
|
+
* Helps identify which parameters changed during navigation.
|
|
58
|
+
*
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
showParamsDiff?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Custom context name for logger.
|
|
64
|
+
* Useful when running multiple routers.
|
|
65
|
+
*
|
|
66
|
+
* @default 'logger-plugin'
|
|
67
|
+
*/
|
|
68
|
+
context?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { type LogLevel, type LoggerPluginConfig, loggerPlugin, loggerPluginFactory };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var o={context:"logger-plugin"},n=o=>o?.name??"(none)";function e(){return()=>{const e=o,t=(o=>{let n=!1;return{open(e){o&&!n&&(console.group(e),n=!0)},close(){o&&n&&(console.groupEnd(),n=!1)},isOpen:()=>n}})("undefined"!=typeof console&&"function"==typeof console.group&&"function"==typeof console.groupEnd);return{onStart(){console.log(`[${e.context}] Router started`)},onStop(){t.close(),console.log(`[${e.context}] Router stopped`)},onTransitionStart(o,r){t.open("Router transition");const s=n(r),c=n(o);console.log(`[${e.context}] Transition: ${s} → ${c}`,{from:r,to:o}),((o,n)=>{if(!n)return;if(o.name!==n.name)return;const t=((o,n)=>{const e={},t={},r={};let s=!1;for(const t in o)t in n?o[t]!==n[t]&&(e[t]={from:o[t],to:n[t]},s=!0):(r[t]=o[t],s=!0);for(const e in n)e in o||(t[e]=n[e],s=!0);return s?{changed:e,added:t,removed:r}:null})(n.params,o.params);t&&((o,n)=>{const e=[],t=Object.entries(o.changed);if(t.length>0){const o=[];for(const[n,{from:e,to:r}]of t)o.push(`${n}: ${JSON.stringify(e)} → ${JSON.stringify(r)}`);e.push(`Changed: { ${o.join(", ")} }`)}Object.entries(o.added).length>0&&e.push(`Added: ${JSON.stringify(o.added)}`),Object.entries(o.removed).length>0&&e.push(`Removed: ${JSON.stringify(o.removed)}`),console.log(`[${n}] ${e.join(", ")}`)})(t,e.context)})(o,r)},onTransitionSuccess(o,n){console.log(`[${e.context}] Transition success`,{to:o,from:n}),t.close()},onTransitionCancel(o,n){console.warn(`[${e.context}] Transition cancelled`,{to:o,from:n}),t.close()},onTransitionError(o,n,r){console.error(`[${e.context}] Transition error: ${r.code}`,{error:r,stack:r.stack,to:o,from:n}),t.close()},teardown(){t.close()}}}}var t=e();exports.loggerPlugin=t,exports.loggerPluginFactory=e;//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/constants.ts","../../src/internal/console-groups.ts","../../src/internal/formatting.ts","../../src/internal/params-diff.ts","../../src/plugin.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// packages/logger-plugin/modules/constants.ts\n\nimport type { LoggerPluginConfig } from \"./types\";\n\nexport const DEFAULT_CONFIG: Required<LoggerPluginConfig> = {\n level: \"all\",\n showParamsDiff: true,\n context: \"logger-plugin\",\n};\n","// packages/logger-plugin/modules/internal/console-groups.ts\n\n/**\n * Checks if console.group is supported in the current environment.\n */\nexport const supportsConsoleGroups = (): boolean => {\n return (\n typeof console !== \"undefined\" &&\n typeof console.group === \"function\" &&\n typeof console.groupEnd === \"function\"\n );\n};\n\n/**\n * Manager for handling console groups\n */\ninterface GroupManager {\n /**\n * Opens a group if it's not already open\n */\n open: (label: string) => void;\n /**\n * Closes a group if it's open\n */\n close: () => void;\n /**\n * Checks if a group is currently open\n */\n isOpen: () => boolean;\n}\n\n/**\n * Creates a manager for handling console groups.\n * Prevents duplicate group opening.\n *\n * @param enabled - Whether groups are supported in the environment\n * @returns Object with open and close methods\n */\nexport const createGroupManager = (enabled: boolean): GroupManager => {\n let isOpened = false;\n\n return {\n /**\n * Opens a group if it's not already open.\n */\n open(label: string): void {\n if (!enabled || isOpened) {\n return;\n }\n\n console.group(label);\n isOpened = true;\n },\n\n /**\n * Closes a group if it's open.\n */\n close(): void {\n if (!enabled || !isOpened) {\n return;\n }\n\n console.groupEnd();\n isOpened = false;\n },\n\n /**\n * Checks if a group is currently open.\n */\n isOpen(): boolean {\n return isOpened;\n },\n };\n};\n","// packages/logger-plugin/modules/internal/formatting.ts\n\nimport type { State } from \"@real-router/core\";\n\n/**\n * Formats route name for logging output.\n * Handles undefined/null.\n */\nexport const formatRouteName = (state?: State): string => {\n return state?.name ?? \"(none)\";\n};\n","// packages/logger-plugin/modules/internal/params-diff.ts\n\nimport type { Params } from \"@real-router/core\";\n\nexport interface ParamsDiff {\n changed: Record<string, { from: unknown; to: unknown }>;\n added: Record<string, unknown>;\n removed: Record<string, unknown>;\n}\n\n/**\n * Calculates differences between two parameter objects.\n * Performs only shallow comparison.\n *\n * @param fromParams - Previous parameters\n * @param toParams - New parameters\n * @returns Object with differences or null if there are no changes\n */\nexport const getParamsDiff = (\n fromParams: Params,\n toParams: Params,\n): ParamsDiff | null => {\n const changed: ParamsDiff[\"changed\"] = {};\n const added: ParamsDiff[\"added\"] = {};\n const removed: ParamsDiff[\"removed\"] = {};\n\n // Track if any changes found to avoid iterating through objects at the end.\n // This is a performance optimization: instead of calling Object.keys().length\n // three times to check if objects are empty, we set this flag when we find\n // any change and check it once at the end.\n let hasChanges = false;\n\n // Find changed and removed\n for (const key in fromParams) {\n if (!(key in toParams)) {\n removed[key] = fromParams[key];\n hasChanges = true;\n } else if (fromParams[key] !== toParams[key]) {\n changed[key] = { from: fromParams[key], to: toParams[key] };\n hasChanges = true;\n }\n }\n\n // Find added\n for (const key in toParams) {\n if (!(key in fromParams)) {\n added[key] = toParams[key];\n hasChanges = true;\n }\n }\n\n // Return null if there are no changes\n if (!hasChanges) {\n return null;\n }\n\n return { changed, added, removed };\n};\n\n/**\n * Formats and logs parameter differences.\n *\n * @param diff - Object with differences\n * @param context - Context for logger\n */\nexport const logParamsDiff = (diff: ParamsDiff, context: string): void => {\n const parts: string[] = [];\n\n // Cache entries to avoid double iteration\n const changedEntries = Object.entries(diff.changed);\n\n if (changedEntries.length > 0) {\n const items: string[] = [];\n\n for (const [key, { from, to }] of changedEntries) {\n items.push(`${key}: ${JSON.stringify(from)} → ${JSON.stringify(to)}`);\n }\n\n parts.push(`Changed: { ${items.join(\", \")} }`);\n }\n\n const addedEntries = Object.entries(diff.added);\n\n if (addedEntries.length > 0) {\n parts.push(`Added: ${JSON.stringify(diff.added)}`);\n }\n\n const removedEntries = Object.entries(diff.removed);\n\n if (removedEntries.length > 0) {\n parts.push(`Removed: ${JSON.stringify(diff.removed)}`);\n }\n\n console.log(`[${context}] ${parts.join(\", \")}`);\n};\n","// packages/logger-plugin/modules/plugin.ts\n\nimport { DEFAULT_CONFIG } from \"./constants\";\nimport {\n createGroupManager,\n supportsConsoleGroups,\n} from \"./internal/console-groups\";\nimport { formatRouteName } from \"./internal/formatting\";\nimport { getParamsDiff, logParamsDiff } from \"./internal/params-diff\";\n\nimport type { PluginFactory, RouterError, State } from \"@real-router/core\";\n\n/**\n * Creates a logger plugin for real-router.\n *\n * Configuration is managed through the logger singleton.\n *\n * @returns Plugin factory function for real-router\n *\n * @example\n * ```ts\n * import { loggerPluginFactory } from \"@real-router/logger-plugin\";\n *\n * router.usePlugin(loggerPluginFactory());\n * ```\n *\n * @example\n * ```ts\n * // Use with default configuration\n * router.usePlugin(loggerPluginFactory());\n * ```\n */\nexport function loggerPluginFactory(): PluginFactory {\n // eslint-disable-next-line unicorn/consistent-function-scoping -- factory pattern: closure captures config, groups\n return () => {\n const config = DEFAULT_CONFIG;\n\n // Create helper managers\n const groups = createGroupManager(supportsConsoleGroups());\n\n /**\n * Logs parameter differences when navigating within the same route.\n */\n const logParamsIfNeeded = (toState: State, fromState?: State): void => {\n if (!fromState) {\n return;\n }\n\n // Show diff only for the same route\n if (toState.name !== fromState.name) {\n return;\n }\n\n const diff = getParamsDiff(fromState.params, toState.params);\n\n if (diff) {\n logParamsDiff(diff, config.context);\n }\n };\n\n return {\n onStart() {\n console.log(`[${config.context}] Router started`);\n },\n\n onStop() {\n groups.close();\n console.log(`[${config.context}] Router stopped`);\n },\n\n onTransitionStart(toState: State, fromState?: State) {\n groups.open(\"Router transition\");\n\n const fromRoute = formatRouteName(fromState);\n const toRoute = formatRouteName(toState);\n\n console.log(\n `[${config.context}] Transition: ${fromRoute} → ${toRoute}`,\n {\n from: fromState,\n to: toState,\n },\n );\n\n logParamsIfNeeded(toState, fromState);\n },\n\n onTransitionSuccess(toState: State, fromState?: State) {\n console.log(`[${config.context}] Transition success`, {\n to: toState,\n from: fromState,\n });\n\n groups.close();\n },\n\n onTransitionCancel(toState: State, fromState?: State) {\n console.warn(`[${config.context}] Transition cancelled`, {\n to: toState,\n from: fromState,\n });\n\n groups.close();\n },\n\n onTransitionError(\n toState: State | undefined,\n fromState: State | undefined,\n err: RouterError,\n ) {\n console.error(`[${config.context}] Transition error: ${err.code}`, {\n error: err,\n stack: err.stack,\n to: toState,\n from: fromState,\n });\n\n groups.close();\n },\n\n teardown() {\n groups.close();\n },\n };\n };\n}\n\n/**\n * Default logger plugin instance with standard configuration.\n * Provided for backward compatibility with existing code.\n *\n * @example\n * // Use default configuration\n * router.usePlugin(loggerPlugin);\n */\nexport const loggerPlugin = loggerPluginFactory();\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"inputs":{"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js":{"bytes":569,"imports":[],"format":"esm"},"src/constants.ts":{"bytes":233,"imports":[{"path":"/Users/olegivanov/WebstormProjects/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/internal/console-groups.ts":{"bytes":1490,"imports":[{"path":"/Users/olegivanov/WebstormProjects/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/internal/formatting.ts":{"bytes":281,"imports":[{"path":"/Users/olegivanov/WebstormProjects/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/internal/params-diff.ts":{"bytes":2619,"imports":[{"path":"/Users/olegivanov/WebstormProjects/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/plugin.ts":{"bytes":3413,"imports":[{"path":"src/constants.ts","kind":"import-statement","original":"./constants"},{"path":"src/internal/console-groups.ts","kind":"import-statement","original":"./internal/console-groups"},{"path":"src/internal/formatting.ts","kind":"import-statement","original":"./internal/formatting"},{"path":"src/internal/params-diff.ts","kind":"import-statement","original":"./internal/params-diff"},{"path":"/Users/olegivanov/WebstormProjects/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":266,"imports":[{"path":"src/plugin.ts","kind":"import-statement","original":"./plugin"},{"path":"/Users/olegivanov/WebstormProjects/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"dist/cjs/index.js.map":{"imports":[],"exports":[],"inputs":{},"bytes":11720},"dist/cjs/index.js":{"imports":[],"exports":["loggerPlugin","loggerPluginFactory"],"entryPoint":"src/index.ts","inputs":{"src/constants.ts":{"bytesInOutput":93},"src/internal/console-groups.ts":{"bytesInOutput":727},"src/internal/formatting.ts":{"bytesInOutput":72},"src/internal/params-diff.ts":{"bytesInOutput":1361},"src/plugin.ts":{"bytesInOutput":1902},"src/index.ts":{"bytesInOutput":0}},"bytes":4341}}}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { PluginFactory } from '@real-router/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a logger plugin for real-router.
|
|
5
|
+
*
|
|
6
|
+
* Configuration is managed through the logger singleton.
|
|
7
|
+
*
|
|
8
|
+
* @returns Plugin factory function for real-router
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { loggerPluginFactory } from "@real-router/logger-plugin";
|
|
13
|
+
*
|
|
14
|
+
* router.usePlugin(loggerPluginFactory());
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* // Use with default configuration
|
|
20
|
+
* router.usePlugin(loggerPluginFactory());
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare function loggerPluginFactory(): PluginFactory;
|
|
24
|
+
/**
|
|
25
|
+
* Default logger plugin instance with standard configuration.
|
|
26
|
+
* Provided for backward compatibility with existing code.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Use default configuration
|
|
30
|
+
* router.usePlugin(loggerPlugin);
|
|
31
|
+
*/
|
|
32
|
+
declare const loggerPlugin: PluginFactory;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Logging level for router events.
|
|
36
|
+
* Controls which events are logged to the console.
|
|
37
|
+
*/
|
|
38
|
+
type LogLevel = "all" | "transitions" | "errors" | "none";
|
|
39
|
+
/**
|
|
40
|
+
* Configuration options for the logger plugin.
|
|
41
|
+
*/
|
|
42
|
+
interface LoggerPluginConfig {
|
|
43
|
+
/**
|
|
44
|
+
* Logging level - controls what router events to log.
|
|
45
|
+
*
|
|
46
|
+
* - 'all': Log all router events (default)
|
|
47
|
+
* - 'transitions': Log only transition-related events
|
|
48
|
+
* - 'errors': Log only transition errors
|
|
49
|
+
* - 'none': Disable all logging
|
|
50
|
+
*
|
|
51
|
+
* @default 'all'
|
|
52
|
+
*/
|
|
53
|
+
level?: LogLevel;
|
|
54
|
+
/**
|
|
55
|
+
* Show diff of changed route parameters between transitions.
|
|
56
|
+
* Only applies when navigating within the same route.
|
|
57
|
+
* Helps identify which parameters changed during navigation.
|
|
58
|
+
*
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
showParamsDiff?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Custom context name for logger.
|
|
64
|
+
* Useful when running multiple routers.
|
|
65
|
+
*
|
|
66
|
+
* @default 'logger-plugin'
|
|
67
|
+
*/
|
|
68
|
+
context?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { type LogLevel, type LoggerPluginConfig, loggerPlugin, loggerPluginFactory };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var o={context:"logger-plugin"},n=o=>o?.name??"(none)";function e(){return()=>{const e=o,t=(o=>{let n=!1;return{open(e){o&&!n&&(console.group(e),n=!0)},close(){o&&n&&(console.groupEnd(),n=!1)},isOpen:()=>n}})("undefined"!=typeof console&&"function"==typeof console.group&&"function"==typeof console.groupEnd);return{onStart(){console.log(`[${e.context}] Router started`)},onStop(){t.close(),console.log(`[${e.context}] Router stopped`)},onTransitionStart(o,r){t.open("Router transition");const s=n(r),c=n(o);console.log(`[${e.context}] Transition: ${s} → ${c}`,{from:r,to:o}),((o,n)=>{if(!n)return;if(o.name!==n.name)return;const t=((o,n)=>{const e={},t={},r={};let s=!1;for(const t in o)t in n?o[t]!==n[t]&&(e[t]={from:o[t],to:n[t]},s=!0):(r[t]=o[t],s=!0);for(const e in n)e in o||(t[e]=n[e],s=!0);return s?{changed:e,added:t,removed:r}:null})(n.params,o.params);t&&((o,n)=>{const e=[],t=Object.entries(o.changed);if(t.length>0){const o=[];for(const[n,{from:e,to:r}]of t)o.push(`${n}: ${JSON.stringify(e)} → ${JSON.stringify(r)}`);e.push(`Changed: { ${o.join(", ")} }`)}Object.entries(o.added).length>0&&e.push(`Added: ${JSON.stringify(o.added)}`),Object.entries(o.removed).length>0&&e.push(`Removed: ${JSON.stringify(o.removed)}`),console.log(`[${n}] ${e.join(", ")}`)})(t,e.context)})(o,r)},onTransitionSuccess(o,n){console.log(`[${e.context}] Transition success`,{to:o,from:n}),t.close()},onTransitionCancel(o,n){console.warn(`[${e.context}] Transition cancelled`,{to:o,from:n}),t.close()},onTransitionError(o,n,r){console.error(`[${e.context}] Transition error: ${r.code}`,{error:r,stack:r.stack,to:o,from:n}),t.close()},teardown(){t.close()}}}}var t=e();export{t as loggerPlugin,e as loggerPluginFactory};//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/constants.ts","../../src/internal/console-groups.ts","../../src/internal/formatting.ts","../../src/internal/params-diff.ts","../../src/plugin.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// packages/logger-plugin/modules/constants.ts\n\nimport type { LoggerPluginConfig } from \"./types\";\n\nexport const DEFAULT_CONFIG: Required<LoggerPluginConfig> = {\n level: \"all\",\n showParamsDiff: true,\n context: \"logger-plugin\",\n};\n","// packages/logger-plugin/modules/internal/console-groups.ts\n\n/**\n * Checks if console.group is supported in the current environment.\n */\nexport const supportsConsoleGroups = (): boolean => {\n return (\n typeof console !== \"undefined\" &&\n typeof console.group === \"function\" &&\n typeof console.groupEnd === \"function\"\n );\n};\n\n/**\n * Manager for handling console groups\n */\ninterface GroupManager {\n /**\n * Opens a group if it's not already open\n */\n open: (label: string) => void;\n /**\n * Closes a group if it's open\n */\n close: () => void;\n /**\n * Checks if a group is currently open\n */\n isOpen: () => boolean;\n}\n\n/**\n * Creates a manager for handling console groups.\n * Prevents duplicate group opening.\n *\n * @param enabled - Whether groups are supported in the environment\n * @returns Object with open and close methods\n */\nexport const createGroupManager = (enabled: boolean): GroupManager => {\n let isOpened = false;\n\n return {\n /**\n * Opens a group if it's not already open.\n */\n open(label: string): void {\n if (!enabled || isOpened) {\n return;\n }\n\n console.group(label);\n isOpened = true;\n },\n\n /**\n * Closes a group if it's open.\n */\n close(): void {\n if (!enabled || !isOpened) {\n return;\n }\n\n console.groupEnd();\n isOpened = false;\n },\n\n /**\n * Checks if a group is currently open.\n */\n isOpen(): boolean {\n return isOpened;\n },\n };\n};\n","// packages/logger-plugin/modules/internal/formatting.ts\n\nimport type { State } from \"@real-router/core\";\n\n/**\n * Formats route name for logging output.\n * Handles undefined/null.\n */\nexport const formatRouteName = (state?: State): string => {\n return state?.name ?? \"(none)\";\n};\n","// packages/logger-plugin/modules/internal/params-diff.ts\n\nimport type { Params } from \"@real-router/core\";\n\nexport interface ParamsDiff {\n changed: Record<string, { from: unknown; to: unknown }>;\n added: Record<string, unknown>;\n removed: Record<string, unknown>;\n}\n\n/**\n * Calculates differences between two parameter objects.\n * Performs only shallow comparison.\n *\n * @param fromParams - Previous parameters\n * @param toParams - New parameters\n * @returns Object with differences or null if there are no changes\n */\nexport const getParamsDiff = (\n fromParams: Params,\n toParams: Params,\n): ParamsDiff | null => {\n const changed: ParamsDiff[\"changed\"] = {};\n const added: ParamsDiff[\"added\"] = {};\n const removed: ParamsDiff[\"removed\"] = {};\n\n // Track if any changes found to avoid iterating through objects at the end.\n // This is a performance optimization: instead of calling Object.keys().length\n // three times to check if objects are empty, we set this flag when we find\n // any change and check it once at the end.\n let hasChanges = false;\n\n // Find changed and removed\n for (const key in fromParams) {\n if (!(key in toParams)) {\n removed[key] = fromParams[key];\n hasChanges = true;\n } else if (fromParams[key] !== toParams[key]) {\n changed[key] = { from: fromParams[key], to: toParams[key] };\n hasChanges = true;\n }\n }\n\n // Find added\n for (const key in toParams) {\n if (!(key in fromParams)) {\n added[key] = toParams[key];\n hasChanges = true;\n }\n }\n\n // Return null if there are no changes\n if (!hasChanges) {\n return null;\n }\n\n return { changed, added, removed };\n};\n\n/**\n * Formats and logs parameter differences.\n *\n * @param diff - Object with differences\n * @param context - Context for logger\n */\nexport const logParamsDiff = (diff: ParamsDiff, context: string): void => {\n const parts: string[] = [];\n\n // Cache entries to avoid double iteration\n const changedEntries = Object.entries(diff.changed);\n\n if (changedEntries.length > 0) {\n const items: string[] = [];\n\n for (const [key, { from, to }] of changedEntries) {\n items.push(`${key}: ${JSON.stringify(from)} → ${JSON.stringify(to)}`);\n }\n\n parts.push(`Changed: { ${items.join(\", \")} }`);\n }\n\n const addedEntries = Object.entries(diff.added);\n\n if (addedEntries.length > 0) {\n parts.push(`Added: ${JSON.stringify(diff.added)}`);\n }\n\n const removedEntries = Object.entries(diff.removed);\n\n if (removedEntries.length > 0) {\n parts.push(`Removed: ${JSON.stringify(diff.removed)}`);\n }\n\n console.log(`[${context}] ${parts.join(\", \")}`);\n};\n","// packages/logger-plugin/modules/plugin.ts\n\nimport { DEFAULT_CONFIG } from \"./constants\";\nimport {\n createGroupManager,\n supportsConsoleGroups,\n} from \"./internal/console-groups\";\nimport { formatRouteName } from \"./internal/formatting\";\nimport { getParamsDiff, logParamsDiff } from \"./internal/params-diff\";\n\nimport type { PluginFactory, RouterError, State } from \"@real-router/core\";\n\n/**\n * Creates a logger plugin for real-router.\n *\n * Configuration is managed through the logger singleton.\n *\n * @returns Plugin factory function for real-router\n *\n * @example\n * ```ts\n * import { loggerPluginFactory } from \"@real-router/logger-plugin\";\n *\n * router.usePlugin(loggerPluginFactory());\n * ```\n *\n * @example\n * ```ts\n * // Use with default configuration\n * router.usePlugin(loggerPluginFactory());\n * ```\n */\nexport function loggerPluginFactory(): PluginFactory {\n // eslint-disable-next-line unicorn/consistent-function-scoping -- factory pattern: closure captures config, groups\n return () => {\n const config = DEFAULT_CONFIG;\n\n // Create helper managers\n const groups = createGroupManager(supportsConsoleGroups());\n\n /**\n * Logs parameter differences when navigating within the same route.\n */\n const logParamsIfNeeded = (toState: State, fromState?: State): void => {\n if (!fromState) {\n return;\n }\n\n // Show diff only for the same route\n if (toState.name !== fromState.name) {\n return;\n }\n\n const diff = getParamsDiff(fromState.params, toState.params);\n\n if (diff) {\n logParamsDiff(diff, config.context);\n }\n };\n\n return {\n onStart() {\n console.log(`[${config.context}] Router started`);\n },\n\n onStop() {\n groups.close();\n console.log(`[${config.context}] Router stopped`);\n },\n\n onTransitionStart(toState: State, fromState?: State) {\n groups.open(\"Router transition\");\n\n const fromRoute = formatRouteName(fromState);\n const toRoute = formatRouteName(toState);\n\n console.log(\n `[${config.context}] Transition: ${fromRoute} → ${toRoute}`,\n {\n from: fromState,\n to: toState,\n },\n );\n\n logParamsIfNeeded(toState, fromState);\n },\n\n onTransitionSuccess(toState: State, fromState?: State) {\n console.log(`[${config.context}] Transition success`, {\n to: toState,\n from: fromState,\n });\n\n groups.close();\n },\n\n onTransitionCancel(toState: State, fromState?: State) {\n console.warn(`[${config.context}] Transition cancelled`, {\n to: toState,\n from: fromState,\n });\n\n groups.close();\n },\n\n onTransitionError(\n toState: State | undefined,\n fromState: State | undefined,\n err: RouterError,\n ) {\n console.error(`[${config.context}] Transition error: ${err.code}`, {\n error: err,\n stack: err.stack,\n to: toState,\n from: fromState,\n });\n\n groups.close();\n },\n\n teardown() {\n groups.close();\n },\n };\n };\n}\n\n/**\n * Default logger plugin instance with standard configuration.\n * Provided for backward compatibility with existing code.\n *\n * @example\n * // Use default configuration\n * router.usePlugin(loggerPlugin);\n */\nexport const loggerPlugin = loggerPluginFactory();\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"inputs":{"src/constants.ts":{"bytes":233,"imports":[],"format":"esm"},"src/internal/console-groups.ts":{"bytes":1490,"imports":[],"format":"esm"},"src/internal/formatting.ts":{"bytes":281,"imports":[],"format":"esm"},"src/internal/params-diff.ts":{"bytes":2619,"imports":[],"format":"esm"},"src/plugin.ts":{"bytes":3413,"imports":[{"path":"src/constants.ts","kind":"import-statement","original":"./constants"},{"path":"src/internal/console-groups.ts","kind":"import-statement","original":"./internal/console-groups"},{"path":"src/internal/formatting.ts","kind":"import-statement","original":"./internal/formatting"},{"path":"src/internal/params-diff.ts","kind":"import-statement","original":"./internal/params-diff"}],"format":"esm"},"src/index.ts":{"bytes":266,"imports":[{"path":"src/plugin.ts","kind":"import-statement","original":"./plugin"}],"format":"esm"}},"outputs":{"dist/esm/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":11720},"dist/esm/index.mjs":{"imports":[],"exports":["loggerPlugin","loggerPluginFactory"],"entryPoint":"src/index.ts","inputs":{"src/constants.ts":{"bytesInOutput":93},"src/internal/console-groups.ts":{"bytesInOutput":727},"src/internal/formatting.ts":{"bytesInOutput":72},"src/internal/params-diff.ts":{"bytesInOutput":1361},"src/plugin.ts":{"bytesInOutput":1902},"src/index.ts":{"bytesInOutput":0}},"bytes":4341}}}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@real-router/logger-plugin",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "commonjs",
|
|
5
|
+
"description": "Development logging plugin with transition tracking and performance metrics",
|
|
6
|
+
"main": "./dist/cjs/index.js",
|
|
7
|
+
"module": "./dist/esm/index.mjs",
|
|
8
|
+
"types": "./dist/esm/index.d.mts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": {
|
|
12
|
+
"import": "./dist/esm/index.d.mts",
|
|
13
|
+
"require": "./dist/cjs/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"import": "./dist/esm/index.mjs",
|
|
16
|
+
"require": "./dist/cjs/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/greydragon888/real-router.git"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"real-router",
|
|
28
|
+
"logger",
|
|
29
|
+
"debugging",
|
|
30
|
+
"development",
|
|
31
|
+
"console",
|
|
32
|
+
"monitoring"
|
|
33
|
+
],
|
|
34
|
+
"author": {
|
|
35
|
+
"name": "Oleg Ivanov",
|
|
36
|
+
"email": "greydragon888@gmail.com",
|
|
37
|
+
"url": "https://github.com/greydragon888"
|
|
38
|
+
},
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/greydragon888/real-router/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/greydragon888/real-router",
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"type-check": "tsc --noEmit",
|
|
48
|
+
"lint": "eslint --cache --ext .ts src/ tests/ --fix --max-warnings 0",
|
|
49
|
+
"test:mutation": "stryker run",
|
|
50
|
+
"test:mutation:report": "open reports/mutation-report.html",
|
|
51
|
+
"lint:package": "publint",
|
|
52
|
+
"lint:types": "attw --pack ."
|
|
53
|
+
},
|
|
54
|
+
"sideEffects": false,
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@real-router/core": "workspace:^"
|
|
57
|
+
}
|
|
58
|
+
}
|