@cequrebackends/cequre-ts 0.11.4

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 (60) hide show
  1. package/dist/adapters/bun/bun-cron.d.ts +20 -0
  2. package/dist/adapters/bun/bun-media.d.ts +9 -0
  3. package/dist/adapters/bun/bun-redis-cache.d.ts +33 -0
  4. package/dist/adapters/bun/bun-response.d.ts +13 -0
  5. package/dist/adapters/bun/bun-server.d.ts +6 -0
  6. package/dist/adapters/bun/bun-storage.d.ts +10 -0
  7. package/dist/adapters/bun/bun-websocket.d.ts +104 -0
  8. package/dist/adapters/bun/index.d.ts +9 -0
  9. package/dist/adapters/bun/index.js +547 -0
  10. package/dist/adapters/node/index.d.ts +9 -0
  11. package/dist/adapters/node/index.js +902 -0
  12. package/dist/adapters/node/node-cron.d.ts +20 -0
  13. package/dist/adapters/node/node-media.d.ts +9 -0
  14. package/dist/adapters/node/node-redis-cache.d.ts +32 -0
  15. package/dist/adapters/node/node-response.d.ts +13 -0
  16. package/dist/adapters/node/node-server.d.ts +6 -0
  17. package/dist/adapters/node/node-storage.d.ts +10 -0
  18. package/dist/adapters/node/node-websocket.d.ts +102 -0
  19. package/dist/index-17yswtmg.js +175 -0
  20. package/dist/index-kyvy0s1x.js +2662 -0
  21. package/dist/index-mfqj7cwr.js +165 -0
  22. package/dist/index-rf1kdn5b.js +732 -0
  23. package/dist/index.d.ts +18 -0
  24. package/dist/index.js +3152 -0
  25. package/dist/interface-map.d.ts +175 -0
  26. package/dist/shared/core/adapter.d.ts +84 -0
  27. package/dist/shared/core/base-sql-adapter.d.ts +34 -0
  28. package/dist/shared/core/cache.d.ts +8 -0
  29. package/dist/shared/core/email.d.ts +53 -0
  30. package/dist/shared/core/index.d.ts +12 -0
  31. package/dist/shared/core/index.js +47 -0
  32. package/dist/shared/core/openapi.d.ts +24 -0
  33. package/dist/shared/core/plugins.d.ts +2 -0
  34. package/dist/shared/core/request.d.ts +32 -0
  35. package/dist/shared/core/sdk.d.ts +3 -0
  36. package/dist/shared/core/stream.d.ts +24 -0
  37. package/dist/shared/core/types-generator.d.ts +0 -0
  38. package/dist/shared/core/types.d.ts +304 -0
  39. package/dist/shared/core/ulid.d.ts +5 -0
  40. package/dist/shared/core/validator.d.ts +32 -0
  41. package/dist/shared/main/access-evaluator.d.ts +13 -0
  42. package/dist/shared/main/access.d.ts +34 -0
  43. package/dist/shared/main/aot.d.ts +3 -0
  44. package/dist/shared/main/hooks.d.ts +76 -0
  45. package/dist/shared/main/population.d.ts +13 -0
  46. package/dist/shared/main/router.d.ts +112 -0
  47. package/dist/shared/main/runtime.d.ts +195 -0
  48. package/dist/shared/main/sse.d.ts +87 -0
  49. package/dist/shared/utils/crypto.d.ts +23 -0
  50. package/dist/shared/utils/durable-queue.d.ts +20 -0
  51. package/dist/shared/utils/duration.d.ts +15 -0
  52. package/dist/shared/utils/error.d.ts +52 -0
  53. package/dist/shared/utils/kv/adapters/memory.d.ts +20 -0
  54. package/dist/shared/utils/kv/adapters/sqlite.d.ts +32 -0
  55. package/dist/shared/utils/kv/index.d.ts +37 -0
  56. package/dist/shared/utils/kv/types.d.ts +38 -0
  57. package/dist/shared/utils/logger.d.ts +42 -0
  58. package/dist/shared/utils/queue-manager.d.ts +64 -0
  59. package/dist/shared/utils/url.d.ts +13 -0
  60. package/package.json +63 -0
@@ -0,0 +1,902 @@
1
+ // @bun
2
+ import {
3
+ CequreQueueManager,
4
+ exports_logger,
5
+ init_logger,
6
+ logger
7
+ } from "../../index-rf1kdn5b.js";
8
+ import {
9
+ CequreError,
10
+ __toCommonJS,
11
+ ulid
12
+ } from "../../index-17yswtmg.js";
13
+
14
+ // adapters/node/node-server.ts
15
+ import http from "http";
16
+ import https from "https";
17
+ import fs from "fs";
18
+ import { createServerAdapter } from "@whatwg-node/server";
19
+ function compilePathRegex(path) {
20
+ let regexStr = "^" + path.replace(/\/?\*/g, "(?:/.*)?").replace(/:([a-zA-Z0-9_]+)/g, "(?<$1>[^/]+)");
21
+ if (!regexStr.endsWith(")?") && !regexStr.endsWith(".*")) {
22
+ regexStr += "$";
23
+ }
24
+ return new RegExp(regexStr);
25
+ }
26
+
27
+ class NodeServerProvider {
28
+ server = null;
29
+ start(config) {
30
+ const routeMatchers = [];
31
+ if (config.routes) {
32
+ for (const path of Object.keys(config.routes)) {
33
+ routeMatchers.push({ path, regex: compilePathRegex(path) });
34
+ }
35
+ }
36
+ const fetchHandler = async (req) => {
37
+ const url = new URL(req.url);
38
+ let handler = config.routes?.[url.pathname]?.[req.method] || config.routes?.[url.pathname]?.["ALL"];
39
+ if (!handler && routeMatchers.length > 0) {
40
+ for (const matcher of routeMatchers) {
41
+ const match = url.pathname.match(matcher.regex);
42
+ if (match) {
43
+ const h = config.routes[matcher.path]?.[req.method] || config.routes[matcher.path]?.["ALL"];
44
+ if (h) {
45
+ handler = h;
46
+ req.params = match.groups || {};
47
+ break;
48
+ }
49
+ }
50
+ }
51
+ }
52
+ if (handler) {
53
+ return handler(req, this.server);
54
+ }
55
+ return config.fetch(req, this.server);
56
+ };
57
+ const adapter = createServerAdapter(fetchHandler);
58
+ if (config.tls?.cert && config.tls?.key) {
59
+ this.server = https.createServer({
60
+ cert: fs.readFileSync(config.tls.cert),
61
+ key: fs.readFileSync(config.tls.key)
62
+ }, adapter);
63
+ } else {
64
+ this.server = http.createServer(adapter);
65
+ }
66
+ const port = config.port ?? (process.env.PORT ? parseInt(process.env.PORT, 10) : 3000);
67
+ this.server.listen(port, config.hostname);
68
+ this.server.on("upgrade", (req, socket, head) => {
69
+ const protocol = config.tls ? "https" : "http";
70
+ const host = req.headers.host || config.hostname || "localhost";
71
+ const url = `${protocol}://${host}${req.url}`;
72
+ const headers = new Headers;
73
+ for (const [key, value] of Object.entries(req.headers)) {
74
+ if (value !== undefined) {
75
+ if (Array.isArray(value)) {
76
+ value.forEach((v) => headers.append(key, v));
77
+ } else {
78
+ headers.set(key, value);
79
+ }
80
+ }
81
+ }
82
+ const webReq = new Request(url, {
83
+ method: req.method,
84
+ headers
85
+ });
86
+ webReq.rawNodeReq = req;
87
+ webReq.rawNodeSocket = socket;
88
+ webReq.rawNodeHead = head;
89
+ Promise.resolve(config.fetch(webReq, this.server)).catch((err) => {
90
+ console.error("Cequre node upgrade handler error:", err);
91
+ socket.destroy();
92
+ });
93
+ });
94
+ console.log(`\uD83D\uDE80 Cequre starting on http://${config.hostname || "localhost"}:${port}`);
95
+ const serverObj = this.server;
96
+ serverObj.stop = this.stop.bind(this);
97
+ return serverObj;
98
+ }
99
+ async stop() {
100
+ if (this.server) {
101
+ if (typeof this.server.closeAllConnections === "function") {
102
+ this.server.closeAllConnections();
103
+ }
104
+ await new Promise((resolve) => {
105
+ this.server.close(() => {
106
+ resolve();
107
+ });
108
+ });
109
+ }
110
+ }
111
+ }
112
+ // adapters/node/node-cron.ts
113
+ import cron from "node-cron";
114
+ init_logger();
115
+
116
+ class NodeCronProvider {
117
+ localJobs = new Map;
118
+ useBullMQ = false;
119
+ constructor() {
120
+ try {
121
+ CequreQueueManager.getInstance();
122
+ this.useBullMQ = true;
123
+ } catch {
124
+ this.useBullMQ = false;
125
+ }
126
+ }
127
+ registerJob(name, schedule, handler) {
128
+ if (this.useBullMQ) {
129
+ const qm = CequreQueueManager.getInstance();
130
+ qm.registerWorker("cequre_cron", async (job) => {
131
+ if (job.name === name) {
132
+ try {
133
+ await Promise.resolve(handler());
134
+ } catch (err) {
135
+ logger.error(err, `[Cequre Cron (BullMQ)] Job "${name}" failed:`);
136
+ throw new Error(String(err instanceof Error ? err.message : err));
137
+ }
138
+ }
139
+ }).catch((err) => {
140
+ logger.error(err, `[Cequre Cron (BullMQ)] Failed to register worker for "${name}":`);
141
+ });
142
+ qm.addJob("cequre_cron", name, {}, {
143
+ repeat: { pattern: schedule },
144
+ jobId: `cron_${name}`,
145
+ removeOnComplete: true,
146
+ removeOnFail: 100
147
+ }).catch((err) => {
148
+ logger.error(err, `[Cequre Cron (BullMQ)] Failed to register job "${name}":`);
149
+ });
150
+ } else {
151
+ if (this.localJobs.has(name)) {
152
+ throw CequreError.Conflict(`[Cequre Cron] A cron job with the name "${name}" is already registered.`);
153
+ }
154
+ const job = cron.schedule(schedule, async () => {
155
+ try {
156
+ await handler();
157
+ } catch (err) {
158
+ logger.error(err, `[Cequre Cron] Job "${name}" failed:`);
159
+ }
160
+ });
161
+ this.localJobs.set(name, job);
162
+ }
163
+ }
164
+ async stop(name) {
165
+ if (this.useBullMQ) {
166
+ const qm = CequreQueueManager.getInstance();
167
+ const queue = qm.getQueue("cequre_cron");
168
+ const repeatableJobs = await queue.getRepeatableJobs();
169
+ const job = repeatableJobs.find((j) => j.name === name);
170
+ if (job) {
171
+ await queue.removeRepeatableByKey(job.key);
172
+ return true;
173
+ }
174
+ return false;
175
+ } else {
176
+ const job = this.localJobs.get(name);
177
+ if (job && typeof job.stop === "function") {
178
+ job.stop();
179
+ this.localJobs.delete(name);
180
+ return true;
181
+ }
182
+ return false;
183
+ }
184
+ }
185
+ async stopAll() {
186
+ if (this.useBullMQ) {
187
+ const qm = CequreQueueManager.getInstance();
188
+ const queue = qm.getQueue("cequre_cron");
189
+ const repeatableJobs = await queue.getRepeatableJobs();
190
+ for (const job of repeatableJobs) {
191
+ await queue.removeRepeatableByKey(job.key);
192
+ }
193
+ } else {
194
+ for (const [name, job] of this.localJobs.entries()) {
195
+ if (typeof job.stop === "function") {
196
+ try {
197
+ job.stop();
198
+ } catch (e) {
199
+ logger.error(e, `[Cequre Cron] Error stopping job "${name}":`);
200
+ }
201
+ }
202
+ }
203
+ this.localJobs.clear();
204
+ }
205
+ }
206
+ async list() {
207
+ if (this.useBullMQ) {
208
+ const qm = CequreQueueManager.getInstance();
209
+ const queue = qm.getQueue("cequre_cron");
210
+ const jobs = await queue.getRepeatableJobs();
211
+ return jobs.map((j) => j.name);
212
+ } else {
213
+ return Array.from(this.localJobs.keys());
214
+ }
215
+ }
216
+ startAll() {}
217
+ }
218
+ // adapters/node/node-websocket.ts
219
+ import { WebSocketServer } from "ws";
220
+ class NodeWebSocketManager {
221
+ connections = new Map;
222
+ rooms = new Map;
223
+ connectionRooms = new Map;
224
+ metadata = new Map;
225
+ lastPong = new Map;
226
+ heartbeatTimer = null;
227
+ register(ws) {
228
+ this.connections.set(ws.id, ws);
229
+ this.connectionRooms.set(ws.id, new Set);
230
+ this.metadata.set(ws.id, {});
231
+ this.lastPong.set(ws.id, Date.now());
232
+ }
233
+ remove(wsOrId) {
234
+ const id = typeof wsOrId === "string" ? wsOrId : wsOrId.id;
235
+ for (const room of this.connectionRooms.get(id) ?? []) {
236
+ this.leaveRoom(id, room);
237
+ }
238
+ this.connections.delete(id);
239
+ this.connectionRooms.delete(id);
240
+ this.metadata.delete(id);
241
+ this.lastPong.delete(id);
242
+ }
243
+ pong(id) {
244
+ if (this.lastPong.has(id))
245
+ this.lastPong.set(id, Date.now());
246
+ }
247
+ startHeartbeat(intervalMs = 30000, timeoutMs = 1e4) {
248
+ if (this.heartbeatTimer !== null)
249
+ return;
250
+ const deadline = intervalMs + timeoutMs;
251
+ this.heartbeatTimer = setInterval(() => {
252
+ const now = Date.now();
253
+ for (const [id, lastSeen] of this.lastPong) {
254
+ if (now - lastSeen > deadline)
255
+ this.remove(id);
256
+ }
257
+ for (const ws of this.connections.values()) {
258
+ ws.send(JSON.stringify({ type: "ping" }));
259
+ }
260
+ }, intervalMs);
261
+ if (this.heartbeatTimer.unref)
262
+ this.heartbeatTimer.unref();
263
+ }
264
+ stopHeartbeat() {
265
+ if (this.heartbeatTimer)
266
+ clearInterval(this.heartbeatTimer);
267
+ this.heartbeatTimer = null;
268
+ }
269
+ joinRoom(id, room) {
270
+ if (!this.rooms.has(room))
271
+ this.rooms.set(room, new Set);
272
+ this.rooms.get(room).add(id);
273
+ this.connectionRooms.get(id)?.add(room);
274
+ }
275
+ leaveRoom(id, room) {
276
+ this.rooms.get(room)?.delete(id);
277
+ if (this.rooms.get(room)?.size === 0)
278
+ this.rooms.delete(room);
279
+ this.connectionRooms.get(id)?.delete(room);
280
+ }
281
+ getRoomMembers(room) {
282
+ return [...this.rooms.get(room) ?? []];
283
+ }
284
+ getConnectionRooms(id) {
285
+ return [...this.connectionRooms.get(id) ?? []];
286
+ }
287
+ listRooms() {
288
+ return [...this.rooms.keys()];
289
+ }
290
+ sendTo(id, payload) {
291
+ const ws = this.connections.get(id);
292
+ if (!ws)
293
+ return false;
294
+ ws.send(JSON.stringify(payload));
295
+ return true;
296
+ }
297
+ broadcastToRoom(room, payload, { exclude = [] } = {}) {
298
+ const ids = this.rooms.get(room);
299
+ if (!ids)
300
+ return 0;
301
+ let sent = 0;
302
+ for (const id of ids) {
303
+ if (exclude.includes(id))
304
+ continue;
305
+ if (this.sendTo(id, payload))
306
+ sent++;
307
+ }
308
+ return sent;
309
+ }
310
+ broadcastAll(payload, { exclude = [] } = {}) {
311
+ let sent = 0;
312
+ for (const id of this.connections.keys()) {
313
+ if (exclude.includes(id))
314
+ continue;
315
+ if (this.sendTo(id, payload))
316
+ sent++;
317
+ }
318
+ return sent;
319
+ }
320
+ setMeta(id, key, value) {
321
+ const meta = this.metadata.get(id);
322
+ if (meta)
323
+ meta[key] = value;
324
+ }
325
+ getMeta(id, key) {
326
+ return this.metadata.get(id)?.[key];
327
+ }
328
+ get connectionCount() {
329
+ return this.connections.size;
330
+ }
331
+ get roomCount() {
332
+ return this.rooms.size;
333
+ }
334
+ getStats() {
335
+ return {
336
+ connections: this.connectionCount,
337
+ rooms: Object.fromEntries([...this.rooms.entries()].map(([room, ids]) => [room, ids.size])),
338
+ heartbeatActive: this.heartbeatTimer !== null
339
+ };
340
+ }
341
+ }
342
+ var wsManager = new NodeWebSocketManager;
343
+ function parseMessage(message) {
344
+ if (typeof message !== "string") {
345
+ return { type: "binary", payload: message };
346
+ }
347
+ try {
348
+ const parsed = JSON.parse(message);
349
+ return parsed && typeof parsed === "object" ? parsed : { type: "message", payload: parsed };
350
+ } catch {
351
+ return { type: "message", payload: message };
352
+ }
353
+ }
354
+ function createWebSocketHandler({
355
+ heartbeat,
356
+ onJoinRoom
357
+ } = {}) {
358
+ const startHeartbeat = () => {
359
+ if (heartbeat === false)
360
+ return;
361
+ wsManager.startHeartbeat(heartbeat?.interval, heartbeat?.timeout);
362
+ };
363
+ return {
364
+ open(wrapped) {
365
+ wsManager.register(wrapped);
366
+ startHeartbeat();
367
+ wrapped.send(JSON.stringify({ type: "connected", id: wrapped.id }));
368
+ },
369
+ async message(wrapped, rawMessage) {
370
+ const message = parseMessage(rawMessage);
371
+ const { id } = wrapped;
372
+ switch (message.type) {
373
+ case "join":
374
+ if (!message.room)
375
+ return;
376
+ if (onJoinRoom && !await onJoinRoom(message.room, wrapped)) {
377
+ wrapped.send(JSON.stringify({ type: "error", message: `Access denied to room '${message.room}'` }));
378
+ return;
379
+ }
380
+ wsManager.joinRoom(id, message.room);
381
+ wrapped.send(JSON.stringify({ type: "joined", room: message.room }));
382
+ return;
383
+ case "leave":
384
+ if (!message.room)
385
+ return;
386
+ wsManager.leaveRoom(id, message.room);
387
+ wrapped.send(JSON.stringify({ type: "left", room: message.room }));
388
+ return;
389
+ case "broadcast":
390
+ if (message.room) {
391
+ if (!wsManager.getConnectionRooms(id).includes(message.room)) {
392
+ wrapped.send(JSON.stringify({ type: "error", message: "Not in room" }));
393
+ return;
394
+ }
395
+ wsManager.broadcastToRoom(message.room, { type: "message", from: id, payload: message.payload }, { exclude: [id] });
396
+ }
397
+ return;
398
+ case "ping":
399
+ wrapped.send(JSON.stringify({ type: "pong" }));
400
+ return;
401
+ case "pong":
402
+ wsManager.pong(id);
403
+ return;
404
+ default:
405
+ wrapped.send(JSON.stringify({ type: "error", message: `Unknown type: ${message.type}` }));
406
+ }
407
+ },
408
+ close(wrapped) {
409
+ wsManager.remove(wrapped.id);
410
+ }
411
+ };
412
+ }
413
+ function createNodeWebSocketRoute({
414
+ path = "/ws",
415
+ heartbeat,
416
+ onJoinRoom
417
+ } = {}) {
418
+ const handler = createWebSocketHandler({ heartbeat, onJoinRoom });
419
+ const wss = new WebSocketServer({ noServer: true });
420
+ wss.on("connection", (ws, req) => {
421
+ const id = ulid();
422
+ const wrapped = {
423
+ id,
424
+ data: {},
425
+ send: (message) => {
426
+ ws.send(message);
427
+ return typeof message === "string" ? Buffer.byteLength(message) : message.byteLength || 0;
428
+ }
429
+ };
430
+ if (handler.open)
431
+ handler.open(wrapped);
432
+ ws.on("message", (message) => {
433
+ if (handler.message)
434
+ handler.message(wrapped, message);
435
+ });
436
+ ws.on("close", (code, reason) => {
437
+ if (handler.close)
438
+ handler.close(wrapped, code, reason.toString());
439
+ });
440
+ });
441
+ return async (request, server) => {
442
+ const rawReq = request.rawNodeReq;
443
+ const socket = request.rawNodeSocket;
444
+ const head = request.rawNodeHead;
445
+ if (rawReq && socket && head) {
446
+ wss.handleUpgrade(rawReq, socket, head, (ws) => {
447
+ wss.emit("connection", ws, rawReq);
448
+ });
449
+ return;
450
+ }
451
+ return new Response(JSON.stringify({ message: "WebSocket upgrade failed or not an upgrade request" }), { status: 400 });
452
+ };
453
+ }
454
+
455
+ class CequreWebsocket {
456
+ static get manager() {
457
+ return wsManager;
458
+ }
459
+ static route(options = {}) {
460
+ return createNodeWebSocketRoute(options);
461
+ }
462
+ static handler(options = {}) {
463
+ return createWebSocketHandler(options);
464
+ }
465
+ static register(ws) {
466
+ return wsManager.register(ws);
467
+ }
468
+ static remove(wsOrId) {
469
+ return wsManager.remove(wsOrId);
470
+ }
471
+ static pong(id) {
472
+ return wsManager.pong(id);
473
+ }
474
+ static startHeartbeat(intervalMs, timeoutMs) {
475
+ return wsManager.startHeartbeat(intervalMs, timeoutMs);
476
+ }
477
+ static stopHeartbeat() {
478
+ return wsManager.stopHeartbeat();
479
+ }
480
+ static joinRoom(id, room) {
481
+ return wsManager.joinRoom(id, room);
482
+ }
483
+ static leaveRoom(id, room) {
484
+ return wsManager.leaveRoom(id, room);
485
+ }
486
+ static getRoomMembers(room) {
487
+ return wsManager.getRoomMembers(room);
488
+ }
489
+ static getConnectionRooms(id) {
490
+ return wsManager.getConnectionRooms(id);
491
+ }
492
+ static listRooms() {
493
+ return wsManager.listRooms();
494
+ }
495
+ static sendTo(id, payload) {
496
+ return wsManager.sendTo(id, payload);
497
+ }
498
+ static broadcastToRoom(room, payload, opts) {
499
+ return wsManager.broadcastToRoom(room, payload, opts);
500
+ }
501
+ static broadcastAll(payload, opts) {
502
+ return wsManager.broadcastAll(payload, opts);
503
+ }
504
+ static setMeta(id, key, value) {
505
+ return wsManager.setMeta(id, key, value);
506
+ }
507
+ static getMeta(id, key) {
508
+ return wsManager.getMeta(id, key);
509
+ }
510
+ static get connectionCount() {
511
+ return wsManager.connectionCount;
512
+ }
513
+ static get roomCount() {
514
+ return wsManager.roomCount;
515
+ }
516
+ static getStats() {
517
+ return wsManager.getStats();
518
+ }
519
+ }
520
+ // adapters/node/node-storage.ts
521
+ import fs2 from "fs";
522
+ import path from "path";
523
+ class NodeLocalStorageProvider {
524
+ uploadDir;
525
+ apiPrefix;
526
+ constructor(uploadDir = "uploads", apiPrefix = "/api") {
527
+ this.apiPrefix = apiPrefix;
528
+ this.uploadDir = path.resolve(process.cwd(), uploadDir);
529
+ if (!fs2.existsSync(this.uploadDir)) {
530
+ fs2.mkdirSync(this.uploadDir, { recursive: true });
531
+ }
532
+ }
533
+ async saveFile(file, options) {
534
+ const ext = file.name ? path.extname(file.name) : "";
535
+ const safeName = options?.filename ? options.filename : `${ulid()}${ext}`;
536
+ const filePath = path.join(this.uploadDir, safeName);
537
+ const buffer = Buffer.from(await file.arrayBuffer());
538
+ await fs2.promises.writeFile(filePath, buffer);
539
+ return {
540
+ filename: safeName,
541
+ originalName: file.name || "upload",
542
+ mimetype: file.type || "application/octet-stream",
543
+ size: file.size,
544
+ url: `${this.apiPrefix}/uploads/${safeName}`
545
+ };
546
+ }
547
+ async deleteFile(filename) {
548
+ const filePath = path.join(this.uploadDir, filename);
549
+ try {
550
+ if (fs2.existsSync(filePath)) {
551
+ await fs2.promises.unlink(filePath);
552
+ }
553
+ } catch (e) {
554
+ console.error(`Failed to delete file ${filePath}`, e);
555
+ }
556
+ }
557
+ }
558
+ // adapters/node/node-redis-cache.ts
559
+ import Redis from "ioredis";
560
+ var _log = null;
561
+ function getLog() {
562
+ if (!_log)
563
+ _log = (init_logger(), __toCommonJS(exports_logger)).createLogger("kv-redis");
564
+ return _log;
565
+ }
566
+
567
+ class RedisAdapter {
568
+ redis;
569
+ constructor(options) {
570
+ this.redis = new Redis(options?.url || process.env.REDIS_URL || "redis://localhost:6379");
571
+ getLog().debug("Redis KV adapter initialized (ioredis)");
572
+ }
573
+ async get(key) {
574
+ const value = await this.redis.get(key);
575
+ if (value === null)
576
+ return null;
577
+ try {
578
+ return JSON.parse(value);
579
+ } catch {
580
+ return value;
581
+ }
582
+ }
583
+ async getMany(keys) {
584
+ const result = new Map;
585
+ if (keys.length === 0)
586
+ return result;
587
+ const values = await this.redis.mget(...keys);
588
+ for (let i = 0;i < keys.length; i++) {
589
+ const key = keys[i];
590
+ if (key === undefined)
591
+ continue;
592
+ const value = values[i];
593
+ if (value !== null && value !== undefined) {
594
+ try {
595
+ result.set(key, JSON.parse(value));
596
+ } catch {
597
+ result.set(key, value);
598
+ }
599
+ }
600
+ }
601
+ return result;
602
+ }
603
+ async set(key, value, ttl) {
604
+ const serialized = JSON.stringify(value);
605
+ if (ttl != null && ttl > 0) {
606
+ await this.redis.setex(key, ttl, serialized);
607
+ } else {
608
+ await this.redis.set(key, serialized);
609
+ }
610
+ }
611
+ async setMany(entries) {
612
+ const pipeline = this.redis.pipeline();
613
+ for (const { key, value, ttl } of entries) {
614
+ const serialized = JSON.stringify(value);
615
+ if (ttl != null && ttl > 0) {
616
+ pipeline.setex(key, ttl, serialized);
617
+ } else {
618
+ pipeline.set(key, serialized);
619
+ }
620
+ }
621
+ await pipeline.exec();
622
+ }
623
+ async delete(key) {
624
+ const deleted = await this.redis.del(key);
625
+ return deleted > 0;
626
+ }
627
+ async deleteMany(keys) {
628
+ if (keys.length === 0)
629
+ return 0;
630
+ return await this.redis.del(...keys);
631
+ }
632
+ async has(key) {
633
+ const exists = await this.redis.exists(key);
634
+ return exists > 0;
635
+ }
636
+ async keys(prefix) {
637
+ if (!prefix) {
638
+ return await this.redis.keys("*");
639
+ }
640
+ return await this.redis.keys(`${prefix}*`);
641
+ }
642
+ async count() {
643
+ return await this.redis.dbsize();
644
+ }
645
+ async clear() {
646
+ await this.redis.flushdb();
647
+ }
648
+ cleanup() {
649
+ return 0;
650
+ }
651
+ close() {
652
+ this.redis.quit().catch(() => {});
653
+ getLog().debug("Redis KV adapter closed (ioredis)");
654
+ }
655
+ }
656
+ // adapters/node/node-response.ts
657
+ import fs3 from "fs";
658
+ import { Readable } from "stream";
659
+ var UPGRADED = Symbol("cequre.bun.upgraded");
660
+ var JSON_CONTENT_TYPE = "application/json";
661
+ var DEFAULT_JSON_HEADERS = { "Content-Type": JSON_CONTENT_TYPE };
662
+ function mergeHeaders(init, headers) {
663
+ const merged = new Headers(init?.headers);
664
+ if (headers) {
665
+ for (const [key, value] of new Headers(headers)) {
666
+ merged.set(key, value);
667
+ }
668
+ }
669
+ return merged;
670
+ }
671
+ function json(data, init = {}) {
672
+ if (!init.headers && init.status === undefined && init.statusText === undefined) {
673
+ return new Response(JSON.stringify(data), { headers: DEFAULT_JSON_HEADERS });
674
+ }
675
+ const headers = mergeHeaders(init, { "Content-Type": JSON_CONTENT_TYPE });
676
+ return new Response(JSON.stringify(data), { ...init, headers });
677
+ }
678
+ function empty(status = 204, init = {}) {
679
+ return new Response(null, { ...init, status });
680
+ }
681
+ function redirect(location, status = 302, init = {}) {
682
+ const headers = mergeHeaders(init, { Location: location });
683
+ return new Response(null, { ...init, status, headers });
684
+ }
685
+ function error(message, status = 500, code = "INTERNAL_ERROR", init = {}) {
686
+ return json({
687
+ error: code,
688
+ message
689
+ }, { ...init, status });
690
+ }
691
+ function notFound(message = "Not found") {
692
+ return error(message, 404, "NOT_FOUND");
693
+ }
694
+ function methodNotAllowed(allowedMethods) {
695
+ return error("Method not allowed", 405, "METHOD_NOT_ALLOWED", {
696
+ headers: { Allow: allowedMethods.join(", ") }
697
+ });
698
+ }
699
+ function file(file2, init = {}) {
700
+ if (typeof file2 === "string") {
701
+ const stream = fs3.createReadStream(file2);
702
+ let readable;
703
+ if (Readable.toWeb) {
704
+ readable = Readable.toWeb(stream);
705
+ } else {
706
+ readable = new ReadableStream({
707
+ start(controller) {
708
+ stream.on("data", (chunk) => controller.enqueue(chunk));
709
+ stream.on("end", () => controller.close());
710
+ stream.on("error", (e) => controller.error(e));
711
+ },
712
+ cancel() {
713
+ stream.destroy();
714
+ }
715
+ });
716
+ }
717
+ return new Response(readable, init);
718
+ }
719
+ if (file2 instanceof Uint8Array) {
720
+ return new Response(new Uint8Array(file2).buffer, init);
721
+ }
722
+ return new Response(file2, init);
723
+ }
724
+ function stream(data, init = {}) {
725
+ if (data instanceof ReadableStream) {
726
+ const headers2 = mergeHeaders(init, { "Content-Type": "text/plain" });
727
+ return new Response(data, { ...init, headers: headers2 });
728
+ }
729
+ const iterator = Symbol.asyncIterator in data ? data[Symbol.asyncIterator]() : data[Symbol.iterator]();
730
+ const encoder = new TextEncoder;
731
+ const readable = new ReadableStream({
732
+ async pull(controller) {
733
+ try {
734
+ const { value, done } = await iterator.next();
735
+ if (done) {
736
+ controller.close();
737
+ } else {
738
+ let chunk = value;
739
+ if (typeof chunk !== "string" && !(chunk instanceof Uint8Array)) {
740
+ chunk = JSON.stringify(chunk) + `
741
+ `;
742
+ }
743
+ if (typeof chunk === "string") {
744
+ chunk = encoder.encode(chunk);
745
+ }
746
+ controller.enqueue(chunk);
747
+ }
748
+ } catch (err) {
749
+ if (typeof iterator.return === "function") {
750
+ try {
751
+ await iterator.return();
752
+ } catch {}
753
+ }
754
+ controller.error(err);
755
+ }
756
+ },
757
+ cancel() {
758
+ if (typeof iterator.return === "function") {
759
+ iterator.return();
760
+ }
761
+ }
762
+ });
763
+ const headers = mergeHeaders(init, { "Content-Type": "text/plain" });
764
+ return new Response(readable, { ...init, headers });
765
+ }
766
+ function toResponse(result) {
767
+ if (result === UPGRADED)
768
+ return;
769
+ if (result instanceof Response)
770
+ return result;
771
+ if (result === undefined)
772
+ return empty();
773
+ if (typeof result === "string")
774
+ return new Response(result);
775
+ if (result !== null && typeof result === "object") {
776
+ if (typeof result.next === "function" && ((Symbol.asyncIterator in result) || (Symbol.iterator in result))) {
777
+ return stream(result);
778
+ }
779
+ }
780
+ return json(result);
781
+ }
782
+ function routeErrorToResponse(errorValue, request) {
783
+ console.error("Cequre Unhandled Route Error:", errorValue);
784
+ const message = errorValue instanceof Error ? errorValue.message : String(errorValue);
785
+ return error(message, 500, "INTERNAL_ERROR", {
786
+ headers: request ? { "X-Cequre-Path": new URL(request.url).pathname } : undefined
787
+ });
788
+ }
789
+ // adapters/node/node-media.ts
790
+ import fs4 from "fs";
791
+ import { Readable as Readable2 } from "stream";
792
+ function CequreStreamMedia(request, absolutePathOrUrl, options = {}) {
793
+ const provider = options.provider || "local";
794
+ if (provider === "s3") {
795
+ return new Response(null, {
796
+ status: 302,
797
+ headers: {
798
+ Location: absolutePathOrUrl
799
+ }
800
+ });
801
+ }
802
+ const rangeHeader = request.headers.get("Range");
803
+ const maxChunkSize = options.maxChunkSize || 1024 * 1024 * 2;
804
+ let stat;
805
+ try {
806
+ stat = fs4.statSync(absolutePathOrUrl);
807
+ } catch (e) {
808
+ return new Response("Not Found", { status: 404 });
809
+ }
810
+ if (!rangeHeader) {
811
+ const stream3 = fs4.createReadStream(absolutePathOrUrl);
812
+ const readable2 = Readable2.toWeb ? Readable2.toWeb(stream3) : new ReadableStream({
813
+ start(controller) {
814
+ stream3.on("data", (chunk) => controller.enqueue(chunk));
815
+ stream3.on("end", () => controller.close());
816
+ stream3.on("error", (e) => controller.error(e));
817
+ },
818
+ cancel() {
819
+ stream3.destroy();
820
+ }
821
+ });
822
+ return new Response(readable2, {
823
+ headers: {
824
+ "Content-Length": stat.size.toString(),
825
+ "Content-Type": "application/octet-stream"
826
+ }
827
+ });
828
+ }
829
+ const parts = rangeHeader.replace(/bytes=/, "").split("-");
830
+ const reqStart = parseInt(parts[0], 10);
831
+ const reqEnd = parts[1] ? parseInt(parts[1], 10) : stat.size - 1;
832
+ if (isNaN(reqStart) || reqStart >= stat.size) {
833
+ return new Response("Requested range not satisfiable", {
834
+ status: 416,
835
+ headers: {
836
+ "Content-Range": `bytes */${stat.size}`
837
+ }
838
+ });
839
+ }
840
+ let end = reqEnd;
841
+ if (end - reqStart + 1 > maxChunkSize) {
842
+ end = reqStart + maxChunkSize - 1;
843
+ }
844
+ if (end >= stat.size) {
845
+ end = stat.size - 1;
846
+ }
847
+ const stream2 = fs4.createReadStream(absolutePathOrUrl, { start: reqStart, end });
848
+ const readable = Readable2.toWeb ? Readable2.toWeb(stream2) : new ReadableStream({
849
+ start(controller) {
850
+ stream2.on("data", (chunk) => controller.enqueue(chunk));
851
+ stream2.on("end", () => controller.close());
852
+ stream2.on("error", (e) => controller.error(e));
853
+ },
854
+ cancel() {
855
+ stream2.destroy();
856
+ }
857
+ });
858
+ const chunkSize = end - reqStart + 1;
859
+ return new Response(readable, {
860
+ status: 206,
861
+ headers: {
862
+ "Content-Range": `bytes ${reqStart}-${end}/${stat.size}`,
863
+ "Accept-Ranges": "bytes",
864
+ "Content-Length": chunkSize.toString(),
865
+ "Content-Type": "application/octet-stream"
866
+ }
867
+ });
868
+ }
869
+ // adapters/node/index.ts
870
+ function withNode(config) {
871
+ return {
872
+ ...config,
873
+ serverProvider: config.serverProvider || new NodeServerProvider,
874
+ cronProvider: config.cronProvider || new NodeCronProvider,
875
+ realtimeProvider: config.realtimeProvider || { websocket: CequreWebsocket },
876
+ storageProvider: config.storageProvider || new NodeLocalStorageProvider
877
+ };
878
+ }
879
+ export {
880
+ wsManager,
881
+ withNode,
882
+ toResponse,
883
+ stream,
884
+ routeErrorToResponse,
885
+ redirect,
886
+ notFound,
887
+ methodNotAllowed,
888
+ json,
889
+ file,
890
+ error,
891
+ empty,
892
+ createWebSocketHandler,
893
+ createNodeWebSocketRoute,
894
+ UPGRADED,
895
+ RedisAdapter,
896
+ NodeWebSocketManager,
897
+ NodeServerProvider,
898
+ NodeLocalStorageProvider,
899
+ NodeCronProvider,
900
+ CequreWebsocket,
901
+ CequreStreamMedia
902
+ };