runtime-reporter 0.4.0 → 0.4.2

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.
Files changed (2) hide show
  1. package/README.md +139 -63
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,19 +1,116 @@
1
1
  # Runtime Reporter
2
2
 
3
- Structured runtime events for applications and frameworks. A composable foundation for logging, messaging, and runtime reporting.
3
+ Structured runtime reporting that is type-safe, centralized, and production-ready for frameworks and applications
4
+
5
+ ## Why Runtime Reporter?
6
+
7
+ Most projects eventually accumulate:
8
+
9
+ - duplicated log messages
10
+ - inconsistent error wording
11
+ - fragile test assertions
12
+ - accidental exposure of sensitive data
13
+
14
+ Runtime Reporter replaces ad-hoc logging with structured, code-based messaging.
15
+
16
+ ## Who is Runtime Reporter for?
17
+
18
+ Use Runtime Reporter if:
19
+
20
+ - you're building a framework or library
21
+ - you want to avoid exposing sensitive information in production
22
+ - you want stable error codes for debugging and tracing runtime behavior
23
+ - you want to avoid bloat from verbose console messages
24
+ - you want a lightweight tool (~2 KB minified) that is easy to use
25
+ - you want to avoid duplicating message text in tests
4
26
 
5
27
  ## Features
6
28
 
7
- - **Security focused**: Pass an empty message set in production to avoid exposing internal messaging.
8
- - **Centralized messages**: Define message text once; reference by a unique code everywhere else.
9
- - **Tokenized templates**: Apply runtime data to messages via templated strings and tokenized variables.
10
- - **Type-safe**: Autocomplete and compile-time validation for message codes and token names.
11
- - **Tree-shakeable**: Pass an empty message set in production to reduce your bundle size
12
- - **Test friendly**: Use `message()` to assert on final output without duplicating message text.
13
- - **Code-based messaging**: Coded messages make it easy to identify errors to perform debugging tasks.
14
- - **Small footprint**: Minimal bundle size (~2 KB minified) so it adds negligible weight to your app.
15
- - **Zero dependencies**: No runtime dependencies; the published package is fully self-contained.
16
- - **Scalable pattern**: Can scale to fit your specific needs regardless of your project's size.
29
+ If you are new to Runtime Reporter, take a moment to explore the its core features.
30
+
31
+ ### Basic usage
32
+
33
+ Getting started is easy. Create a reporter instance with your messages and start logging.
34
+
35
+ ```ts
36
+ import { createReporter } from "runtime-reporter";
37
+
38
+ const reporter = createReporter({
39
+ ERR01: "MyComponent failed at mount",
40
+ });
41
+
42
+ reporter.error("ERR01");
43
+ ```
44
+
45
+ ### Code-based messaging
46
+
47
+ Replace inline strings with centralized, code-based identifiers.
48
+
49
+ ```ts
50
+ // Without runtime-reporter (logs "MyComponent failed at mount")
51
+ console.error("MyComponent failed at mount");
52
+
53
+ // With runtime-reporter (logs "MyComponent failed at mount (ERR01)")
54
+ reporter.error("ERR01");
55
+ ```
56
+
57
+ ### Dynamic messages
58
+
59
+ Inject runtime data into your messages via message templates and tokenized variables.
60
+
61
+ ```ts
62
+ const reporter = createReporter({
63
+ ERR01: "{{ componentName }} failed at {{ phase }}",
64
+ });
65
+
66
+ reporter.error("ERR01", { componentName: "MyComponent", phase: "mount" });
67
+ ```
68
+
69
+ ### Type safety
70
+
71
+ Annotate your messages to get autocomplete and compile-time validation for message codes and token names.
72
+
73
+ ```ts
74
+ const messages: RuntimeReporterMessages<{
75
+ code: "ERR01";
76
+ template: "{{ componentName }} failed at {{ phase }}";
77
+ tokens: "componentName" | "phase";
78
+ }> = {
79
+ ERR01: "{{ componentName }} failed at {{ phase }}",
80
+ };
81
+
82
+ const reporter = createReporter(messages);
83
+
84
+ reporter.error("ERR01", { componentName: "MyComponent", phase: "mount" }); // ✅ Autocomplete
85
+ reporter.error("ERR01", { componentName: "MyComponent" }); // ❌ TypeScript Error: "phase" is required
86
+ reporter.error("ERR02", { componentName: "MyComponent", phase: "mount" }); // ❌ TypeScript Error: "ERR02" is not a valid message code
87
+ ```
88
+
89
+ ### Production builds
90
+
91
+ Pass an empty object to the `createReporter` function in production for better security and a smaller bundle size.
92
+
93
+ ```ts
94
+ const reporter = createReporter(
95
+ process.env.NODE_ENV === "production" ? ({} as typeof messages) : messages
96
+ );
97
+ ```
98
+
99
+ ### Test friendly
100
+
101
+ Assert against resolved messages without duplicating message text in your test environment.
102
+
103
+ ```ts
104
+ it("should log error if component fails to mount", () => {
105
+ vi.spyOn(console, "error").mockImplementation(() => {});
106
+
107
+ render(<MyComponent />);
108
+
109
+ expect(console.error).toHaveBeenCalledWith(
110
+ reporter.message("ERR01", { componentName: "MyComponent", phase: "mount" })
111
+ );
112
+ });
113
+ ```
17
114
 
18
115
  ## Installation
19
116
 
@@ -21,14 +118,14 @@ Structured runtime events for applications and frameworks. A composable foundati
21
118
  npm install runtime-reporter
22
119
  ```
23
120
 
24
- ## Usage
25
-
26
- ### 1) Define your messages
121
+ ## Quick start
27
122
 
28
- Define your messages by creating an object with the message "schema" (code + template + tokens) and keyed by their codes.
123
+ A copy-and-paste example of how to use Runtime Reporter in your project.
29
124
 
30
125
  ```ts
31
- import type { RuntimeReporterMessages } from "runtime-reporter";
126
+ // src/runtime-reporter.ts
127
+
128
+ import { createReporter, type RuntimeReporterMessages } from "runtime-reporter";
32
129
 
33
130
  const messages: RuntimeReporterMessages<
34
131
  | {
@@ -37,38 +134,34 @@ const messages: RuntimeReporterMessages<
37
134
  tokens: "componentName" | "phase";
38
135
  }
39
136
  | {
40
- code: "INFO01";
41
- template: "Ready";
137
+ code: "ERR02";
138
+ template: "Failed to load configuration";
42
139
  }
43
140
  > = {
44
141
  ERR01: "{{ componentName }} failed at {{ phase }}",
45
- INFO01: "Ready",
142
+ ERR02: "Failed to load configuration",
46
143
  };
47
- ```
48
-
49
- ### 2) Create the reporter
50
-
51
- Pass your messages to `createReporter()` to create a reporter instance.
52
144
 
53
- ```ts
54
- import { createReporter } from "runtime-reporter";
145
+ /** The runtime reporter for <project-name> */
146
+ const reporter = createReporter(messages);
55
147
 
56
- export const reporter = createReporter(
57
- // Pass an empty object in production for better security and a smaller bundle size
58
- process.env.NODE_ENV === "production" ? ({} as typeof messages) : messages
59
- );
148
+ export default reporter;
60
149
  ```
61
150
 
62
- ### 3) Use the reporter
63
-
64
- Call the various reporter methods wherever you need them.
151
+ Once your project's reporter is created, you can import and use it wherever you need it.
65
152
 
66
153
  ```ts
67
- reporter.error("ERR01", { componentName: "Router", phase: "mount" });
68
- // logs: "Router failed at mount (ERR01)"
154
+ // src/my-component.ts
69
155
 
70
- reporter.message("INFO01");
71
- // returns: "Ready (INFO01)"
156
+ import { reporter } from "./runtime-reporter";
157
+
158
+ export function MyComponent() {
159
+ useEffect(() => {
160
+ reporter.error("ERR01", { componentName: "MyComponent", phase: "mount" });
161
+ }, []);
162
+
163
+ return <div>My Component</div>;
164
+ }
72
165
  ```
73
166
 
74
167
  ## API
@@ -146,37 +239,20 @@ reporter.error("ERR01", { componentName: "Router", phase: "mount" });
146
239
  The `message` method returns the resolved string without side effects, allowing you to validate precise messaging without duplicating text.
147
240
 
148
241
  ```ts
149
- import { describe, it, expect, vi } from "vitest";
150
- import { reporter } from "./reporter";
151
-
152
- describe("reporter messages", () => {
153
- it("consoles error ERR01 correctly", () => {
154
- vi.spyOn(console, "error").mockImplementation(() => {});
155
- reporter.error("ERR01", { componentName: "Widget" });
156
-
157
- expect(console.error).toHaveBeenCalledWith(
158
- reporter.message("ERR01", { componentName: "Widget" })
159
- );
160
- });
161
- });
162
- ```
163
-
164
- ### Using the reporter without TypeScript
165
-
166
- You can use the reporter without TypeScript, you will just lose the type safety and autocomplete.
242
+ it("should log error if component fails to mount", () => {
243
+ vi.spyOn(console, "error").mockImplementation(() => {});
167
244
 
168
- ```js
169
- import { createReporter } from "runtime-reporter";
245
+ render(<MyComponent />);
170
246
 
171
- const reporter = createReporter({
172
- ERR01: "{{ componentName }} failed at {{ phase }}",
247
+ expect(console.error).toHaveBeenCalledWith(
248
+ reporter.message("ERR01", { componentName: "MyComponent", phase: "mount" })
249
+ );
173
250
  });
174
-
175
- reporter.error("ERR01", { componentName: "Router", phase: "mount" });
176
- // logs: "Router failed at mount (ERR01)"
177
251
  ```
178
252
 
179
- However, you can still get the same benefits as TypeScript by using JSDoc-style type annotations.
253
+ ### Type safety without TypeScript
254
+
255
+ You can still get the same benefits as TypeScript by using JSDoc-style type annotations.
180
256
 
181
257
  ```js
182
258
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "runtime-reporter",
3
- "version": "0.4.0",
4
- "description": "Structured runtime events for applications and frameworks. A composable foundation for logging, messaging, and runtime reporting.",
3
+ "version": "0.4.2",
4
+ "description": "Structured runtime reporting that is type-safe, centralized, and production-ready.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",