create-nexwire 4.2.5 → 4.3.0

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 (85) hide show
  1. package/README.md +20 -8
  2. package/express/.env +1 -1
  3. package/express/package.json +1 -1
  4. package/express/src/config/database.ts +48 -29
  5. package/express/src/config/index.ts +83 -83
  6. package/express/src/config/openapi.ts +6 -24
  7. package/express/src/config/queue.ts +30 -30
  8. package/express/src/config/validate.ts +50 -40
  9. package/express/src/database/migrations/sqlite/0000_init.sql +47 -47
  10. package/express/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  11. package/express/src/database/migrations/sqlite/meta/_journal.json +1 -1
  12. package/express/src/framework/cache/cache.ts +40 -8
  13. package/express/src/framework/circuit-breaker/cb.ts +88 -60
  14. package/express/src/framework/database/connection.ts +52 -27
  15. package/express/src/framework/events/dispatcher.ts +61 -49
  16. package/express/src/framework/facade.ts +46 -3
  17. package/express/src/framework/http/app.ts +28 -22
  18. package/express/src/framework/http/logger.ts +27 -16
  19. package/express/src/framework/http/openapi.ts +9 -11
  20. package/express/src/framework/modules/routes.ts +26 -21
  21. package/express/src/framework/notification/channels/broadcast.ts +15 -0
  22. package/express/src/framework/notification/channels/mail.ts +40 -0
  23. package/express/src/framework/notification/contracts.ts +29 -0
  24. package/express/src/framework/notification/index.ts +19 -94
  25. package/express/src/framework/notification/registry.ts +15 -0
  26. package/express/src/framework/providers/adapter.ts +27 -17
  27. package/express/src/framework/queue/queue.ts +43 -44
  28. package/express/src/framework/realtime/broadcast.ts +29 -5
  29. package/express/src/framework/realtime/socket.ts +149 -119
  30. package/express/src/framework/redis/client.ts +148 -151
  31. package/express/src/framework/runtime/server-adapter.ts +39 -34
  32. package/express/src/framework/scheduler/lock.ts +128 -116
  33. package/express/src/framework/server.ts +33 -49
  34. package/express/src/framework/session/session.ts +69 -14
  35. package/express/src/framework/storage/storage.ts +744 -785
  36. package/express/src/framework/support/mail.ts +15 -7
  37. package/express/src/providers/notification.ts +4 -0
  38. package/express/src/resources/src/layouts/Layout/Header.vue +124 -105
  39. package/express/src/resources/src/plugins/pulse.ts +157 -147
  40. package/express/src/resources/vite.config.ts +54 -43
  41. package/express/src/storage/database/nexwire.sqlite +0 -0
  42. package/express/src/storage/logs/app.log +0 -0
  43. package/express/src/storage/logs/fatal.log +0 -0
  44. package/express/src/types/global.d.ts +32 -26
  45. package/hono/.env +1 -1
  46. package/hono/package.json +1 -1
  47. package/hono/src/config/database.ts +48 -29
  48. package/hono/src/config/index.ts +83 -83
  49. package/hono/src/config/openapi.ts +6 -24
  50. package/hono/src/config/queue.ts +30 -30
  51. package/hono/src/config/validate.ts +50 -40
  52. package/hono/src/database/migrations/sqlite/0000_init.sql +47 -47
  53. package/hono/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  54. package/hono/src/database/migrations/sqlite/meta/_journal.json +1 -1
  55. package/hono/src/framework/cache/cache.ts +40 -8
  56. package/hono/src/framework/circuit-breaker/cb.ts +88 -60
  57. package/hono/src/framework/database/connection.ts +52 -27
  58. package/hono/src/framework/events/dispatcher.ts +61 -49
  59. package/hono/src/framework/facade.ts +38 -1
  60. package/hono/src/framework/http/openapi.ts +7 -9
  61. package/hono/src/framework/notification/channels/broadcast.ts +15 -0
  62. package/hono/src/framework/notification/channels/mail.ts +40 -0
  63. package/hono/src/framework/notification/contracts.ts +29 -0
  64. package/hono/src/framework/notification/index.ts +19 -94
  65. package/hono/src/framework/notification/registry.ts +15 -0
  66. package/hono/src/framework/providers/adapter.ts +27 -17
  67. package/hono/src/framework/queue/queue.ts +43 -44
  68. package/hono/src/framework/realtime/broadcast.ts +29 -5
  69. package/hono/src/framework/realtime/socket.ts +217 -196
  70. package/hono/src/framework/redis/client.ts +148 -151
  71. package/hono/src/framework/scheduler/lock.ts +128 -116
  72. package/hono/src/framework/server.ts +27 -29
  73. package/hono/src/framework/session/session.ts +62 -14
  74. package/hono/src/framework/storage/storage.ts +744 -785
  75. package/hono/src/framework/support/mail.ts +56 -48
  76. package/hono/src/providers/notification.ts +4 -0
  77. package/hono/src/resources/src/layouts/Layout/Header.vue +124 -105
  78. package/hono/src/resources/src/plugins/pulse.ts +157 -147
  79. package/hono/src/resources/vite.config.ts +54 -43
  80. package/hono/src/storage/database/nexwire.sqlite +0 -0
  81. package/hono/src/storage/logs/app.log +0 -0
  82. package/hono/src/storage/logs/fatal.log +0 -0
  83. package/hono/src/types/global.d.ts +32 -26
  84. package/package.json +2 -2
  85. package/src/index.js +139 -14
@@ -2,8 +2,16 @@ import { randomUUID } from "node:crypto";
2
2
  import type { Context, Next } from "hono";
3
3
  import { getCookie, setCookie } from "hono/cookie";
4
4
  import { appConfig, redisConfig, sessionConfig } from "@/config/index.js";
5
+ import { createCircuitBreaker, isCircuitBreakerError } from "@/framework/circuit-breaker/cb.js";
5
6
  import { redisClientIfReady } from "@/framework/redis/client.js";
6
7
 
8
+ // Initialize the breaker for Session operations
9
+ const sessionBreaker = createCircuitBreaker({
10
+ name: "Redis Session",
11
+ failureThreshold: 3,
12
+ resetTimeout: 30000
13
+ });
14
+
7
15
  /** Extract origin from a URL string. Returns empty string on invalid/missing input. */
8
16
  function originOf(url?: string) {
9
17
  if (!url) return "";
@@ -60,9 +68,16 @@ export const session = {
60
68
  const client = redisClientIfReady();
61
69
  if (!client) return "";
62
70
 
63
- const id = randomUUID();
64
- await client.set(sessionKey(id), JSON.stringify(data), "EX", sessionConfig.ttlSeconds);
65
- return id;
71
+ try {
72
+ return await sessionBreaker.exec(async () => {
73
+ const id = randomUUID();
74
+ await client.set(sessionKey(id), JSON.stringify(data), "EX", sessionConfig.ttlSeconds);
75
+ return id;
76
+ });
77
+ } catch (error) {
78
+ if (isCircuitBreakerError(error)) return "";
79
+ return "";
80
+ }
66
81
  },
67
82
 
68
83
  /** Get the full session payload for a given id. Returns null when session doesn't exist or Redis is unavailable. */
@@ -70,8 +85,15 @@ export const session = {
70
85
  const client = redisClientIfReady();
71
86
  if (!client) return null;
72
87
 
73
- const data = await client.get(sessionKey(id));
74
- return data ? JSON.parse(data) : null;
88
+ try {
89
+ return await sessionBreaker.exec(async () => {
90
+ const data = await client.get(sessionKey(id));
91
+ return data ? (JSON.parse(data) as T) : null;
92
+ });
93
+ } catch (error) {
94
+ if (isCircuitBreakerError(error)) return null;
95
+ return null;
96
+ }
75
97
  },
76
98
 
77
99
  /** Read a single key from the session payload. Returns null if the key or session doesn't exist. */
@@ -85,10 +107,22 @@ export const session = {
85
107
  const client = redisClientIfReady();
86
108
  if (!client) return false;
87
109
 
88
- const data = (await session.all<Record<string, unknown>>(id)) || {};
89
- data[key] = value;
90
- await client.set(sessionKey(id), JSON.stringify(data), "EX", sessionConfig.ttlSeconds);
91
- return true;
110
+ try {
111
+ return await sessionBreaker.exec(async () => {
112
+ // Read through the client directly rather than `session.all()`. Calling
113
+ // another breaker-wrapped method from inside `exec` deadlocks the
114
+ // half-open probe: the inner call sees the outer probe in flight and
115
+ // rejects, so a `set` could never be the call that closes the breaker.
116
+ const raw = await client.get(sessionKey(id));
117
+ const data = raw ? (JSON.parse(raw) as Record<string, unknown>) : {};
118
+ data[key] = value;
119
+ await client.set(sessionKey(id), JSON.stringify(data), "EX", sessionConfig.ttlSeconds);
120
+ return true;
121
+ });
122
+ } catch (error) {
123
+ if (isCircuitBreakerError(error)) return false;
124
+ return false;
125
+ }
92
126
  },
93
127
 
94
128
  /** @deprecated Use set() instead. */
@@ -101,8 +135,15 @@ export const session = {
101
135
  const client = redisClientIfReady();
102
136
  if (!client) return false;
103
137
 
104
- await client.expire(sessionKey(id), sessionConfig.ttlSeconds);
105
- return true;
138
+ try {
139
+ return await sessionBreaker.exec(async () => {
140
+ await client.expire(sessionKey(id), sessionConfig.ttlSeconds);
141
+ return true;
142
+ });
143
+ } catch (error) {
144
+ if (isCircuitBreakerError(error)) return false;
145
+ return false;
146
+ }
106
147
  },
107
148
 
108
149
  /** Delete a session document from Redis. Use on logout or session expiry. Returns false when Redis is unavailable. */
@@ -110,12 +151,19 @@ export const session = {
110
151
  const client = redisClientIfReady();
111
152
  if (!client) return false;
112
153
 
113
- await client.del(sessionKey(id));
114
- return true;
154
+ try {
155
+ return await sessionBreaker.exec(async () => {
156
+ await client.del(sessionKey(id));
157
+ return true;
158
+ });
159
+ } catch (error) {
160
+ if (isCircuitBreakerError(error)) return false;
161
+ return false;
162
+ }
115
163
  },
116
164
 
117
165
  /** Returns true when Redis is enabled and the Redis client is ready — guards against using session store without Redis. */
118
166
  isAvailable() {
119
- return redisConfig.enabled && redisClientIfReady() !== null;
167
+ return redisConfig.enabled && redisClientIfReady() !== null && sessionBreaker.getState() !== "open";
120
168
  }
121
169
  };