silgi 0.0.14 → 0.1.0-beta.2

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 (186) hide show
  1. package/README.md +102 -1
  2. package/dist/_virtual/_rolldown/runtime.mjs +5 -0
  3. package/dist/adapters/astro.d.mts +17 -0
  4. package/dist/adapters/astro.mjs +24 -0
  5. package/dist/adapters/aws-lambda.d.mts +31 -0
  6. package/dist/adapters/aws-lambda.mjs +85 -0
  7. package/dist/adapters/elysia.d.mts +17 -0
  8. package/dist/adapters/elysia.mjs +76 -0
  9. package/dist/adapters/express.d.mts +16 -0
  10. package/dist/adapters/express.mjs +78 -0
  11. package/dist/adapters/fastify.d.mts +15 -0
  12. package/dist/adapters/fastify.mjs +78 -0
  13. package/dist/adapters/message-port.d.mts +37 -0
  14. package/dist/adapters/message-port.mjs +129 -0
  15. package/dist/adapters/nestjs.d.mts +25 -0
  16. package/dist/adapters/nestjs.mjs +91 -0
  17. package/dist/adapters/nextjs.d.mts +21 -0
  18. package/dist/adapters/nextjs.mjs +30 -0
  19. package/dist/adapters/peer.d.mts +27 -0
  20. package/dist/adapters/peer.mjs +36 -0
  21. package/dist/adapters/remix.d.mts +17 -0
  22. package/dist/adapters/remix.mjs +24 -0
  23. package/dist/adapters/solidstart.d.mts +14 -0
  24. package/dist/adapters/solidstart.mjs +30 -0
  25. package/dist/adapters/sveltekit.d.mts +18 -0
  26. package/dist/adapters/sveltekit.mjs +33 -0
  27. package/dist/analyze.mjs +26 -0
  28. package/dist/broker/index.d.mts +62 -0
  29. package/dist/broker/index.mjs +153 -0
  30. package/dist/broker/nats.d.mts +33 -0
  31. package/dist/broker/nats.mjs +31 -0
  32. package/dist/broker/redis.d.mts +51 -0
  33. package/dist/broker/redis.mjs +92 -0
  34. package/dist/builder.d.mts +36 -0
  35. package/dist/builder.mjs +51 -0
  36. package/dist/callable.d.mts +17 -0
  37. package/dist/callable.mjs +42 -0
  38. package/dist/client/adapters/fetch/index.d.mts +17 -0
  39. package/dist/client/adapters/fetch/index.mjs +61 -0
  40. package/dist/client/adapters/ofetch/index.d.mts +41 -0
  41. package/dist/client/adapters/ofetch/index.mjs +92 -0
  42. package/dist/client/client.d.mts +29 -0
  43. package/dist/client/client.mjs +54 -0
  44. package/dist/client/dynamic-link.d.mts +15 -0
  45. package/dist/client/dynamic-link.mjs +16 -0
  46. package/dist/client/index.d.mts +7 -0
  47. package/dist/client/index.mjs +6 -0
  48. package/dist/client/interceptor.d.mts +31 -0
  49. package/dist/client/interceptor.mjs +34 -0
  50. package/dist/client/merge.d.mts +28 -0
  51. package/dist/client/merge.mjs +30 -0
  52. package/dist/client/openapi.d.mts +29 -0
  53. package/dist/client/openapi.mjs +89 -0
  54. package/dist/client/plugins/batch.d.mts +20 -0
  55. package/dist/client/plugins/batch.mjs +64 -0
  56. package/dist/client/plugins/csrf.d.mts +13 -0
  57. package/dist/client/plugins/csrf.mjs +20 -0
  58. package/dist/client/plugins/dedupe.d.mts +10 -0
  59. package/dist/client/plugins/dedupe.mjs +28 -0
  60. package/dist/client/plugins/index.d.mts +5 -0
  61. package/dist/client/plugins/index.mjs +5 -0
  62. package/dist/client/plugins/retry.d.mts +11 -0
  63. package/dist/client/plugins/retry.mjs +21 -0
  64. package/dist/client/server.d.mts +16 -0
  65. package/dist/client/server.mjs +60 -0
  66. package/dist/client/types.d.mts +29 -0
  67. package/dist/codec/devalue.d.mts +21 -0
  68. package/dist/codec/devalue.mjs +32 -0
  69. package/dist/codec/msgpack.d.mts +21 -0
  70. package/dist/codec/msgpack.mjs +59 -0
  71. package/dist/compile.d.mts +54 -0
  72. package/dist/compile.mjs +305 -0
  73. package/dist/contract.d.mts +36 -0
  74. package/dist/contract.mjs +40 -0
  75. package/dist/core/error.d.mts +104 -0
  76. package/dist/core/error.mjs +139 -0
  77. package/dist/core/handler.mjs +546 -0
  78. package/dist/core/iterator.d.mts +17 -0
  79. package/dist/core/iterator.mjs +79 -0
  80. package/dist/core/router-utils.mjs +16 -0
  81. package/dist/core/schema.d.mts +19 -0
  82. package/dist/core/schema.mjs +26 -0
  83. package/dist/core/serve.mjs +38 -0
  84. package/dist/core/sse.d.mts +16 -0
  85. package/dist/core/sse.mjs +95 -0
  86. package/dist/core/storage.d.mts +21 -0
  87. package/dist/core/storage.mjs +63 -0
  88. package/dist/core/utils.mjs +21 -0
  89. package/dist/fast-stringify.mjs +125 -0
  90. package/dist/index.d.mts +15 -37
  91. package/dist/index.mjs +13 -7
  92. package/dist/integrations/ai/index.d.mts +25 -0
  93. package/dist/integrations/ai/index.mjs +116 -0
  94. package/dist/integrations/react/index.d.mts +83 -0
  95. package/dist/integrations/react/index.mjs +197 -0
  96. package/dist/integrations/tanstack-query/index.d.mts +120 -0
  97. package/dist/integrations/tanstack-query/index.mjs +100 -0
  98. package/dist/integrations/tanstack-query/ssr.d.mts +51 -0
  99. package/dist/integrations/tanstack-query/ssr.mjs +89 -0
  100. package/dist/integrations/zod/converter.d.mts +75 -0
  101. package/dist/integrations/zod/converter.mjs +345 -0
  102. package/dist/integrations/zod/index.d.mts +2 -0
  103. package/dist/integrations/zod/index.mjs +2 -0
  104. package/dist/lazy.d.mts +24 -0
  105. package/dist/lazy.mjs +27 -0
  106. package/dist/lifecycle.d.mts +36 -0
  107. package/dist/lifecycle.mjs +46 -0
  108. package/dist/map-input.d.mts +17 -0
  109. package/dist/map-input.mjs +24 -0
  110. package/dist/plugins/analytics.d.mts +168 -0
  111. package/dist/plugins/analytics.mjs +459 -0
  112. package/dist/plugins/batch-server.d.mts +20 -0
  113. package/dist/plugins/batch-server.mjs +86 -0
  114. package/dist/plugins/body-limit.d.mts +16 -0
  115. package/dist/plugins/body-limit.mjs +44 -0
  116. package/dist/plugins/cache.d.mts +170 -0
  117. package/dist/plugins/cache.mjs +200 -0
  118. package/dist/plugins/coerce.d.mts +21 -0
  119. package/dist/plugins/coerce.mjs +46 -0
  120. package/dist/plugins/compression.d.mts +19 -0
  121. package/dist/plugins/compression.mjs +23 -0
  122. package/dist/plugins/cookies.d.mts +44 -0
  123. package/dist/plugins/cookies.mjs +67 -0
  124. package/dist/plugins/cors.d.mts +39 -0
  125. package/dist/plugins/cors.mjs +56 -0
  126. package/dist/plugins/custom-serializer.d.mts +57 -0
  127. package/dist/plugins/custom-serializer.mjs +40 -0
  128. package/dist/plugins/file-upload.d.mts +38 -0
  129. package/dist/plugins/file-upload.mjs +100 -0
  130. package/dist/plugins/index.d.mts +16 -0
  131. package/dist/plugins/index.mjs +16 -0
  132. package/dist/plugins/otel.d.mts +35 -0
  133. package/dist/plugins/otel.mjs +40 -0
  134. package/dist/plugins/pino.d.mts +60 -0
  135. package/dist/plugins/pino.mjs +42 -0
  136. package/dist/plugins/pubsub.d.mts +50 -0
  137. package/dist/plugins/pubsub.mjs +53 -0
  138. package/dist/plugins/ratelimit.d.mts +51 -0
  139. package/dist/plugins/ratelimit.mjs +81 -0
  140. package/dist/plugins/signing.d.mts +41 -0
  141. package/dist/plugins/signing.mjs +115 -0
  142. package/dist/plugins/strict-get.d.mts +10 -0
  143. package/dist/plugins/strict-get.mjs +33 -0
  144. package/dist/route/add.mjs +240 -0
  145. package/dist/route/compiler.mjs +373 -0
  146. package/dist/route/context.mjs +12 -0
  147. package/dist/route/types.d.mts +11 -0
  148. package/dist/route/utils.mjs +17 -0
  149. package/dist/scalar.d.mts +53 -0
  150. package/dist/scalar.mjs +330 -0
  151. package/dist/silgi.d.mts +139 -0
  152. package/dist/silgi.mjs +113 -0
  153. package/dist/trpc-interop.d.mts +22 -0
  154. package/dist/trpc-interop.mjs +68 -0
  155. package/dist/types.d.mts +82 -0
  156. package/dist/ws.d.mts +42 -0
  157. package/dist/ws.mjs +137 -0
  158. package/lib/dashboard/index.html +123 -0
  159. package/lib/ocache.d.mts +1 -0
  160. package/lib/ocache.mjs +1 -0
  161. package/lib/ofetch.d.mts +1 -0
  162. package/lib/ofetch.mjs +1 -0
  163. package/lib/srvx.d.mts +1 -0
  164. package/lib/srvx.mjs +1 -0
  165. package/lib/unstorage.d.mts +1 -0
  166. package/lib/unstorage.mjs +1 -0
  167. package/package.json +291 -65
  168. package/bin/silgi.mjs +0 -3
  169. package/dist/chunks/generate.mjs +0 -933
  170. package/dist/chunks/init.mjs +0 -21
  171. package/dist/cli/config.d.mts +0 -19
  172. package/dist/cli/config.d.ts +0 -19
  173. package/dist/cli/config.mjs +0 -5
  174. package/dist/cli/index.d.mts +0 -2
  175. package/dist/cli/index.d.ts +0 -2
  176. package/dist/cli/index.mjs +0 -119
  177. package/dist/index.d.ts +0 -37
  178. package/dist/plugins/openapi.d.mts +0 -138
  179. package/dist/plugins/openapi.d.ts +0 -138
  180. package/dist/plugins/openapi.mjs +0 -204
  181. package/dist/plugins/scalar.d.mts +0 -14
  182. package/dist/plugins/scalar.d.ts +0 -14
  183. package/dist/plugins/scalar.mjs +0 -66
  184. package/dist/shared/silgi.BMCYk2cR.mjs +0 -841
  185. package/dist/shared/silgi.D5qK9QOm.d.mts +0 -301
  186. package/dist/shared/silgi.D5qK9QOm.d.ts +0 -301
@@ -0,0 +1,546 @@
1
+ import { SilgiError, toSilgiError } from "./error.mjs";
2
+ import { ValidationError } from "./schema.mjs";
3
+ import { ContextPool, compileRouter } from "../compile.mjs";
4
+ import { AnalyticsCollector, RequestAccumulator, RequestTrace, analyticsHTML, errorToMarkdown, requestToMarkdown } from "../plugins/analytics.mjs";
5
+ import { generateOpenAPI, scalarHTML } from "../scalar.mjs";
6
+ import { routerCache } from "./router-utils.mjs";
7
+ import { stringifyJSON } from "./utils.mjs";
8
+ import { iteratorToEventStream } from "./sse.mjs";
9
+ //#region src/core/handler.ts
10
+ let _msgpack;
11
+ let _devalue;
12
+ async function encodeResponse(data, status, format, jsonStringify, extraHeaders) {
13
+ switch (format) {
14
+ case "msgpack":
15
+ _msgpack ??= await import("../codec/msgpack.mjs");
16
+ return new Response(_msgpack.encode(data), {
17
+ status,
18
+ headers: {
19
+ "content-type": _msgpack.MSGPACK_CONTENT_TYPE,
20
+ ...extraHeaders
21
+ }
22
+ });
23
+ case "devalue":
24
+ _devalue ??= await import("../codec/devalue.mjs");
25
+ return new Response(_devalue.encode(data), {
26
+ status,
27
+ headers: {
28
+ "content-type": _devalue.DEVALUE_CONTENT_TYPE,
29
+ ...extraHeaders
30
+ }
31
+ });
32
+ default: return new Response(jsonStringify ? jsonStringify(data) : stringifyJSON(data), {
33
+ status,
34
+ headers: {
35
+ "content-type": "application/json",
36
+ ...extraHeaders
37
+ }
38
+ });
39
+ }
40
+ }
41
+ function round(n) {
42
+ return Math.round(n * 100) / 100;
43
+ }
44
+ function checkAnalyticsAuth(request, rawUrl, auth) {
45
+ if (typeof auth === "function") return auth(request);
46
+ const cookie = request.headers.get("cookie");
47
+ if (cookie) {
48
+ const match = cookie.match(/(?:^|;\s*)silgi-auth=([^;]*)/);
49
+ if (match && decodeURIComponent(match[1]) === auth) return true;
50
+ }
51
+ if (request.headers.get("authorization") === `Bearer ${auth}`) return true;
52
+ const tokenIdx = rawUrl.indexOf("token=");
53
+ if (tokenIdx !== -1) {
54
+ const valueStart = tokenIdx + 6;
55
+ const valueEnd = rawUrl.indexOf("&", valueStart);
56
+ const token = valueEnd === -1 ? rawUrl.slice(valueStart) : rawUrl.slice(valueStart, valueEnd);
57
+ if (decodeURIComponent(token) === auth) return true;
58
+ }
59
+ return false;
60
+ }
61
+ function createFetchHandler(routerDef, contextFactory, hooks, handlerOptions) {
62
+ let compiledRouter = routerCache.get(routerDef);
63
+ if (!compiledRouter) {
64
+ compiledRouter = compileRouter(routerDef);
65
+ routerCache.set(routerDef, compiledRouter);
66
+ }
67
+ const ctxPool = new ContextPool();
68
+ const jsonHeaders = { "content-type": "application/json" };
69
+ const emptyCtx = Object.create(null);
70
+ const sseHeaders = {
71
+ "content-type": "text/event-stream",
72
+ "cache-control": "no-cache"
73
+ };
74
+ const notFoundBody = JSON.stringify({
75
+ code: "NOT_FOUND",
76
+ status: 404,
77
+ message: "Procedure not found"
78
+ });
79
+ const scalarEnabled = !!handlerOptions?.scalar;
80
+ let specJson;
81
+ let specHtml;
82
+ if (scalarEnabled) {
83
+ const scalarOpts = typeof handlerOptions.scalar === "object" ? handlerOptions.scalar : {};
84
+ specJson = JSON.stringify(generateOpenAPI(routerDef, scalarOpts));
85
+ specHtml = scalarHTML("/openapi.json", scalarOpts);
86
+ }
87
+ const analyticsEnabled = !!handlerOptions?.analytics;
88
+ let collector;
89
+ let analyticsDashboardHtml;
90
+ let analyticsAuth;
91
+ if (analyticsEnabled) {
92
+ const analyticsOpts = typeof handlerOptions.analytics === "object" ? handlerOptions.analytics : {};
93
+ collector = new AnalyticsCollector(analyticsOpts);
94
+ analyticsDashboardHtml = analyticsHTML();
95
+ analyticsAuth = analyticsOpts.auth;
96
+ }
97
+ const analyticsLoginHTML = `<!doctype html>
98
+ <html lang="en">
99
+ <head>
100
+ <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
101
+ <title>Silgi Analytics</title>
102
+ <style>
103
+ *{margin:0;padding:0;box-sizing:border-box}
104
+ body{font-family:system-ui,-apple-system,sans-serif;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#0a0a0a;color:#e5e5e5}
105
+ .c{width:100%;max-width:360px;padding:0 24px}
106
+ .logo{display:flex;align-items:center;gap:8px;margin-bottom:20px}
107
+ .logo svg{width:20px;height:20px;color:#c2822a}
108
+ .logo span{font-size:14px;font-weight:600;letter-spacing:-.01em}
109
+ p{font-size:13px;color:#737373;margin-bottom:16px;line-height:1.5}
110
+ input{width:100%;height:40px;padding:0 12px;background:#171717;border:1px solid #262626;border-radius:6px;color:#e5e5e5;font-size:13px;outline:none}
111
+ input:focus{border-color:#c2822a}
112
+ input::placeholder{color:#525252}
113
+ button{width:100%;height:36px;margin-top:10px;background:#c2822a;color:#0a0a0a;border:none;border-radius:6px;font-size:13px;font-weight:500;cursor:pointer}
114
+ button:hover{background:#d4943b}
115
+ .err{color:#ef4444;font-size:12px;margin-top:8px;display:none}
116
+ </style>
117
+ </head>
118
+ <body>
119
+ <div class="c">
120
+ <div class="logo"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg><span>Silgi Analytics</span></div>
121
+ <p>Enter your access token to view the dashboard.</p>
122
+ <form id="f"><input id="t" type="password" placeholder="Access token" autofocus><div class="err" id="e">Invalid token</div><button type="submit">Authenticate</button></form>
123
+ </div>
124
+ <script>
125
+ document.getElementById('f').onsubmit=function(e){
126
+ e.preventDefault();
127
+ var t=document.getElementById('t').value.trim();
128
+ if(!t)return;
129
+ document.cookie='silgi-auth='+encodeURIComponent(t)+';path=/analytics;samesite=strict';
130
+ fetch('/analytics/_api/stats',{headers:{'cookie':'silgi-auth='+encodeURIComponent(t)}}).then(function(){
131
+ location.reload();
132
+ }).catch(function(){location.reload()});
133
+ };
134
+ <\/script>
135
+ </body>
136
+ </html>`;
137
+ const hasHooks = !!hooks;
138
+ const isBun = typeof globalThis.Bun !== "undefined";
139
+ let ctxFactoryIsSync = false;
140
+ let ctxFactoryIsEmpty = false;
141
+ try {
142
+ const testResult = contextFactory(new Request("http://localhost"));
143
+ if (testResult instanceof Promise) testResult.then((r) => {
144
+ ctxFactoryIsEmpty = Object.keys(r).length === 0;
145
+ });
146
+ else {
147
+ ctxFactoryIsSync = true;
148
+ ctxFactoryIsEmpty = Object.keys(testResult).length === 0;
149
+ }
150
+ } catch {}
151
+ function analyticsAuthResponse(pathname) {
152
+ if (pathname.includes("_api/")) return new Response(JSON.stringify({
153
+ code: "UNAUTHORIZED",
154
+ status: 401,
155
+ message: "Invalid token"
156
+ }), {
157
+ status: 401,
158
+ headers: jsonHeaders
159
+ });
160
+ return new Response(analyticsLoginHTML, {
161
+ status: 401,
162
+ headers: { "content-type": "text/html" }
163
+ });
164
+ }
165
+ function serveAnalytics(pathname, col) {
166
+ if (pathname === "analytics/_api/stats") return new Response(JSON.stringify(col.toJSON()), { headers: {
167
+ "content-type": "application/json",
168
+ "cache-control": "no-cache"
169
+ } });
170
+ if (pathname === "analytics/_api/errors") return new Response(JSON.stringify(col.getErrors()), { headers: {
171
+ "content-type": "application/json",
172
+ "cache-control": "no-cache"
173
+ } });
174
+ if (pathname === "analytics/_api/requests") return new Response(JSON.stringify(col.getRequests()), { headers: {
175
+ "content-type": "application/json",
176
+ "cache-control": "no-cache"
177
+ } });
178
+ if (pathname.startsWith("analytics/_api/requests/") && pathname.endsWith("/md")) {
179
+ const id = Number(pathname.slice(24, -3));
180
+ const entry = col.getRequests().find((r) => r.id === id);
181
+ if (entry) return new Response(requestToMarkdown(entry), { headers: {
182
+ "content-type": "text/markdown; charset=utf-8",
183
+ "cache-control": "no-cache"
184
+ } });
185
+ return new Response("not found", { status: 404 });
186
+ }
187
+ if (pathname.startsWith("analytics/_api/errors/") && pathname.endsWith("/md")) {
188
+ const id = Number(pathname.slice(22, -3));
189
+ const entry = col.getErrors().find((e) => e.id === id);
190
+ if (entry) return new Response(errorToMarkdown(entry), { headers: {
191
+ "content-type": "text/markdown; charset=utf-8",
192
+ "cache-control": "no-cache"
193
+ } });
194
+ return new Response("not found", { status: 404 });
195
+ }
196
+ if (pathname === "analytics/_api/errors/md") {
197
+ const errors = col.getErrors();
198
+ const md = errors.length === 0 ? "No errors.\n" : `# Errors (${errors.length})\n\n` + errors.map((e) => errorToMarkdown(e)).join("\n\n---\n\n");
199
+ return new Response(md, { headers: {
200
+ "content-type": "text/markdown; charset=utf-8",
201
+ "cache-control": "no-cache"
202
+ } });
203
+ }
204
+ return new Response(analyticsDashboardHtml, { headers: { "content-type": "text/html" } });
205
+ }
206
+ function handleRequest(request) {
207
+ const url = request.url;
208
+ const pathStart = url.indexOf("/", url.indexOf("//") + 2);
209
+ const qMark = url.indexOf("?", pathStart);
210
+ const fullPath = qMark === -1 ? url.slice(pathStart) : url.slice(pathStart, qMark);
211
+ const pathname = fullPath.length > 1 ? fullPath.slice(1) : "";
212
+ const accumulator = request.__acc ?? (collector ? new RequestAccumulator(request, collector) : void 0);
213
+ if (scalarEnabled) {
214
+ if (pathname === "openapi.json") return new Response(specJson, { headers: { "content-type": "application/json" } });
215
+ if (pathname === "reference") return new Response(specHtml, { headers: { "content-type": "text/html" } });
216
+ }
217
+ if (analyticsEnabled && collector && pathname.startsWith("analytics")) {
218
+ if (analyticsAuth) {
219
+ const authResult = checkAnalyticsAuth(request, url, analyticsAuth);
220
+ if (authResult instanceof Promise) return authResult.then((ok) => {
221
+ if (!ok) return analyticsAuthResponse(pathname);
222
+ return serveAnalytics(pathname, collector);
223
+ });
224
+ if (!authResult) return analyticsAuthResponse(pathname);
225
+ }
226
+ return serveAnalytics(pathname, collector);
227
+ }
228
+ const match = compiledRouter(request.method, fullPath);
229
+ if (!match) return new Response(notFoundBody, {
230
+ status: 404,
231
+ headers: jsonHeaders
232
+ });
233
+ const route = match.data;
234
+ const method = request.method;
235
+ if (ctxFactoryIsSync && (method === "GET" || !request.body || route.passthrough)) {
236
+ const usePool = !ctxFactoryIsEmpty || match.params || collector;
237
+ const ctx = usePool ? ctxPool.borrow() : emptyCtx;
238
+ let t0 = 0;
239
+ let reqTrace;
240
+ let rawInput;
241
+ try {
242
+ if (!ctxFactoryIsEmpty) {
243
+ const baseCtx = contextFactory(request);
244
+ const keys = Object.keys(baseCtx);
245
+ for (let i = 0; i < keys.length; i++) ctx[keys[i]] = baseCtx[keys[i]];
246
+ }
247
+ if (match.params) ctx.params = match.params;
248
+ if (collector) {
249
+ reqTrace = new RequestTrace();
250
+ ctx.__analyticsTrace = reqTrace;
251
+ ctx.trace = reqTrace.trace.bind(reqTrace);
252
+ }
253
+ if (method === "GET" && qMark !== -1) {
254
+ const searchStr = url.slice(qMark + 1);
255
+ const dataIdx = searchStr.indexOf("data=");
256
+ if (dataIdx !== -1) {
257
+ const valueStart = dataIdx + 5;
258
+ const valueEnd = searchStr.indexOf("&", valueStart);
259
+ const encoded = valueEnd === -1 ? searchStr.slice(valueStart) : searchStr.slice(valueStart, valueEnd);
260
+ rawInput = JSON.parse(decodeURIComponent(encoded));
261
+ }
262
+ }
263
+ if (hasHooks) hooks.callHook("request", {
264
+ path: pathname,
265
+ input: rawInput
266
+ });
267
+ t0 = collector ? performance.now() : 0;
268
+ const pipelineResult = route.handler(ctx, rawInput, request.signal);
269
+ if (!(pipelineResult instanceof Promise)) {
270
+ const output = pipelineResult;
271
+ if (hasHooks || collector) {
272
+ const durationMs = collector ? round(performance.now() - t0) : 0;
273
+ if (hasHooks) hooks.callHook("response", {
274
+ path: pathname,
275
+ output,
276
+ durationMs
277
+ });
278
+ if (collector) {
279
+ collector.record(pathname, durationMs);
280
+ if (accumulator) accumulator.addProcedure({
281
+ procedure: pathname,
282
+ durationMs,
283
+ status: 200,
284
+ input: rawInput,
285
+ output,
286
+ spans: reqTrace?.spans ?? []
287
+ });
288
+ }
289
+ }
290
+ if (output instanceof Response) return output;
291
+ if (output instanceof ReadableStream) {
292
+ if (collector && accumulator) accumulator.addProcedure({
293
+ procedure: pathname,
294
+ durationMs: collector ? round(performance.now() - t0) : 0,
295
+ status: 200,
296
+ input: rawInput,
297
+ output: null,
298
+ spans: reqTrace?.spans ?? []
299
+ });
300
+ return new Response(output, { headers: { "content-type": "application/octet-stream" } });
301
+ }
302
+ if (output && typeof output === "object" && Symbol.asyncIterator in output) {
303
+ if (collector && accumulator) accumulator.addProcedure({
304
+ procedure: pathname,
305
+ durationMs: collector ? round(performance.now() - t0) : 0,
306
+ status: 200,
307
+ input: rawInput,
308
+ output: null,
309
+ spans: reqTrace?.spans ?? []
310
+ });
311
+ return new Response(iteratorToEventStream(output), { headers: sseHeaders });
312
+ }
313
+ const accept = request.headers.get("accept");
314
+ if (accept && (accept.includes("msgpack") || accept.includes("x-devalue"))) {
315
+ const fmt = accept.includes("msgpack") ? "msgpack" : "devalue";
316
+ const cacheHeaders = route.cacheControl ? { "cache-control": route.cacheControl } : void 0;
317
+ return encodeResponse(output, 200, fmt, route.stringify, cacheHeaders);
318
+ }
319
+ const cacheHeaders = route.cacheControl ? { "cache-control": route.cacheControl } : void 0;
320
+ return new Response(route.stringify(output), { headers: cacheHeaders ? {
321
+ ...jsonHeaders,
322
+ ...cacheHeaders
323
+ } : jsonHeaders });
324
+ }
325
+ return pipelineResult.then((output) => {
326
+ const durationMs = collector ? round(performance.now() - t0) : 0;
327
+ if (hasHooks) hooks.callHook("response", {
328
+ path: pathname,
329
+ output,
330
+ durationMs
331
+ });
332
+ if (collector) {
333
+ collector.record(pathname, durationMs);
334
+ if (accumulator) accumulator.addProcedure({
335
+ procedure: pathname,
336
+ durationMs,
337
+ status: 200,
338
+ input: rawInput,
339
+ output,
340
+ spans: reqTrace?.spans ?? []
341
+ });
342
+ }
343
+ if (output instanceof Response) return output;
344
+ if (output instanceof ReadableStream) return new Response(output, { headers: { "content-type": "application/octet-stream" } });
345
+ if (output && typeof output === "object" && Symbol.asyncIterator in output) return new Response(iteratorToEventStream(output), { headers: sseHeaders });
346
+ const cacheHeaders = route.cacheControl ? { "cache-control": route.cacheControl } : void 0;
347
+ return new Response(route.stringify(output), { headers: cacheHeaders ? {
348
+ ...jsonHeaders,
349
+ ...cacheHeaders
350
+ } : jsonHeaders });
351
+ }).catch((error) => handleError(error, pathname, request, rawInput, reqTrace, t0, accumulator)).finally(() => {
352
+ if (usePool) ctxPool.release(ctx);
353
+ });
354
+ } catch (error) {
355
+ if (usePool) ctxPool.release(ctx);
356
+ return handleError(error, pathname, request, rawInput, reqTrace, t0, accumulator);
357
+ }
358
+ }
359
+ return handleAsync(request, url, pathname, qMark, match, route, accumulator);
360
+ }
361
+ async function handleAsync(request, url, pathname, qMark, match, route, accumulator) {
362
+ const ctx = ctxPool.borrow();
363
+ let reqTrace;
364
+ let rawInput;
365
+ let t0 = 0;
366
+ try {
367
+ if (!ctxFactoryIsEmpty) {
368
+ const baseCtxResult = contextFactory(request);
369
+ const baseCtx = baseCtxResult instanceof Promise ? await baseCtxResult : baseCtxResult;
370
+ const keys = Object.keys(baseCtx);
371
+ for (let i = 0; i < keys.length; i++) ctx[keys[i]] = baseCtx[keys[i]];
372
+ }
373
+ if (match.params) ctx.params = match.params;
374
+ if (collector) {
375
+ reqTrace = new RequestTrace();
376
+ ctx.__analyticsTrace = reqTrace;
377
+ ctx.trace = reqTrace.trace.bind(reqTrace);
378
+ }
379
+ if (route.passthrough) {} else if (request.method === "GET") {
380
+ if (qMark !== -1) {
381
+ const searchStr = url.slice(qMark + 1);
382
+ const dataIdx = searchStr.indexOf("data=");
383
+ if (dataIdx !== -1) {
384
+ const valueStart = dataIdx + 5;
385
+ const valueEnd = searchStr.indexOf("&", valueStart);
386
+ const encoded = valueEnd === -1 ? searchStr.slice(valueStart) : searchStr.slice(valueStart, valueEnd);
387
+ rawInput = JSON.parse(decodeURIComponent(encoded));
388
+ }
389
+ }
390
+ } else if (request.body) {
391
+ const ct = request.headers.get("content-type");
392
+ if (ct && ct.charCodeAt(12) !== 106) if (ct.includes("msgpack")) {
393
+ _msgpack ??= await import("../codec/msgpack.mjs");
394
+ const buf = new Uint8Array(await request.arrayBuffer());
395
+ rawInput = buf.length > 0 ? _msgpack.decode(buf) : void 0;
396
+ } else if (ct.includes("x-devalue")) {
397
+ _devalue ??= await import("../codec/devalue.mjs");
398
+ const text = await request.text();
399
+ rawInput = text ? _devalue.decode(text) : void 0;
400
+ } else if (isBun) rawInput = await request.json();
401
+ else {
402
+ const text = await request.text();
403
+ rawInput = text ? JSON.parse(text) : void 0;
404
+ }
405
+ else if (isBun) rawInput = await request.json();
406
+ else {
407
+ const text = await request.text();
408
+ rawInput = text ? JSON.parse(text) : void 0;
409
+ }
410
+ }
411
+ if (hasHooks) hooks.callHook("request", {
412
+ path: pathname,
413
+ input: rawInput
414
+ });
415
+ t0 = collector ? performance.now() : 0;
416
+ const pipelineResult = route.handler(ctx, rawInput, request.signal);
417
+ const output = pipelineResult instanceof Promise ? await pipelineResult : pipelineResult;
418
+ if (output instanceof Response) return output;
419
+ if (output instanceof ReadableStream) {
420
+ if (collector) {
421
+ const durationMs = round(performance.now() - t0);
422
+ collector.record(pathname, durationMs);
423
+ if (accumulator) accumulator.addProcedure({
424
+ procedure: pathname,
425
+ durationMs,
426
+ status: 200,
427
+ input: rawInput,
428
+ output: null,
429
+ spans: reqTrace?.spans ?? []
430
+ });
431
+ }
432
+ return new Response(output, { headers: { "content-type": "application/octet-stream" } });
433
+ }
434
+ if (output && typeof output === "object" && Symbol.asyncIterator in output) {
435
+ if (collector) {
436
+ const durationMs = round(performance.now() - t0);
437
+ collector.record(pathname, durationMs);
438
+ if (accumulator) accumulator.addProcedure({
439
+ procedure: pathname,
440
+ durationMs,
441
+ status: 200,
442
+ input: rawInput,
443
+ output: null,
444
+ spans: reqTrace?.spans ?? []
445
+ });
446
+ }
447
+ return new Response(iteratorToEventStream(output), { headers: sseHeaders });
448
+ }
449
+ const durationMs = collector ? round(performance.now() - t0) : 0;
450
+ if (hasHooks) hooks.callHook("response", {
451
+ path: pathname,
452
+ output,
453
+ durationMs
454
+ });
455
+ if (collector) {
456
+ collector.record(pathname, durationMs);
457
+ if (accumulator) accumulator.addProcedure({
458
+ procedure: pathname,
459
+ durationMs,
460
+ status: 200,
461
+ input: rawInput,
462
+ output,
463
+ spans: reqTrace?.spans ?? []
464
+ });
465
+ }
466
+ const accept = request.headers.get("accept");
467
+ if (accept && (accept.includes("msgpack") || accept.includes("x-devalue"))) {
468
+ const fmt = accept.includes("msgpack") ? "msgpack" : "devalue";
469
+ const cacheHeaders = route.cacheControl ? { "cache-control": route.cacheControl } : void 0;
470
+ return encodeResponse(output, 200, fmt, route.stringify, cacheHeaders);
471
+ }
472
+ const cacheHeaders = route.cacheControl ? { "cache-control": route.cacheControl } : void 0;
473
+ return new Response(route.stringify(output), { headers: cacheHeaders ? {
474
+ ...jsonHeaders,
475
+ ...cacheHeaders
476
+ } : jsonHeaders });
477
+ } catch (error) {
478
+ return handleError(error, pathname, request, rawInput, reqTrace, t0, accumulator);
479
+ } finally {
480
+ ctxPool.release(ctx);
481
+ }
482
+ }
483
+ function handleError(error, pathname, request, rawInput, reqTrace, t0, accumulator) {
484
+ if (hasHooks) hooks.callHook("error", {
485
+ path: pathname,
486
+ error
487
+ });
488
+ if (collector) {
489
+ const durationMs = t0 ? round(performance.now() - t0) : 0;
490
+ const errorMsg = error instanceof Error ? error.message : String(error);
491
+ const isValidation = error instanceof ValidationError;
492
+ const silgiErr = isValidation ? null : error instanceof SilgiError ? error : toSilgiError(error);
493
+ const errStatus = isValidation ? 400 : silgiErr?.status ?? 500;
494
+ collector.recordError(pathname, durationMs, errorMsg);
495
+ collector.recordDetailedError({
496
+ requestId: accumulator?.requestId ?? "",
497
+ timestamp: Date.now(),
498
+ procedure: pathname,
499
+ error: errorMsg,
500
+ code: isValidation ? "BAD_REQUEST" : silgiErr?.code ?? "INTERNAL_SERVER_ERROR",
501
+ status: errStatus,
502
+ stack: error instanceof Error ? error.stack ?? "" : "",
503
+ input: rawInput,
504
+ headers: Object.fromEntries(request.headers),
505
+ durationMs,
506
+ spans: reqTrace?.spans ?? []
507
+ });
508
+ if (accumulator) accumulator.addProcedure({
509
+ procedure: pathname,
510
+ durationMs,
511
+ status: errStatus,
512
+ input: rawInput,
513
+ output: null,
514
+ spans: reqTrace?.spans ?? [],
515
+ error: errorMsg
516
+ });
517
+ }
518
+ const accept = request.headers.get("accept");
519
+ const fmt = accept?.includes("msgpack") ? "msgpack" : accept?.includes("x-devalue") ? "devalue" : "json";
520
+ if (error instanceof ValidationError) return encodeResponse({
521
+ code: "BAD_REQUEST",
522
+ status: 400,
523
+ message: error.message,
524
+ data: { issues: error.issues }
525
+ }, 400, fmt);
526
+ const e = error instanceof SilgiError ? error : toSilgiError(error);
527
+ return encodeResponse(e.toJSON(), e.status, fmt);
528
+ }
529
+ if (!collector) return handleRequest;
530
+ return (request) => {
531
+ const acc = new RequestAccumulator(request, collector);
532
+ request.__acc = acc;
533
+ const result = handleRequest(request);
534
+ function injectHeaders(res) {
535
+ res.headers.set("x-request-id", acc.requestId);
536
+ const cookie = acc.getSessionCookie();
537
+ if (cookie) res.headers.append("set-cookie", cookie);
538
+ acc.flushWithResponse(res);
539
+ return res;
540
+ }
541
+ if (result instanceof Promise) return result.then(injectHeaders);
542
+ return injectHeaders(result);
543
+ };
544
+ }
545
+ //#endregion
546
+ export { createFetchHandler };
@@ -0,0 +1,17 @@
1
+ //#region src/core/iterator.d.ts
2
+ /**
3
+ * Async iterator utilities for streaming support.
4
+ */
5
+ type CleanupReason = 'return' | 'throw' | 'next' | 'dispose';
6
+ declare class AsyncIteratorClass<TYield, TReturn = void> implements AsyncGenerator<TYield, TReturn> {
7
+ #private;
8
+ constructor(nextFn: () => Promise<IteratorResult<TYield, TReturn>>, cleanup?: (reason: CleanupReason) => Promise<void>);
9
+ next(): Promise<IteratorResult<TYield, TReturn>>;
10
+ return(value?: TReturn | PromiseLike<TReturn>): Promise<IteratorResult<TYield, TReturn>>;
11
+ throw(error?: unknown): Promise<IteratorResult<TYield, TReturn>>;
12
+ [Symbol.asyncIterator](): this;
13
+ [Symbol.asyncDispose](): Promise<void>;
14
+ }
15
+ declare function mapAsyncIterator<TIn, TOut, TReturn = void>(source: AsyncIterableIterator<TIn>, transform: (value: TIn) => Promise<TOut> | TOut, transformError?: (error: unknown) => unknown): AsyncIteratorClass<TOut, TReturn>;
16
+ //#endregion
17
+ export { AsyncIteratorClass, mapAsyncIterator };
@@ -0,0 +1,79 @@
1
+ import { sequential } from "./utils.mjs";
2
+ //#region src/core/iterator.ts
3
+ /**
4
+ * Async iterator utilities for streaming support.
5
+ */
6
+ var AsyncIteratorClass = class {
7
+ #nextFn;
8
+ #cleanup;
9
+ #isDone = false;
10
+ #cleanupCalled = false;
11
+ constructor(nextFn, cleanup) {
12
+ this.#nextFn = sequential(nextFn);
13
+ this.#cleanup = cleanup;
14
+ }
15
+ async #doCleanup(reason) {
16
+ if (this.#cleanupCalled) return;
17
+ this.#cleanupCalled = true;
18
+ await this.#cleanup?.(reason);
19
+ }
20
+ async next() {
21
+ if (this.#isDone) return {
22
+ done: true,
23
+ value: void 0
24
+ };
25
+ try {
26
+ const result = await this.#nextFn();
27
+ if (result.done) {
28
+ this.#isDone = true;
29
+ await this.#doCleanup("next");
30
+ }
31
+ return result;
32
+ } catch (error) {
33
+ this.#isDone = true;
34
+ await this.#doCleanup("throw");
35
+ throw error;
36
+ }
37
+ }
38
+ async return(value) {
39
+ this.#isDone = true;
40
+ await this.#doCleanup("return");
41
+ return {
42
+ done: true,
43
+ value
44
+ };
45
+ }
46
+ async throw(error) {
47
+ this.#isDone = true;
48
+ await this.#doCleanup("throw");
49
+ throw error;
50
+ }
51
+ [Symbol.asyncIterator]() {
52
+ return this;
53
+ }
54
+ async [Symbol.asyncDispose]() {
55
+ this.#isDone = true;
56
+ await this.#doCleanup("dispose");
57
+ }
58
+ };
59
+ function mapAsyncIterator(source, transform, transformError) {
60
+ return new AsyncIteratorClass(async () => {
61
+ try {
62
+ const result = await source.next();
63
+ if (result.done) return {
64
+ done: true,
65
+ value: await transform(result.value)
66
+ };
67
+ return {
68
+ done: false,
69
+ value: await transform(result.value)
70
+ };
71
+ } catch (error) {
72
+ throw transformError ? transformError(error) : error;
73
+ }
74
+ }, async () => {
75
+ await source.return?.();
76
+ });
77
+ }
78
+ //#endregion
79
+ export { AsyncIteratorClass, mapAsyncIterator };
@@ -0,0 +1,16 @@
1
+ import "../compile.mjs";
2
+ //#region src/core/router-utils.ts
3
+ const routerCache = /* @__PURE__ */ new WeakMap();
4
+ function isProcedureDef(value) {
5
+ return typeof value === "object" && value !== null && "type" in value && "resolve" in value && typeof value.resolve === "function";
6
+ }
7
+ function assignPaths(def, prefix = []) {
8
+ for (const [key, value] of Object.entries(def)) {
9
+ const currentPath = [...prefix, key];
10
+ if (isProcedureDef(value)) {
11
+ if (!value.route) value.route = { path: "/" + currentPath.join("/") };
12
+ } else if (typeof value === "object" && value !== null) assignPaths(value, currentPath);
13
+ }
14
+ }
15
+ //#endregion
16
+ export { assignPaths, routerCache };
@@ -0,0 +1,19 @@
1
+ import { StandardSchemaV1 } from "@standard-schema/spec";
2
+
3
+ //#region src/core/schema.d.ts
4
+ type Schema<TInput = unknown, TOutput = unknown> = StandardSchemaV1<TInput, TOutput>;
5
+ type AnySchema = Schema<any, any>;
6
+ type InferSchemaInput<T extends AnySchema> = T extends Schema<infer I, unknown> ? I : never;
7
+ type InferSchemaOutput<T extends AnySchema> = T extends Schema<unknown, infer O> ? O : never;
8
+ type SchemaIssue = StandardSchemaV1.Issue;
9
+ declare class ValidationError extends Error {
10
+ readonly issues: readonly SchemaIssue[];
11
+ constructor(options: {
12
+ message?: string;
13
+ issues: readonly SchemaIssue[];
14
+ });
15
+ }
16
+ declare function validateSchema(schema: AnySchema, value: unknown): Promise<unknown>;
17
+ declare function type<TInput, TOutput = TInput>(...args: TInput extends TOutput ? TOutput extends TInput ? [map?: (input: TInput) => TOutput] : [map: (input: TInput) => TOutput] : [map: (input: TInput) => TOutput]): Schema<TInput, TOutput>;
18
+ //#endregion
19
+ export { AnySchema, InferSchemaInput, InferSchemaOutput, Schema, ValidationError, type, validateSchema };