create-nexwire 4.2.4 → 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.
- package/README.md +20 -8
- package/express/.env +1 -1
- package/express/.vscode/extensions.json +6 -0
- package/express/.vscode/settings.json +37 -26
- package/express/biome.json +99 -66
- package/express/package.json +31 -29
- package/express/src/config/database.ts +48 -29
- package/express/src/config/index.ts +83 -83
- package/express/src/config/openapi.ts +6 -24
- package/express/src/config/queue.ts +30 -30
- package/express/src/config/validate.ts +50 -40
- package/express/src/database/migrations/sqlite/0000_init.sql +47 -47
- package/express/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
- package/express/src/database/migrations/sqlite/meta/_journal.json +1 -1
- package/express/src/database/schema.ts +2 -2
- package/express/src/framework/cache/cache.ts +40 -8
- package/express/src/framework/circuit-breaker/cb.ts +88 -60
- package/express/src/framework/database/connection.ts +52 -27
- package/express/src/framework/events/dispatcher.ts +61 -49
- package/express/src/framework/facade.ts +46 -3
- package/express/src/framework/http/app.ts +28 -22
- package/express/src/framework/http/logger.ts +27 -16
- package/express/src/framework/http/openapi.ts +9 -11
- package/express/src/framework/modules/routes.ts +26 -21
- package/express/src/framework/notification/channels/broadcast.ts +15 -0
- package/express/src/framework/notification/channels/mail.ts +40 -0
- package/express/src/framework/notification/contracts.ts +29 -0
- package/express/src/framework/notification/index.ts +19 -94
- package/express/src/framework/notification/registry.ts +15 -0
- package/express/src/framework/providers/adapter.ts +27 -17
- package/express/src/framework/queue/queue.ts +43 -44
- package/express/src/framework/realtime/broadcast.ts +29 -5
- package/express/src/framework/realtime/socket.ts +149 -119
- package/express/src/framework/redis/client.ts +148 -151
- package/express/src/framework/runtime/server-adapter.ts +39 -34
- package/express/src/framework/scheduler/lock.ts +128 -116
- package/express/src/framework/server.ts +33 -49
- package/express/src/framework/session/session.ts +69 -14
- package/express/src/framework/storage/storage.ts +744 -785
- package/express/src/framework/support/mail.ts +15 -7
- package/express/src/providers/notification.ts +4 -0
- package/express/src/resources/src/components/Checkbox.vue +32 -29
- package/express/src/resources/src/components/Input.vue +243 -223
- package/express/src/resources/src/components/InputGroup.vue +147 -145
- package/express/src/resources/src/components/InputPasswordToggle.vue +229 -213
- package/express/src/resources/src/components/Modal.vue +71 -55
- package/express/src/resources/src/components/Refresh.vue +19 -0
- package/express/src/resources/src/helpers/assets.ts +51 -0
- package/express/src/resources/src/layouts/Layout/Header.vue +124 -105
- package/express/src/resources/src/main.ts +3 -1
- package/express/src/resources/src/plugins/gum.ts +1 -1
- package/express/src/resources/src/plugins/pulse.ts +157 -147
- package/express/src/resources/src/stores/auth.ts +184 -164
- package/express/src/resources/vite.config.ts +54 -36
- package/express/src/storage/database/nexwire.sqlite +0 -0
- package/express/src/storage/logs/app.log +0 -0
- package/express/src/storage/logs/fatal.log +0 -0
- package/express/src/types/global.d.ts +32 -26
- package/hono/.env +1 -1
- package/hono/.vscode/extensions.json +6 -0
- package/hono/.vscode/settings.json +37 -26
- package/hono/biome.json +25 -2
- package/hono/package.json +25 -23
- package/hono/src/config/database.ts +48 -29
- package/hono/src/config/index.ts +83 -83
- package/hono/src/config/openapi.ts +6 -24
- package/hono/src/config/queue.ts +30 -30
- package/hono/src/config/validate.ts +50 -40
- package/hono/src/database/migrations/sqlite/0000_init.sql +47 -47
- package/hono/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
- package/hono/src/database/migrations/sqlite/meta/_journal.json +1 -1
- package/hono/src/database/schema.ts +2 -2
- package/hono/src/framework/cache/cache.ts +40 -8
- package/hono/src/framework/circuit-breaker/cb.ts +88 -60
- package/hono/src/framework/database/connection.ts +52 -27
- package/hono/src/framework/events/dispatcher.ts +61 -49
- package/hono/src/framework/facade.ts +38 -1
- package/hono/src/framework/http/openapi.ts +7 -9
- package/hono/src/framework/notification/channels/broadcast.ts +15 -0
- package/hono/src/framework/notification/channels/mail.ts +40 -0
- package/hono/src/framework/notification/contracts.ts +29 -0
- package/hono/src/framework/notification/index.ts +19 -94
- package/hono/src/framework/notification/registry.ts +15 -0
- package/hono/src/framework/providers/adapter.ts +27 -17
- package/hono/src/framework/queue/queue.ts +43 -44
- package/hono/src/framework/realtime/broadcast.ts +29 -5
- package/hono/src/framework/realtime/socket.ts +217 -196
- package/hono/src/framework/redis/client.ts +148 -151
- package/hono/src/framework/scheduler/lock.ts +128 -116
- package/hono/src/framework/server.ts +27 -29
- package/hono/src/framework/session/session.ts +62 -14
- package/hono/src/framework/storage/storage.ts +744 -785
- package/hono/src/framework/support/mail.ts +56 -48
- package/hono/src/providers/notification.ts +4 -0
- package/hono/src/resources/src/components/Checkbox.vue +32 -29
- package/hono/src/resources/src/components/Input.vue +243 -234
- package/hono/src/resources/src/components/InputGroup.vue +147 -149
- package/hono/src/resources/src/components/InputPasswordToggle.vue +229 -222
- package/hono/src/resources/src/components/Modal.vue +71 -55
- package/hono/src/resources/src/components/Refresh.vue +19 -0
- package/hono/src/resources/src/helpers/assets.ts +51 -0
- package/hono/src/resources/src/layouts/Layout/Header.vue +124 -105
- package/hono/src/resources/src/main.ts +3 -1
- package/hono/src/resources/src/plugins/gum.ts +1 -1
- package/hono/src/resources/src/plugins/pulse.ts +157 -147
- package/hono/src/resources/src/stores/auth.ts +184 -164
- package/hono/src/resources/vite.config.ts +54 -36
- package/hono/src/storage/database/nexwire.sqlite +0 -0
- package/hono/src/storage/logs/app.log +0 -0
- package/hono/src/storage/logs/fatal.log +0 -0
- package/hono/src/types/global.d.ts +32 -26
- package/package.json +2 -2
- 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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
74
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
105
|
-
|
|
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
|
-
|
|
114
|
-
|
|
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
|
};
|