@buenojs/bueno 0.8.4 → 0.8.6
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 +264 -17
- package/dist/cli/{index.js → bin.js} +413 -332
- package/dist/container/index.js +273 -0
- package/dist/context/index.js +219 -0
- package/dist/database/index.js +493 -0
- package/dist/frontend/index.js +7697 -0
- package/dist/graphql/index.js +2156 -0
- package/dist/health/index.js +364 -0
- package/dist/i18n/index.js +345 -0
- package/dist/index.js +9694 -5047
- package/dist/jobs/index.js +819 -0
- package/dist/lock/index.js +367 -0
- package/dist/logger/index.js +281 -0
- package/dist/metrics/index.js +289 -0
- package/dist/middleware/index.js +77 -0
- package/dist/migrations/index.js +571 -0
- package/dist/modules/index.js +3411 -0
- package/dist/notification/index.js +484 -0
- package/dist/observability/index.js +331 -0
- package/dist/openapi/index.js +795 -0
- package/dist/orm/index.js +1356 -0
- package/dist/router/index.js +886 -0
- package/dist/rpc/index.js +691 -0
- package/dist/schema/index.js +400 -0
- package/dist/telemetry/index.js +595 -0
- package/dist/template/index.js +640 -0
- package/dist/templates/index.js +640 -0
- package/dist/testing/index.js +1111 -0
- package/dist/types/index.js +60 -0
- package/llms.txt +231 -0
- package/package.json +125 -27
- package/src/cache/index.ts +2 -1
- package/src/cli/ARCHITECTURE.md +3 -3
- package/src/cli/bin.ts +2 -2
- package/src/cli/commands/build.ts +183 -165
- package/src/cli/commands/dev.ts +96 -89
- package/src/cli/commands/generate.ts +142 -111
- package/src/cli/commands/help.ts +20 -16
- package/src/cli/commands/index.ts +3 -6
- package/src/cli/commands/migration.ts +124 -105
- package/src/cli/commands/new.ts +294 -232
- package/src/cli/commands/start.ts +81 -79
- package/src/cli/core/args.ts +68 -50
- package/src/cli/core/console.ts +89 -95
- package/src/cli/core/index.ts +4 -4
- package/src/cli/core/prompt.ts +65 -62
- package/src/cli/core/spinner.ts +23 -20
- package/src/cli/index.ts +46 -38
- package/src/cli/templates/database/index.ts +37 -18
- package/src/cli/templates/database/mysql.ts +3 -3
- package/src/cli/templates/database/none.ts +2 -2
- package/src/cli/templates/database/postgresql.ts +3 -3
- package/src/cli/templates/database/sqlite.ts +3 -3
- package/src/cli/templates/deploy.ts +29 -26
- package/src/cli/templates/docker.ts +41 -30
- package/src/cli/templates/frontend/index.ts +33 -15
- package/src/cli/templates/frontend/none.ts +2 -2
- package/src/cli/templates/frontend/react.ts +18 -18
- package/src/cli/templates/frontend/solid.ts +15 -15
- package/src/cli/templates/frontend/svelte.ts +17 -17
- package/src/cli/templates/frontend/vue.ts +15 -15
- package/src/cli/templates/generators/index.ts +29 -29
- package/src/cli/templates/generators/types.ts +21 -21
- package/src/cli/templates/index.ts +6 -6
- package/src/cli/templates/project/api.ts +37 -36
- package/src/cli/templates/project/default.ts +25 -25
- package/src/cli/templates/project/fullstack.ts +28 -26
- package/src/cli/templates/project/index.ts +55 -16
- package/src/cli/templates/project/minimal.ts +17 -12
- package/src/cli/templates/project/types.ts +10 -5
- package/src/cli/templates/project/website.ts +15 -15
- package/src/cli/utils/fs.ts +55 -41
- package/src/cli/utils/index.ts +3 -3
- package/src/cli/utils/strings.ts +47 -33
- package/src/cli/utils/version.ts +14 -8
- package/src/config/env-validation.ts +100 -0
- package/src/config/env.ts +169 -41
- package/src/config/index.ts +28 -20
- package/src/config/loader.ts +25 -16
- package/src/config/merge.ts +21 -10
- package/src/config/types.ts +566 -25
- package/src/config/validation.ts +215 -7
- package/src/container/forward-ref.ts +22 -22
- package/src/container/index.ts +34 -12
- package/src/context/index.ts +11 -1
- package/src/database/index.ts +7 -190
- package/src/database/orm/builder.ts +457 -0
- package/src/database/orm/casts/index.ts +130 -0
- package/src/database/orm/casts/types.ts +25 -0
- package/src/database/orm/compiler.ts +304 -0
- package/src/database/orm/hooks/index.ts +114 -0
- package/src/database/orm/index.ts +61 -0
- package/src/database/orm/model-registry.ts +59 -0
- package/src/database/orm/model.ts +821 -0
- package/src/database/orm/relationships/base.ts +146 -0
- package/src/database/orm/relationships/belongs-to-many.ts +179 -0
- package/src/database/orm/relationships/belongs-to.ts +56 -0
- package/src/database/orm/relationships/has-many.ts +45 -0
- package/src/database/orm/relationships/has-one.ts +41 -0
- package/src/database/orm/relationships/index.ts +11 -0
- package/src/database/orm/scopes/index.ts +55 -0
- package/src/events/__tests__/event-system.test.ts +235 -0
- package/src/events/config.ts +238 -0
- package/src/events/example-usage.ts +185 -0
- package/src/events/index.ts +278 -0
- package/src/events/manager.ts +385 -0
- package/src/events/registry.ts +182 -0
- package/src/events/types.ts +124 -0
- package/src/frontend/api-routes.ts +65 -23
- package/src/frontend/bundler.ts +76 -34
- package/src/frontend/console-client.ts +2 -2
- package/src/frontend/console-stream.ts +94 -38
- package/src/frontend/dev-server.ts +94 -46
- package/src/frontend/file-router.ts +61 -19
- package/src/frontend/frameworks/index.ts +37 -10
- package/src/frontend/frameworks/react.ts +10 -8
- package/src/frontend/frameworks/solid.ts +11 -9
- package/src/frontend/frameworks/svelte.ts +15 -9
- package/src/frontend/frameworks/vue.ts +13 -11
- package/src/frontend/hmr-client.ts +12 -10
- package/src/frontend/hmr.ts +146 -103
- package/src/frontend/index.ts +14 -5
- package/src/frontend/islands.ts +41 -22
- package/src/frontend/isr.ts +59 -37
- package/src/frontend/layout.ts +36 -21
- package/src/frontend/ssr/react.ts +74 -27
- package/src/frontend/ssr/solid.ts +54 -20
- package/src/frontend/ssr/svelte.ts +48 -14
- package/src/frontend/ssr/vue.ts +50 -18
- package/src/frontend/ssr.ts +83 -39
- package/src/frontend/types.ts +91 -56
- package/src/graphql/built-in-engine.ts +598 -0
- package/src/graphql/context-builder.ts +110 -0
- package/src/graphql/decorators.ts +358 -0
- package/src/graphql/execution-pipeline.ts +227 -0
- package/src/graphql/graphql-module.ts +563 -0
- package/src/graphql/index.ts +101 -0
- package/src/graphql/metadata.ts +237 -0
- package/src/graphql/schema-builder.ts +319 -0
- package/src/graphql/subscription-handler.ts +283 -0
- package/src/graphql/types.ts +324 -0
- package/src/health/index.ts +21 -9
- package/src/i18n/engine.ts +305 -0
- package/src/i18n/index.ts +38 -0
- package/src/i18n/loader.ts +218 -0
- package/src/i18n/middleware.ts +164 -0
- package/src/i18n/negotiator.ts +162 -0
- package/src/i18n/types.ts +158 -0
- package/src/index.ts +182 -27
- package/src/jobs/drivers/memory.ts +315 -0
- package/src/jobs/drivers/redis.ts +459 -0
- package/src/jobs/index.ts +30 -0
- package/src/jobs/queue.ts +281 -0
- package/src/jobs/types.ts +295 -0
- package/src/jobs/worker.ts +380 -0
- package/src/logger/index.ts +1 -3
- package/src/logger/transports/index.ts +62 -22
- package/src/metrics/index.ts +25 -16
- package/src/migrations/index.ts +9 -0
- package/src/modules/filters.ts +13 -17
- package/src/modules/guards.ts +49 -26
- package/src/modules/index.ts +457 -299
- package/src/modules/interceptors.ts +58 -20
- package/src/modules/lazy.ts +11 -19
- package/src/modules/lifecycle.ts +15 -7
- package/src/modules/metadata.ts +15 -5
- package/src/modules/pipes.ts +94 -72
- package/src/notification/channels/base.ts +68 -0
- package/src/notification/channels/email.ts +105 -0
- package/src/notification/channels/push.ts +104 -0
- package/src/notification/channels/sms.ts +105 -0
- package/src/notification/channels/whatsapp.ts +104 -0
- package/src/notification/index.ts +48 -0
- package/src/notification/service.ts +354 -0
- package/src/notification/types.ts +344 -0
- package/src/observability/__tests__/observability.test.ts +483 -0
- package/src/observability/breadcrumbs.ts +114 -0
- package/src/observability/index.ts +136 -0
- package/src/observability/interceptor.ts +85 -0
- package/src/observability/service.ts +303 -0
- package/src/observability/trace.ts +37 -0
- package/src/observability/types.ts +196 -0
- package/src/openapi/__tests__/decorators.test.ts +335 -0
- package/src/openapi/__tests__/document-builder.test.ts +285 -0
- package/src/openapi/__tests__/route-scanner.test.ts +334 -0
- package/src/openapi/__tests__/schema-generator.test.ts +275 -0
- package/src/openapi/decorators.ts +328 -0
- package/src/openapi/document-builder.ts +274 -0
- package/src/openapi/index.ts +112 -0
- package/src/openapi/metadata.ts +112 -0
- package/src/openapi/route-scanner.ts +289 -0
- package/src/openapi/schema-generator.ts +256 -0
- package/src/openapi/swagger-module.ts +166 -0
- package/src/openapi/types.ts +398 -0
- package/src/orm/index.ts +10 -0
- package/src/rpc/index.ts +3 -1
- package/src/schema/index.ts +9 -0
- package/src/security/index.ts +15 -6
- package/src/ssg/index.ts +9 -8
- package/src/telemetry/index.ts +76 -22
- package/src/template/index.ts +7 -0
- package/src/templates/engine.ts +224 -0
- package/src/templates/index.ts +9 -0
- package/src/templates/loader.ts +331 -0
- package/src/templates/renderers/markdown.ts +212 -0
- package/src/templates/renderers/simple.ts +269 -0
- package/src/templates/types.ts +154 -0
- package/src/testing/index.ts +100 -27
- package/src/types/optional-deps.d.ts +347 -187
- package/src/validation/index.ts +92 -2
- package/src/validation/schemas.ts +536 -0
- package/tests/integration/cli.test.ts +19 -19
- package/tests/integration/fullstack.test.ts +4 -4
- package/tests/unit/cli.test.ts +1 -1
- package/tests/unit/database.test.ts +2 -72
- package/tests/unit/env-validation.test.ts +166 -0
- package/tests/unit/events.test.ts +910 -0
- package/tests/unit/graphql.test.ts +991 -0
- package/tests/unit/i18n.test.ts +455 -0
- package/tests/unit/jobs.test.ts +493 -0
- package/tests/unit/notification.test.ts +988 -0
- package/tests/unit/observability.test.ts +453 -0
- package/tests/unit/orm/builder.test.ts +323 -0
- package/tests/unit/orm/casts.test.ts +179 -0
- package/tests/unit/orm/compiler.test.ts +220 -0
- package/tests/unit/orm/eager-loading.test.ts +285 -0
- package/tests/unit/orm/hooks.test.ts +191 -0
- package/tests/unit/orm/model.test.ts +373 -0
- package/tests/unit/orm/relationships.test.ts +303 -0
- package/tests/unit/orm/scopes.test.ts +74 -0
- package/tests/unit/templates-simple.test.ts +53 -0
- package/tests/unit/templates.test.ts +454 -0
- package/tests/unit/validation.test.ts +18 -24
- package/tsconfig.json +11 -3
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createEvent,
|
|
3
|
+
createEventCategory,
|
|
4
|
+
createEventListener,
|
|
5
|
+
createEventManager,
|
|
6
|
+
createEventRegistry,
|
|
7
|
+
deserializeEvent,
|
|
8
|
+
serializeEvent,
|
|
9
|
+
validateEvent,
|
|
10
|
+
} from "../index";
|
|
11
|
+
|
|
12
|
+
describe("Event System", () => {
|
|
13
|
+
let manager: any;
|
|
14
|
+
let registry: any;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
manager = createEventManager();
|
|
18
|
+
registry = createEventRegistry();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("Event Manager", () => {
|
|
22
|
+
it("should emit and handle events", async () => {
|
|
23
|
+
const eventData = { message: "test" };
|
|
24
|
+
const event = createEvent("test.event", eventData);
|
|
25
|
+
|
|
26
|
+
const handler = jest.fn();
|
|
27
|
+
manager.on("test.event", handler);
|
|
28
|
+
|
|
29
|
+
await manager.emit(event);
|
|
30
|
+
|
|
31
|
+
expect(handler).toHaveBeenCalledWith(event);
|
|
32
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should support one-time listeners", async () => {
|
|
36
|
+
const eventData = { message: "test" };
|
|
37
|
+
const event = createEvent("test.event", eventData);
|
|
38
|
+
|
|
39
|
+
const handler = jest.fn();
|
|
40
|
+
manager.once("test.event", handler);
|
|
41
|
+
|
|
42
|
+
await manager.emit(event);
|
|
43
|
+
await manager.emit(event);
|
|
44
|
+
|
|
45
|
+
expect(handler).toHaveBeenCalledWith(event);
|
|
46
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should support event filtering", async () => {
|
|
50
|
+
const eventData1 = { type: "important" };
|
|
51
|
+
const eventData2 = { type: "normal" };
|
|
52
|
+
const event1 = createEvent("test.event", eventData1);
|
|
53
|
+
const event2 = createEvent("test.event", eventData2);
|
|
54
|
+
|
|
55
|
+
const handler = jest.fn();
|
|
56
|
+
const filter = (e: any) => e.data.type === "important";
|
|
57
|
+
manager.on("test.event", handler, { filter });
|
|
58
|
+
|
|
59
|
+
await manager.emit(event1);
|
|
60
|
+
await manager.emit(event2);
|
|
61
|
+
|
|
62
|
+
expect(handler).toHaveBeenCalledWith(event1);
|
|
63
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should support event middleware", async () => {
|
|
67
|
+
const eventData = { message: "test" };
|
|
68
|
+
const event = createEvent("test.event", eventData);
|
|
69
|
+
|
|
70
|
+
const middleware = jest.fn(async (e, next) => {
|
|
71
|
+
e.data.middleware = true;
|
|
72
|
+
await next();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
manager.addMiddleware(middleware);
|
|
76
|
+
const handler = jest.fn();
|
|
77
|
+
manager.on("test.event", handler);
|
|
78
|
+
|
|
79
|
+
await manager.emit(event);
|
|
80
|
+
|
|
81
|
+
expect(middleware).toHaveBeenCalled();
|
|
82
|
+
expect(handler).toHaveBeenCalledWith(event);
|
|
83
|
+
expect(event.data.middleware).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should handle errors gracefully", async () => {
|
|
87
|
+
const eventData = { message: "test" };
|
|
88
|
+
const event = createEvent("test.event", eventData);
|
|
89
|
+
|
|
90
|
+
const failingHandler = jest.fn(() => {
|
|
91
|
+
throw new Error("Test error");
|
|
92
|
+
});
|
|
93
|
+
const successHandler = jest.fn();
|
|
94
|
+
|
|
95
|
+
manager.on("test.event", failingHandler);
|
|
96
|
+
manager.on("test.event", successHandler);
|
|
97
|
+
|
|
98
|
+
await manager.emit(event);
|
|
99
|
+
|
|
100
|
+
expect(failingHandler).toHaveBeenCalled();
|
|
101
|
+
expect(successHandler).toHaveBeenCalled();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should support event categories", () => {
|
|
105
|
+
const category = createEventCategory("database", "Database operations");
|
|
106
|
+
manager.registerEventCategory(category);
|
|
107
|
+
|
|
108
|
+
expect(manager.getEventCategories()).toContainEqual(category);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("Event Registry", () => {
|
|
113
|
+
it("should register and retrieve events", () => {
|
|
114
|
+
const eventData = { message: "test" };
|
|
115
|
+
const event = createEvent("test.event", eventData);
|
|
116
|
+
|
|
117
|
+
registry.registerEvent(event);
|
|
118
|
+
|
|
119
|
+
expect(registry.getEvent(event.id)).toEqual(event);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should support event cleanup", () => {
|
|
123
|
+
const eventData = { message: "test" };
|
|
124
|
+
const event = createEvent("test.event", eventData, {
|
|
125
|
+
timestamp: new Date(Date.now() - 25 * 60 * 60 * 1000), // 25 hours ago
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
registry.registerEvent(event);
|
|
129
|
+
registry.cleanupOldEvents();
|
|
130
|
+
|
|
131
|
+
expect(registry.getEvent(event.id)).toBeUndefined();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("should support event search", () => {
|
|
135
|
+
const event1 = createEvent("user.created", { name: "John" });
|
|
136
|
+
const event2 = createEvent("user.deleted", { name: "Jane" });
|
|
137
|
+
|
|
138
|
+
registry.registerEvent(event1);
|
|
139
|
+
registry.registerEvent(event2);
|
|
140
|
+
|
|
141
|
+
const results = registry.searchEvents("user");
|
|
142
|
+
|
|
143
|
+
expect(results).toHaveLength(2);
|
|
144
|
+
expect(results).toContainEqual(event1);
|
|
145
|
+
expect(results).toContainEqual(event2);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("should support event history", () => {
|
|
149
|
+
const events = [
|
|
150
|
+
createEvent(
|
|
151
|
+
"test.event",
|
|
152
|
+
{ count: 1 },
|
|
153
|
+
{ timestamp: new Date(Date.now() - 3000) },
|
|
154
|
+
),
|
|
155
|
+
createEvent(
|
|
156
|
+
"test.event",
|
|
157
|
+
{ count: 2 },
|
|
158
|
+
{ timestamp: new Date(Date.now() - 2000) },
|
|
159
|
+
),
|
|
160
|
+
createEvent(
|
|
161
|
+
"test.event",
|
|
162
|
+
{ count: 3 },
|
|
163
|
+
{ timestamp: new Date(Date.now() - 1000) },
|
|
164
|
+
),
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
events.forEach((event) => registry.registerEvent(event));
|
|
168
|
+
|
|
169
|
+
const history = registry.getEventHistory({
|
|
170
|
+
category: undefined,
|
|
171
|
+
startTime: new Date(Date.now() - 60 * 60 * 1000),
|
|
172
|
+
endTime: new Date(),
|
|
173
|
+
limit: 2,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
expect(history).toHaveLength(2);
|
|
177
|
+
expect(history[0].data.count).toBe(3);
|
|
178
|
+
expect(history[1].data.count).toBe(2);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe("Event Utilities", () => {
|
|
183
|
+
it("should create valid events", () => {
|
|
184
|
+
const eventData = { message: "test" };
|
|
185
|
+
const event = createEvent("test.event", eventData);
|
|
186
|
+
|
|
187
|
+
expect(event).toHaveProperty("id");
|
|
188
|
+
expect(event).toHaveProperty("name", "test.event");
|
|
189
|
+
expect(event).toHaveProperty("timestamp");
|
|
190
|
+
expect(event).toHaveProperty("data", eventData);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("should validate events", () => {
|
|
194
|
+
const validEvent = createEvent("test.event", { message: "test" });
|
|
195
|
+
const invalidEvent = { name: "test", data: {} };
|
|
196
|
+
|
|
197
|
+
expect(validateEvent(validEvent)).toBe(true);
|
|
198
|
+
expect(validateEvent(invalidEvent)).toBe(false);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("should serialize and deserialize events", () => {
|
|
202
|
+
const eventData = { message: "test" };
|
|
203
|
+
const event = createEvent("test.event", eventData);
|
|
204
|
+
const serialized = serializeEvent(event);
|
|
205
|
+
const deserialized = deserializeEvent(serialized);
|
|
206
|
+
|
|
207
|
+
expect(deserialized).toEqual(event);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should create event listeners", () => {
|
|
211
|
+
const handler = () => {};
|
|
212
|
+
const listener = createEventListener("test.listener", handler, {
|
|
213
|
+
priority: 10,
|
|
214
|
+
once: true,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
expect(listener).toHaveProperty("id");
|
|
218
|
+
expect(listener).toHaveProperty("name", "test.listener");
|
|
219
|
+
expect(listener).toHaveProperty("handler", handler);
|
|
220
|
+
expect(listener).toHaveProperty("priority", 10);
|
|
221
|
+
expect(listener).toHaveProperty("once", true);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("should create event categories", () => {
|
|
225
|
+
const category = createEventCategory("database", "Database operations", [
|
|
226
|
+
"query",
|
|
227
|
+
"mutation",
|
|
228
|
+
]);
|
|
229
|
+
|
|
230
|
+
expect(category).toHaveProperty("name", "database");
|
|
231
|
+
expect(category).toHaveProperty("description", "Database operations");
|
|
232
|
+
expect(category).toHaveProperty("events", ["query", "mutation"]);
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
});
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EventManagerConfig,
|
|
3
|
+
type EventManagerOptions,
|
|
4
|
+
type EventRegistryOptions,
|
|
5
|
+
} from "./types";
|
|
6
|
+
|
|
7
|
+
export interface EventSystemConfig {
|
|
8
|
+
manager: EventManagerOptions;
|
|
9
|
+
registry: EventRegistryOptions;
|
|
10
|
+
defaultContext?: EventContext;
|
|
11
|
+
errorHandling?: "throw" | "log" | "ignore";
|
|
12
|
+
maxEventSize?: number;
|
|
13
|
+
eventCategories?: EventCategory[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const defaultEventSystemConfig: EventSystemConfig = {
|
|
17
|
+
manager: {
|
|
18
|
+
maxListeners: 100,
|
|
19
|
+
errorHandling: "log",
|
|
20
|
+
},
|
|
21
|
+
registry: {
|
|
22
|
+
maxEvents: 1000,
|
|
23
|
+
retentionPeriod: 24 * 60 * 60 * 1000, // 24 hours
|
|
24
|
+
cleanupInterval: 60 * 60 * 1000, // 1 hour
|
|
25
|
+
},
|
|
26
|
+
defaultContext: {
|
|
27
|
+
userId: undefined,
|
|
28
|
+
sessionId: undefined,
|
|
29
|
+
requestId: undefined,
|
|
30
|
+
ipAddress: undefined,
|
|
31
|
+
userAgent: undefined,
|
|
32
|
+
},
|
|
33
|
+
errorHandling: "log",
|
|
34
|
+
maxEventSize: 1024 * 1024, // 1MB
|
|
35
|
+
eventCategories: [
|
|
36
|
+
{
|
|
37
|
+
name: "database",
|
|
38
|
+
description: "Database operations and query lifecycle",
|
|
39
|
+
events: ["query", "mutation", "connection", "transaction"],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "job-queue",
|
|
43
|
+
description: "Background job processing and queue management",
|
|
44
|
+
events: ["job.created", "job.started", "job.completed", "job.failed"],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "notification",
|
|
48
|
+
description: "Multi-channel notification system",
|
|
49
|
+
events: [
|
|
50
|
+
"notification.sent",
|
|
51
|
+
"notification.delivered",
|
|
52
|
+
"notification.failed",
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "websocket",
|
|
57
|
+
description: "Real-time WebSocket communication",
|
|
58
|
+
events: ["connection", "message", "disconnection", "error"],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "http-rpc",
|
|
62
|
+
description: "HTTP and RPC request/response handling",
|
|
63
|
+
events: ["request.received", "response.sent", "error"],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "system",
|
|
67
|
+
description: "System-level events and health checks",
|
|
68
|
+
events: ["startup", "shutdown", "health.check"],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "cache",
|
|
72
|
+
description: "Caching operations and invalidation",
|
|
73
|
+
events: ["cache.set", "cache.get", "cache.delete", "cache.miss"],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "validation",
|
|
77
|
+
description: "Data validation and sanitization",
|
|
78
|
+
events: ["validation.passed", "validation.failed"],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "security",
|
|
82
|
+
description: "Security and authentication events",
|
|
83
|
+
events: ["login", "logout", "permission.granted", "permission.denied"],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "logging",
|
|
87
|
+
description: "Application logging and monitoring",
|
|
88
|
+
events: ["log.info", "log.warn", "log.error", "log.debug"],
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export function createEventSystemConfig(
|
|
94
|
+
customConfig: Partial<EventSystemConfig> = {},
|
|
95
|
+
): EventSystemConfig {
|
|
96
|
+
return {
|
|
97
|
+
...defaultEventSystemConfig,
|
|
98
|
+
...customConfig,
|
|
99
|
+
manager: {
|
|
100
|
+
...defaultEventSystemConfig.manager,
|
|
101
|
+
...customConfig.manager,
|
|
102
|
+
},
|
|
103
|
+
registry: {
|
|
104
|
+
...defaultEventSystemConfig.registry,
|
|
105
|
+
...customConfig.registry,
|
|
106
|
+
},
|
|
107
|
+
defaultContext: {
|
|
108
|
+
...defaultEventSystemConfig.defaultContext,
|
|
109
|
+
...customConfig.defaultContext,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function validateEventSystemConfig(config: EventSystemConfig): boolean {
|
|
115
|
+
if (!config || typeof config !== "object") return false;
|
|
116
|
+
|
|
117
|
+
// Validate manager config
|
|
118
|
+
if (!config.manager || typeof config.manager !== "object") return false;
|
|
119
|
+
if (
|
|
120
|
+
config.manager.maxListeners !== undefined &&
|
|
121
|
+
(typeof config.manager.maxListeners !== "number" ||
|
|
122
|
+
config.manager.maxListeners < 0)
|
|
123
|
+
) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Validate registry config
|
|
128
|
+
if (!config.registry || typeof config.registry !== "object") return false;
|
|
129
|
+
if (
|
|
130
|
+
config.registry.maxEvents !== undefined &&
|
|
131
|
+
(typeof config.registry.maxEvents !== "number" ||
|
|
132
|
+
config.registry.maxEvents < 0)
|
|
133
|
+
) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (
|
|
137
|
+
config.registry.retentionPeriod !== undefined &&
|
|
138
|
+
(typeof config.registry.retentionPeriod !== "number" ||
|
|
139
|
+
config.registry.retentionPeriod < 0)
|
|
140
|
+
) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
if (
|
|
144
|
+
config.registry.cleanupInterval !== undefined &&
|
|
145
|
+
(typeof config.registry.cleanupInterval !== "number" ||
|
|
146
|
+
config.registry.cleanupInterval < 0)
|
|
147
|
+
) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Validate error handling
|
|
152
|
+
if (
|
|
153
|
+
config.errorHandling &&
|
|
154
|
+
!["throw", "log", "ignore"].includes(config.errorHandling)
|
|
155
|
+
) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Validate max event size
|
|
160
|
+
if (
|
|
161
|
+
config.maxEventSize !== undefined &&
|
|
162
|
+
(typeof config.maxEventSize !== "number" || config.maxEventSize < 0)
|
|
163
|
+
) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Validate event categories
|
|
168
|
+
if (config.eventCategories) {
|
|
169
|
+
for (const category of config.eventCategories) {
|
|
170
|
+
if (!category.name || typeof category.name !== "string") return false;
|
|
171
|
+
if (!category.description || typeof category.description !== "string")
|
|
172
|
+
return false;
|
|
173
|
+
if (category.events && !Array.isArray(category.events)) return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function loadEventSystemConfig(
|
|
181
|
+
configPath = "./config/event-system.json",
|
|
182
|
+
): EventSystemConfig {
|
|
183
|
+
try {
|
|
184
|
+
const config = require(configPath);
|
|
185
|
+
if (validateEventSystemConfig(config)) {
|
|
186
|
+
return config;
|
|
187
|
+
}
|
|
188
|
+
console.warn("Invalid event system config, using defaults");
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.warn("Could not load event system config, using defaults");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return defaultEventSystemConfig;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function saveEventSystemConfig(
|
|
197
|
+
config: EventSystemConfig,
|
|
198
|
+
configPath = "./config/event-system.json",
|
|
199
|
+
): boolean {
|
|
200
|
+
try {
|
|
201
|
+
const fs = require("fs");
|
|
202
|
+
const path = require("path");
|
|
203
|
+
|
|
204
|
+
const dir = path.dirname(configPath);
|
|
205
|
+
if (!fs.existsSync(dir)) {
|
|
206
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
210
|
+
return true;
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error("Failed to save event system config:", error);
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function mergeEventSystemConfigs(
|
|
218
|
+
...configs: Partial<EventSystemConfig>[]
|
|
219
|
+
): EventSystemConfig {
|
|
220
|
+
return configs.reduce((merged, config) => {
|
|
221
|
+
return {
|
|
222
|
+
...merged,
|
|
223
|
+
...config,
|
|
224
|
+
manager: {
|
|
225
|
+
...merged.manager,
|
|
226
|
+
...config.manager,
|
|
227
|
+
},
|
|
228
|
+
registry: {
|
|
229
|
+
...merged.registry,
|
|
230
|
+
...config.registry,
|
|
231
|
+
},
|
|
232
|
+
defaultContext: {
|
|
233
|
+
...merged.defaultContext,
|
|
234
|
+
...config.defaultContext,
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}, defaultEventSystemConfig);
|
|
238
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createEvent,
|
|
3
|
+
createEventCategory,
|
|
4
|
+
createEventContext,
|
|
5
|
+
createEventFilter,
|
|
6
|
+
createEventListener,
|
|
7
|
+
createEventManager,
|
|
8
|
+
createEventMiddleware,
|
|
9
|
+
createEventRegistry,
|
|
10
|
+
} from "./index";
|
|
11
|
+
|
|
12
|
+
// Create event manager and registry
|
|
13
|
+
const manager = createEventManager({
|
|
14
|
+
maxListeners: 200,
|
|
15
|
+
errorHandling: "log",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const registry = createEventRegistry({
|
|
19
|
+
maxEvents: 5000,
|
|
20
|
+
retentionPeriod: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Register event categories
|
|
24
|
+
const databaseCategory = createEventCategory(
|
|
25
|
+
"database",
|
|
26
|
+
"Database operations and query lifecycle",
|
|
27
|
+
["query", "mutation", "connection", "transaction"],
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const jobQueueCategory = createEventCategory(
|
|
31
|
+
"job-queue",
|
|
32
|
+
"Background job processing and queue management",
|
|
33
|
+
["job.created", "job.started", "job.completed", "job.failed"],
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
manager.registerEventCategory(databaseCategory);
|
|
37
|
+
manager.registerEventCategory(jobQueueCategory);
|
|
38
|
+
|
|
39
|
+
// Create event context
|
|
40
|
+
const defaultContext = createEventContext({
|
|
41
|
+
userId: "user123",
|
|
42
|
+
sessionId: "session456",
|
|
43
|
+
ipAddress: "192.168.1.1",
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Create event middleware
|
|
47
|
+
const loggingMiddleware = createEventMiddleware(async (event, next) => {
|
|
48
|
+
console.log(`Event received: ${event.name}`);
|
|
49
|
+
await next();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const validationMiddleware = createEventMiddleware(async (event, next) => {
|
|
53
|
+
if (event.data && typeof event.data === "object") {
|
|
54
|
+
// Validate event data
|
|
55
|
+
if (Object.keys(event.data).length === 0) {
|
|
56
|
+
throw new Error("Event data cannot be empty");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
await next();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
manager.addMiddleware(loggingMiddleware);
|
|
63
|
+
manager.addMiddleware(validationMiddleware);
|
|
64
|
+
|
|
65
|
+
// Create event listeners
|
|
66
|
+
const queryListener = createEventListener(
|
|
67
|
+
"database.query",
|
|
68
|
+
async (event) => {
|
|
69
|
+
console.log("Query executed:", event.data.query);
|
|
70
|
+
// Log query to database
|
|
71
|
+
registry.registerEvent(event);
|
|
72
|
+
},
|
|
73
|
+
{ priority: 10 },
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const jobStartedListener = createEventListener("job.started", async (event) => {
|
|
77
|
+
console.log(`Job started: ${event.data.jobId}`);
|
|
78
|
+
// Update job status
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const errorListener = createEventListener(
|
|
82
|
+
"error",
|
|
83
|
+
async (event) => {
|
|
84
|
+
console.error("Error occurred:", event.data.error);
|
|
85
|
+
},
|
|
86
|
+
{ priority: 100 },
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// Add listeners to manager
|
|
90
|
+
manager.addListener(queryListener);
|
|
91
|
+
manager.addListener(jobStartedListener);
|
|
92
|
+
manager.addListener(errorListener);
|
|
93
|
+
|
|
94
|
+
// Create event filters
|
|
95
|
+
const importantFilter = createEventFilter((event) => {
|
|
96
|
+
return event.data && event.data.importance === "high";
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Create filtered listener
|
|
100
|
+
const importantEventListener = createEventListener(
|
|
101
|
+
"important.event",
|
|
102
|
+
async (event) => {
|
|
103
|
+
console.log("Important event detected:", event.data);
|
|
104
|
+
// Send alert or notification
|
|
105
|
+
},
|
|
106
|
+
{ filter: importantFilter },
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
manager.addListener(importantEventListener);
|
|
110
|
+
|
|
111
|
+
// Example event emission
|
|
112
|
+
async function exampleUsage() {
|
|
113
|
+
try {
|
|
114
|
+
// Database query event
|
|
115
|
+
const queryEvent = createEvent(
|
|
116
|
+
"database.query",
|
|
117
|
+
{
|
|
118
|
+
query: "SELECT * FROM users WHERE id = 1",
|
|
119
|
+
executionTime: 120,
|
|
120
|
+
},
|
|
121
|
+
{ context: defaultContext },
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
await manager.emit(queryEvent);
|
|
125
|
+
|
|
126
|
+
// Job started event
|
|
127
|
+
const jobEvent = createEvent(
|
|
128
|
+
"job.started",
|
|
129
|
+
{
|
|
130
|
+
jobId: "job789",
|
|
131
|
+
type: "email-sender",
|
|
132
|
+
data: { userId: "user123" },
|
|
133
|
+
},
|
|
134
|
+
{ context: defaultContext },
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
await manager.emit(jobEvent);
|
|
138
|
+
|
|
139
|
+
// Important event
|
|
140
|
+
const importantEvent = createEvent(
|
|
141
|
+
"important.event",
|
|
142
|
+
{
|
|
143
|
+
message: "System alert",
|
|
144
|
+
importance: "high",
|
|
145
|
+
details: "High memory usage detected",
|
|
146
|
+
},
|
|
147
|
+
{ context: defaultContext },
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
await manager.emit(importantEvent);
|
|
151
|
+
|
|
152
|
+
// Error event
|
|
153
|
+
const errorEvent = createEvent(
|
|
154
|
+
"error",
|
|
155
|
+
{
|
|
156
|
+
error: new Error("Test error"),
|
|
157
|
+
source: "example-usage",
|
|
158
|
+
},
|
|
159
|
+
{ context: defaultContext },
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
await manager.emit(errorEvent);
|
|
163
|
+
|
|
164
|
+
console.log("All events processed successfully!");
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error("Error in example usage:", error);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Run example
|
|
171
|
+
exampleUsage();
|
|
172
|
+
|
|
173
|
+
// Export for use in other modules
|
|
174
|
+
export {
|
|
175
|
+
manager,
|
|
176
|
+
registry,
|
|
177
|
+
defaultContext,
|
|
178
|
+
loggingMiddleware,
|
|
179
|
+
validationMiddleware,
|
|
180
|
+
queryListener,
|
|
181
|
+
jobStartedListener,
|
|
182
|
+
errorListener,
|
|
183
|
+
importantFilter,
|
|
184
|
+
importantEventListener,
|
|
185
|
+
};
|