@rebasepro/server 0.14.1 → 0.14.2-canary.g27a129e

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 (37) hide show
  1. package/dist/{admin_block-H86dCPsj.js → admin_block-DLILvzle.js} +2 -1
  2. package/dist/admin_block-DLILvzle.js.map +1 -0
  3. package/dist/api/logs-routes.d.ts +47 -8
  4. package/dist/auth/index.d.ts +4 -0
  5. package/dist/auth/resolve-rate-limit-store.d.ts +51 -0
  6. package/dist/auth/sql-rate-limit-store.d.ts +63 -0
  7. package/dist/{auth-BobZVd0j.js → auth-DIKS1rsI.js} +205 -9
  8. package/dist/auth-DIKS1rsI.js.map +1 -0
  9. package/dist/boot/boot.d.ts +15 -0
  10. package/dist/{contract-routes-Bet-eCNJ.js → contract-routes-DDNj4_J1.js} +2 -2
  11. package/dist/{contract-routes-Bet-eCNJ.js.map → contract-routes-DDNj4_J1.js.map} +1 -1
  12. package/dist/{cron-store-CB1x-Ken.js → cron-store-BBGvOA-9.js} +3 -3
  13. package/dist/{cron-store-CB1x-Ken.js.map → cron-store-BBGvOA-9.js.map} +1 -1
  14. package/dist/ddl-bootstrap-Cywoj8Ta.js.map +1 -1
  15. package/dist/index.es.js +128 -20
  16. package/dist/index.es.js.map +1 -1
  17. package/dist/{jobs-DR4SjGrD.js → jobs-BOEOIGAm.js} +3 -3
  18. package/dist/{jobs-DR4SjGrD.js.map → jobs-BOEOIGAm.js.map} +1 -1
  19. package/dist/{jwt-VJyXTdQQ.js → jwt-DxH9fLPt.js} +2 -2
  20. package/dist/{jwt-VJyXTdQQ.js.map → jwt-DxH9fLPt.js.map} +1 -1
  21. package/dist/logs-routes-CWBLQj2l.js +245 -0
  22. package/dist/logs-routes-CWBLQj2l.js.map +1 -0
  23. package/dist/{openapi-generator-DQeQ_q2f.js → openapi-generator-DLiiGD9X.js} +3 -3
  24. package/dist/{openapi-generator-DQeQ_q2f.js.map → openapi-generator-DLiiGD9X.js.map} +1 -1
  25. package/dist/{schema-editor-routes-CRcS3ArS.js → schema-editor-routes-CV9k0w3G.js} +3 -3
  26. package/dist/{schema-editor-routes-CRcS3ArS.js.map → schema-editor-routes-CV9k0w3G.js.map} +1 -1
  27. package/dist/{src-8XDWyDfR.js → src-B-E7RjdN.js} +54 -14
  28. package/dist/src-B-E7RjdN.js.map +1 -0
  29. package/dist/{src-Cz9nMgUR.js → src-CrCxd8km.js} +60 -2
  30. package/dist/src-CrCxd8km.js.map +1 -0
  31. package/package.json +5 -5
  32. package/dist/admin_block-H86dCPsj.js.map +0 -1
  33. package/dist/auth-BobZVd0j.js.map +0 -1
  34. package/dist/logs-routes-BYA72C_C.js +0 -100
  35. package/dist/logs-routes-BYA72C_C.js.map +0 -1
  36. package/dist/src-8XDWyDfR.js.map +0 -1
  37. package/dist/src-Cz9nMgUR.js.map +0 -1
@@ -0,0 +1,245 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ import "process";
3
+ __createRequire(import.meta.url);
4
+ import { n as __exportAll } from "./rolldown-runtime-DSJWtz9O.js";
5
+ import { Hono } from "hono";
6
+ import { streamSSE } from "hono/streaming";
7
+ //#region src/api/logs-routes.ts
8
+ var logs_routes_exports = /* @__PURE__ */ __exportAll({
9
+ addLog: () => addLog,
10
+ createLogsRoutes: () => createLogsRoutes,
11
+ default: () => logs_routes_default,
12
+ logBuffer: () => logBuffer,
13
+ logMiddleware: () => logMiddleware
14
+ });
15
+ function normalizeFilter(options) {
16
+ return {
17
+ ...options,
18
+ search: options.search?.toLowerCase()
19
+ };
20
+ }
21
+ /**
22
+ * Whether one entry belongs in a filtered view.
23
+ *
24
+ * Shared by the query and the stream on purpose: two copies of this would drift,
25
+ * and the failure that produces is invisible — a tail that quietly shows a
26
+ * different set of lines than the snapshot it started from.
27
+ */
28
+ function matchesFilter(entry, filter) {
29
+ if (filter.level && entry.level !== filter.level) return false;
30
+ if (filter.source && entry.source !== filter.source) return false;
31
+ if (filter.search && !entry.message.toLowerCase().includes(filter.search)) return false;
32
+ if (filter.since && entry.timestamp < filter.since) return false;
33
+ return true;
34
+ }
35
+ var LogRingBuffer = class {
36
+ buffer = [];
37
+ maxSize;
38
+ idCounter = 0;
39
+ listeners = /* @__PURE__ */ new Set();
40
+ constructor(maxSize = 1e4) {
41
+ this.maxSize = maxSize;
42
+ }
43
+ push(entry) {
44
+ const id = `log_${++this.idCounter}`;
45
+ const stored = {
46
+ ...entry,
47
+ id
48
+ };
49
+ this.buffer.push(stored);
50
+ if (this.buffer.length > this.maxSize) this.buffer.shift();
51
+ for (const listener of this.listeners) try {
52
+ listener(stored);
53
+ } catch {}
54
+ }
55
+ /**
56
+ * Follow the buffer. Returns the unsubscribe — call it, always: a listener
57
+ * left behind holds its whole closure, and on this class that closure is a
58
+ * pending-entry array.
59
+ *
60
+ * A listener must not log. It is called from inside `push`, so anything that
61
+ * reaches `addLog` from here recurses until the stack gives out.
62
+ */
63
+ subscribe(listener) {
64
+ this.listeners.add(listener);
65
+ return () => {
66
+ this.listeners.delete(listener);
67
+ };
68
+ }
69
+ query(options) {
70
+ const filter = normalizeFilter(options);
71
+ const sorted = [...this.buffer.filter((e) => matchesFilter(e, filter))].reverse();
72
+ const total = sorted.length;
73
+ const limit = options.limit || 100;
74
+ const offset = options.offset || 0;
75
+ return {
76
+ entries: sorted.slice(offset, offset + limit),
77
+ total
78
+ };
79
+ }
80
+ getLatest(count = 50) {
81
+ return this.buffer.slice(-count).reverse();
82
+ }
83
+ };
84
+ var logBuffer = new LogRingBuffer();
85
+ /** Add a log entry */
86
+ function addLog(level, source, message, metadata) {
87
+ logBuffer.push({
88
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
89
+ level,
90
+ source,
91
+ message,
92
+ metadata
93
+ });
94
+ }
95
+ /** Hono middleware to log API requests */
96
+ function logMiddleware(options = {}) {
97
+ const ignored = new Set(options.ignorePaths ?? []);
98
+ return async (c, next) => {
99
+ const start = Date.now();
100
+ await next();
101
+ if (ignored.has(c.req.path)) return;
102
+ const duration = Date.now() - start;
103
+ const reqId = c.get("requestId");
104
+ addLog("info", "api", `${c.req.method} ${c.req.path} ${c.res.status} ${duration}ms`, {
105
+ method: c.req.method,
106
+ path: c.req.path,
107
+ status: c.res.status,
108
+ duration,
109
+ ...reqId && { requestId: reqId }
110
+ });
111
+ };
112
+ }
113
+ /**
114
+ * How long entries accumulate before a batch goes out.
115
+ *
116
+ * Not zero, and that is the point. A busy server logs faster than a browser can
117
+ * render, and one SSE frame per line would hand the client a re-render per
118
+ * request served — worse than the 3s poll this replaces, precisely when the logs
119
+ * are worth watching. Coalescing keeps the frame rate bounded by the window
120
+ * rather than by traffic, and 250ms still reads as "live" to a person.
121
+ */
122
+ var STREAM_FLUSH_MS = 250;
123
+ /**
124
+ * Idle gap after which the stream sends a comment line.
125
+ *
126
+ * A silent SSE connection is indistinguishable from a dead one to everything in
127
+ * between — proxies, load balancers and laptop NICs all reap idle sockets, and a
128
+ * server with nothing to say is the normal state here.
129
+ */
130
+ var STREAM_HEARTBEAT_MS = 25e3;
131
+ /**
132
+ * Entries a single connection will hold between flushes.
133
+ *
134
+ * This is a *rate* ceiling, not just a memory bound, and that is easy to get
135
+ * wrong: nothing drains `pending` between flushes, so the most a connection can
136
+ * carry losslessly is `maxPending` per `flushMs` — here 2000 per 250ms, or 8000
137
+ * entries a second. Above that the oldest pending entries go and the client is
138
+ * told how many, whatever speed it is reading at.
139
+ *
140
+ * It was 500, which put that ceiling at 2000/s. A healthy reader on a loopback
141
+ * socket lost 85% of a 20k burst to it — the cap fired on the server's own
142
+ * coalescing window rather than on any slowness at the client, which is a drop
143
+ * notice that says nothing true about why. 8000/s is past what one Node process
144
+ * serves, so reaching it now means genuinely more log than a person can be shown.
145
+ *
146
+ * The memory this bounds is the copy a *stalled* reader causes: roughly 2000
147
+ * entries, a few MB, per stuck connection.
148
+ */
149
+ var STREAM_MAX_PENDING = 2e3;
150
+ function createLogsRoutes(timing = {}) {
151
+ const flushMs = timing.flushMs ?? STREAM_FLUSH_MS;
152
+ const heartbeatMs = timing.heartbeatMs ?? STREAM_HEARTBEAT_MS;
153
+ const maxPending = timing.maxPending ?? STREAM_MAX_PENDING;
154
+ const app = new Hono();
155
+ app.get("/", (c) => {
156
+ const query = c.req.query();
157
+ const result = logBuffer.query({
158
+ level: query.level,
159
+ source: query.source,
160
+ search: query.search,
161
+ limit: query.limit ? parseInt(query.limit) : void 0,
162
+ offset: query.offset ? parseInt(query.offset) : void 0,
163
+ since: query.since
164
+ });
165
+ return c.json(result);
166
+ });
167
+ app.get("/latest", (c) => {
168
+ const count = parseInt(c.req.query("count") || "50");
169
+ return c.json({ entries: logBuffer.getLatest(count) });
170
+ });
171
+ app.get("/stream", (c) => {
172
+ const query = c.req.query();
173
+ const filter = normalizeFilter({
174
+ level: query.level,
175
+ source: query.source,
176
+ search: query.search
177
+ });
178
+ const limit = query.limit ? parseInt(query.limit) : 200;
179
+ c.header("X-Accel-Buffering", "no");
180
+ return streamSSE(c, async (stream) => {
181
+ let pending = [];
182
+ let dropped = 0;
183
+ const unsubscribe = logBuffer.subscribe((entry) => {
184
+ if (!matchesFilter(entry, filter)) return;
185
+ if (pending.length >= maxPending) {
186
+ pending.shift();
187
+ dropped++;
188
+ }
189
+ pending.push(entry);
190
+ });
191
+ const snapshot = logBuffer.query({
192
+ ...filter,
193
+ limit
194
+ });
195
+ const abortOnDisconnect = () => {
196
+ if (!stream.closed) stream.abort();
197
+ };
198
+ c.req.raw.signal.addEventListener("abort", abortOnDisconnect, { once: true });
199
+ if (c.req.raw.signal.aborted) abortOnDisconnect();
200
+ try {
201
+ await stream.writeSSE({
202
+ event: "snapshot",
203
+ data: JSON.stringify({
204
+ entries: snapshot.entries.slice().reverse(),
205
+ total: snapshot.total
206
+ })
207
+ });
208
+ let idleMs = 0;
209
+ while (!stream.aborted && !stream.closed) {
210
+ await stream.sleep(flushMs);
211
+ if (stream.aborted || stream.closed) break;
212
+ if (pending.length === 0) {
213
+ idleMs += flushMs;
214
+ if (idleMs >= heartbeatMs) {
215
+ await stream.write(": ping\n\n");
216
+ idleMs = 0;
217
+ }
218
+ continue;
219
+ }
220
+ const entries = pending;
221
+ const lost = dropped;
222
+ pending = [];
223
+ dropped = 0;
224
+ idleMs = 0;
225
+ await stream.writeSSE({
226
+ event: "append",
227
+ data: JSON.stringify(lost > 0 ? {
228
+ entries,
229
+ dropped: lost
230
+ } : { entries })
231
+ });
232
+ }
233
+ } finally {
234
+ unsubscribe();
235
+ c.req.raw.signal.removeEventListener("abort", abortOnDisconnect);
236
+ }
237
+ });
238
+ });
239
+ return app;
240
+ }
241
+ var logs_routes_default = createLogsRoutes();
242
+ //#endregion
243
+ export { logs_routes_exports as n, logMiddleware as t };
244
+
245
+ //# sourceMappingURL=logs-routes-CWBLQj2l.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs-routes-CWBLQj2l.js","names":[],"sources":["../src/api/logs-routes.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { MiddlewareHandler } from \"hono\";\nimport { streamSSE } from \"hono/streaming\";\nimport type { HonoEnv } from \"./types\";\n\nexport interface LogEntry {\n id: string;\n timestamp: string;\n level: \"debug\" | \"info\" | \"warn\" | \"error\";\n source: \"api\" | \"auth\" | \"storage\" | \"realtime\" | \"system\";\n message: string;\n metadata?: Record<string, unknown>;\n}\n\n/** What a caller can narrow the log by, in either direction (query or stream). */\nexport interface LogFilterOptions {\n level?: string;\n source?: string;\n search?: string;\n since?: string;\n}\n\n/**\n * A filter with the search term already lowercased.\n *\n * The distinction matters on the stream path: `query()` lowercases once and then\n * scans, but a subscriber tests one entry at a time and would otherwise redo the\n * same `toLowerCase()` on every request the server handles.\n */\ntype NormalizedFilter = LogFilterOptions;\n\nfunction normalizeFilter(options: LogFilterOptions): NormalizedFilter {\n return { ...options,\n search: options.search?.toLowerCase() };\n}\n\n/**\n * Whether one entry belongs in a filtered view.\n *\n * Shared by the query and the stream on purpose: two copies of this would drift,\n * and the failure that produces is invisible — a tail that quietly shows a\n * different set of lines than the snapshot it started from.\n */\nfunction matchesFilter(entry: LogEntry, filter: NormalizedFilter): boolean {\n if (filter.level && entry.level !== filter.level) return false;\n if (filter.source && entry.source !== filter.source) return false;\n if (filter.search && !entry.message.toLowerCase().includes(filter.search)) return false;\n if (filter.since && entry.timestamp < filter.since) return false;\n return true;\n}\n\n/** Notified for every entry pushed, in push order. */\nexport type LogListener = (entry: LogEntry) => void;\n\nclass LogRingBuffer {\n private buffer: LogEntry[] = [];\n private maxSize: number;\n private idCounter = 0;\n private listeners = new Set<LogListener>();\n\n constructor(maxSize = 10000) {\n this.maxSize = maxSize;\n }\n\n push(entry: Omit<LogEntry, \"id\">): void {\n const id = `log_${++this.idCounter}`;\n const stored: LogEntry = { ...entry,\n id };\n this.buffer.push(stored);\n if (this.buffer.length > this.maxSize) {\n this.buffer.shift();\n }\n // This runs on the request hot path, so a listener must never be able to\n // take the request down with it: a tail that throws loses its own tail,\n // not the response the log line was describing.\n for (const listener of this.listeners) {\n try {\n listener(stored);\n } catch {\n /* a broken tail is not the request's problem */\n }\n }\n }\n\n /**\n * Follow the buffer. Returns the unsubscribe — call it, always: a listener\n * left behind holds its whole closure, and on this class that closure is a\n * pending-entry array.\n *\n * A listener must not log. It is called from inside `push`, so anything that\n * reaches `addLog` from here recurses until the stack gives out.\n */\n subscribe(listener: LogListener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n query(options: LogFilterOptions & {\n limit?: number;\n offset?: number;\n }): { entries: LogEntry[]; total: number } {\n const filter = normalizeFilter(options);\n const filtered = this.buffer.filter(e => matchesFilter(e, filter));\n\n // Newest first\n const sorted = [...filtered].reverse();\n const total = sorted.length;\n const limit = options.limit || 100;\n const offset = options.offset || 0;\n\n return {\n entries: sorted.slice(offset, offset + limit),\n total\n };\n }\n\n getLatest(count = 50): LogEntry[] {\n return this.buffer.slice(-count).reverse();\n }\n}\n\n// Global singleton\nexport const logBuffer = new LogRingBuffer();\n\n/** Add a log entry */\nexport function addLog(\n level: LogEntry[\"level\"],\n source: LogEntry[\"source\"],\n message: string,\n metadata?: Record<string, unknown>\n): void {\n logBuffer.push({\n timestamp: new Date().toISOString(),\n level,\n source,\n message,\n metadata\n });\n}\n\nexport interface LogMiddlewareOptions {\n /**\n * Paths this sink ignores, matched exactly against `c.req.path`.\n *\n * For requests whose only reason to exist is to read the log. Recording\n * those makes the reader the loudest thing in its own output, and on a quiet\n * server it is also the thing evicting real entries out of the ring.\n */\n ignorePaths?: string[];\n}\n\n/** Hono middleware to log API requests */\nexport function logMiddleware(options: LogMiddlewareOptions = {}): MiddlewareHandler<HonoEnv> {\n const ignored = new Set(options.ignorePaths ?? []);\n return async (c, next) => {\n const start = Date.now();\n await next();\n if (ignored.has(c.req.path)) return;\n const duration = Date.now() - start;\n const reqId = c.get(\"requestId\");\n addLog(\"info\", \"api\", `${c.req.method} ${c.req.path} ${c.res.status} ${duration}ms`, {\n method: c.req.method,\n path: c.req.path,\n status: c.res.status,\n duration,\n ...(reqId && { requestId: reqId })\n });\n };\n}\n\n/**\n * How long entries accumulate before a batch goes out.\n *\n * Not zero, and that is the point. A busy server logs faster than a browser can\n * render, and one SSE frame per line would hand the client a re-render per\n * request served — worse than the 3s poll this replaces, precisely when the logs\n * are worth watching. Coalescing keeps the frame rate bounded by the window\n * rather than by traffic, and 250ms still reads as \"live\" to a person.\n */\nconst STREAM_FLUSH_MS = 250;\n\n/**\n * Idle gap after which the stream sends a comment line.\n *\n * A silent SSE connection is indistinguishable from a dead one to everything in\n * between — proxies, load balancers and laptop NICs all reap idle sockets, and a\n * server with nothing to say is the normal state here.\n */\nconst STREAM_HEARTBEAT_MS = 25_000;\n\n/**\n * Entries a single connection will hold between flushes.\n *\n * This is a *rate* ceiling, not just a memory bound, and that is easy to get\n * wrong: nothing drains `pending` between flushes, so the most a connection can\n * carry losslessly is `maxPending` per `flushMs` — here 2000 per 250ms, or 8000\n * entries a second. Above that the oldest pending entries go and the client is\n * told how many, whatever speed it is reading at.\n *\n * It was 500, which put that ceiling at 2000/s. A healthy reader on a loopback\n * socket lost 85% of a 20k burst to it — the cap fired on the server's own\n * coalescing window rather than on any slowness at the client, which is a drop\n * notice that says nothing true about why. 8000/s is past what one Node process\n * serves, so reaching it now means genuinely more log than a person can be shown.\n *\n * The memory this bounds is the copy a *stalled* reader causes: roughly 2000\n * entries, a few MB, per stuck connection.\n */\nconst STREAM_MAX_PENDING = 2000;\n\n/**\n * The stream's timings, injectable only so they can be tested.\n *\n * The defaults above are the contract and nothing in production passes this. A\n * heartbeat is a 25-second wait to observe, and a suite that cannot observe it is\n * a suite where the keepalive can rot — which surfaces as \"the tail dies after a\n * few minutes behind the load balancer\", months later, on someone else's cluster.\n */\nexport interface LogStreamTiming {\n flushMs?: number;\n heartbeatMs?: number;\n maxPending?: number;\n}\n\nexport function createLogsRoutes(timing: LogStreamTiming = {}): Hono<HonoEnv> {\n const flushMs = timing.flushMs ?? STREAM_FLUSH_MS;\n const heartbeatMs = timing.heartbeatMs ?? STREAM_HEARTBEAT_MS;\n const maxPending = timing.maxPending ?? STREAM_MAX_PENDING;\n\n const app = new Hono<HonoEnv>();\n\n // GET /api/logs — Query logs\n app.get(\"/\", (c) => {\n const query = c.req.query();\n const result = logBuffer.query({\n level: query.level,\n source: query.source,\n search: query.search,\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n since: query.since\n });\n return c.json(result);\n });\n\n // GET /api/logs/latest — Get latest logs (for real-time)\n app.get(\"/latest\", (c) => {\n const count = parseInt(c.req.query(\"count\") || \"50\");\n return c.json({ entries: logBuffer.getLatest(count) });\n });\n\n // GET /api/logs/stream — tail the buffer over SSE.\n //\n // The Logs Explorer used to poll this router every 3 seconds, which cost a\n // request per client per 3s to say \"nothing happened\" and still showed each\n // line up to 3s late. Here the buffer pushes instead, so an idle server is an\n // idle socket.\n //\n // Events:\n // snapshot {entries, total} the filtered window, oldest-first, at open\n // append {entries, dropped} entries since the last frame, oldest-first\n // `: ping` comment, keepalive only\n //\n // Snapshot and appends come down the same connection deliberately. A client\n // that fetched its backlog separately would race the subscription — entries\n // logged between the two calls belong to neither — and closing that race from\n // the outside needs an id cursor and dedupe on every frame.\n app.get(\"/stream\", (c) => {\n const query = c.req.query();\n const filter = normalizeFilter({\n level: query.level,\n source: query.source,\n search: query.search\n });\n const limit = query.limit ? parseInt(query.limit) : 200;\n\n // Reverse proxies buffer text responses by default, which turns a live\n // tail into nothing at all until the buffer fills. nginx (and the ingress\n // in front of the managed runtime) reads this header; everything else\n // ignores it. The rest of the SSE headers are set by `streamSSE`.\n c.header(\"X-Accel-Buffering\", \"no\");\n\n return streamSSE(c, async (stream) => {\n let pending: LogEntry[] = [];\n let dropped = 0;\n\n // Subscribe *before* reading the backlog, with nothing awaited\n // between the two. Both are synchronous, so the two halves meet\n // exactly: an entry logged after the query but before the\n // subscription would otherwise be in neither, and that gap is the one\n // thing this route exists to close.\n const unsubscribe = logBuffer.subscribe(entry => {\n if (!matchesFilter(entry, filter)) return;\n if (pending.length >= maxPending) {\n pending.shift();\n dropped++;\n }\n pending.push(entry);\n });\n const snapshot = logBuffer.query({ ...filter,\n limit });\n\n // A client that goes away has to end this handler, or the\n // subscription outlives the socket. `streamSSE` only wires the\n // request signal through on old Bun, so do it here and let\n // `stream.aborted` be the one condition the loop tests.\n //\n // The `aborted` check is not belt-and-braces. A listener added to an\n // already-aborted signal is never called, so a client that leaves\n // during the snapshot write — a fast navigation, or a reconnect storm\n // against a restarting server — would leave this handler with no way\n // to learn it had gone: a subscriber and a flush loop, per attempt,\n // for the life of the process.\n const abortOnDisconnect = () => {\n if (!stream.closed) stream.abort();\n };\n c.req.raw.signal.addEventListener(\"abort\", abortOnDisconnect, { once: true });\n if (c.req.raw.signal.aborted) abortOnDisconnect();\n\n try {\n await stream.writeSSE({\n event: \"snapshot\",\n // The view tails like a terminal; both frames are oldest-first\n // so the client only ever appends.\n data: JSON.stringify({\n entries: snapshot.entries.slice().reverse(),\n total: snapshot.total\n })\n });\n\n let idleMs = 0;\n while (!stream.aborted && !stream.closed) {\n await stream.sleep(flushMs);\n if (stream.aborted || stream.closed) break;\n\n if (pending.length === 0) {\n idleMs += flushMs;\n if (idleMs >= heartbeatMs) {\n await stream.write(\": ping\\n\\n\");\n idleMs = 0;\n }\n continue;\n }\n\n const entries = pending;\n const lost = dropped;\n pending = [];\n dropped = 0;\n idleMs = 0;\n await stream.writeSSE({\n event: \"append\",\n data: JSON.stringify(lost > 0 ? { entries,\n dropped: lost } : { entries })\n });\n }\n } finally {\n unsubscribe();\n c.req.raw.signal.removeEventListener(\"abort\", abortOnDisconnect);\n }\n });\n });\n\n return app;\n}\n\nexport default createLogsRoutes();\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  import "process";
3
3
  __createRequire(import.meta.url);
4
- import { y as resolveCollectionRelations } from "./src-8XDWyDfR.js";
5
- import "./src-Cz9nMgUR.js";
4
+ import { y as resolveCollectionRelations } from "./src-B-E7RjdN.js";
5
+ import "./src-CrCxd8km.js";
6
6
  //#region ../types/src/types/relations.ts
7
7
  /** @group Models */
8
8
  function isToMany(relation) {
@@ -927,4 +927,4 @@ function toPascalCase(str) {
927
927
  //#endregion
928
928
  export { generateOpenApiSpec };
929
929
 
930
- //# sourceMappingURL=openapi-generator-DQeQ_q2f.js.map
930
+ //# sourceMappingURL=openapi-generator-DLiiGD9X.js.map