mates-fullstack 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +311 -0
- package/dist/arctic-auth.d.ts +101 -0
- package/dist/arctic-auth.d.ts.map +1 -0
- package/dist/arctic-auth.js +538 -0
- package/dist/arctic-auth.js.map +1 -0
- package/dist/asset-manifest.d.ts +14 -0
- package/dist/asset-manifest.d.ts.map +1 -0
- package/dist/asset-manifest.js +102 -0
- package/dist/asset-manifest.js.map +1 -0
- package/dist/browser.d.ts +18 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +25 -0
- package/dist/browser.js.map +1 -0
- package/dist/build-esbuild.d.ts +29 -0
- package/dist/build-esbuild.d.ts.map +1 -0
- package/dist/build-esbuild.js +699 -0
- package/dist/build-esbuild.js.map +1 -0
- package/dist/build-prod.d.ts +126 -0
- package/dist/build-prod.d.ts.map +1 -0
- package/dist/build-prod.js +1014 -0
- package/dist/build-prod.js.map +1 -0
- package/dist/cli-new.d.ts +14 -0
- package/dist/cli-new.d.ts.map +1 -0
- package/dist/cli-new.js +637 -0
- package/dist/cli-new.js.map +1 -0
- package/dist/client.d.ts +43 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +130 -0
- package/dist/client.js.map +1 -0
- package/dist/cors.d.ts +16 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +60 -0
- package/dist/cors.js.map +1 -0
- package/dist/ctx.d.ts +78 -0
- package/dist/ctx.d.ts.map +1 -0
- package/dist/ctx.js +280 -0
- package/dist/ctx.js.map +1 -0
- package/dist/dev-watcher.d.ts +23 -0
- package/dist/dev-watcher.d.ts.map +1 -0
- package/dist/dev-watcher.js +136 -0
- package/dist/dev-watcher.js.map +1 -0
- package/dist/docs-generator.d.ts +69 -0
- package/dist/docs-generator.d.ts.map +1 -0
- package/dist/docs-generator.js +557 -0
- package/dist/docs-generator.js.map +1 -0
- package/dist/docs-page.d.ts +20 -0
- package/dist/docs-page.d.ts.map +1 -0
- package/dist/docs-page.js +1152 -0
- package/dist/docs-page.js.map +1 -0
- package/dist/download.d.ts +78 -0
- package/dist/download.d.ts.map +1 -0
- package/dist/download.js +202 -0
- package/dist/download.js.map +1 -0
- package/dist/env-loader.d.ts +76 -0
- package/dist/env-loader.d.ts.map +1 -0
- package/dist/env-loader.js +213 -0
- package/dist/env-loader.js.map +1 -0
- package/dist/errors.d.ts +146 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +386 -0
- package/dist/errors.js.map +1 -0
- package/dist/head.d.ts +31 -0
- package/dist/head.d.ts.map +1 -0
- package/dist/head.js +245 -0
- package/dist/head.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/internal-prefixes.d.ts +16 -0
- package/dist/internal-prefixes.d.ts.map +1 -0
- package/dist/internal-prefixes.js +16 -0
- package/dist/internal-prefixes.js.map +1 -0
- package/dist/internal.d.ts +25 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +25 -0
- package/dist/internal.js.map +1 -0
- package/dist/jwt.d.ts +166 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +261 -0
- package/dist/jwt.js.map +1 -0
- package/dist/log.d.ts +44 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +66 -0
- package/dist/log.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +138 -0
- package/dist/logger.js.map +1 -0
- package/dist/main-runner.d.ts +59 -0
- package/dist/main-runner.d.ts.map +1 -0
- package/dist/main-runner.js +157 -0
- package/dist/main-runner.js.map +1 -0
- package/dist/mates-auth.d.ts +82 -0
- package/dist/mates-auth.d.ts.map +1 -0
- package/dist/mates-auth.js +323 -0
- package/dist/mates-auth.js.map +1 -0
- package/dist/middleware.d.ts +30 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +67 -0
- package/dist/middleware.js.map +1 -0
- package/dist/project-resolver.d.ts +102 -0
- package/dist/project-resolver.d.ts.map +1 -0
- package/dist/project-resolver.js +271 -0
- package/dist/project-resolver.js.map +1 -0
- package/dist/rate-limit.d.ts +37 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +109 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/redirect.d.ts +84 -0
- package/dist/redirect.d.ts.map +1 -0
- package/dist/redirect.js +105 -0
- package/dist/redirect.js.map +1 -0
- package/dist/renderer.d.ts +91 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +630 -0
- package/dist/renderer.js.map +1 -0
- package/dist/request-logger.d.ts +12 -0
- package/dist/request-logger.d.ts.map +1 -0
- package/dist/request-logger.js +55 -0
- package/dist/request-logger.js.map +1 -0
- package/dist/rest.d.ts +25 -0
- package/dist/rest.d.ts.map +1 -0
- package/dist/rest.js +93 -0
- package/dist/rest.js.map +1 -0
- package/dist/router.d.ts +71 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +222 -0
- package/dist/router.js.map +1 -0
- package/dist/rpc-registry.d.ts +84 -0
- package/dist/rpc-registry.d.ts.map +1 -0
- package/dist/rpc-registry.js +271 -0
- package/dist/rpc-registry.js.map +1 -0
- package/dist/rpc-runner.d.ts +82 -0
- package/dist/rpc-runner.d.ts.map +1 -0
- package/dist/rpc-runner.js +564 -0
- package/dist/rpc-runner.js.map +1 -0
- package/dist/sanitize.d.ts +61 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +193 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/security-headers.d.ts +114 -0
- package/dist/security-headers.d.ts.map +1 -0
- package/dist/security-headers.js +121 -0
- package/dist/security-headers.js.map +1 -0
- package/dist/server-fn.d.ts +323 -0
- package/dist/server-fn.d.ts.map +1 -0
- package/dist/server-fn.js +373 -0
- package/dist/server-fn.js.map +1 -0
- package/dist/server-public.d.ts +13 -0
- package/dist/server-public.d.ts.map +1 -0
- package/dist/server-public.js +12 -0
- package/dist/server-public.js.map +1 -0
- package/dist/server-timeout.d.ts +38 -0
- package/dist/server-timeout.d.ts.map +1 -0
- package/dist/server-timeout.js +46 -0
- package/dist/server-timeout.js.map +1 -0
- package/dist/server.d.ts +100 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1218 -0
- package/dist/server.js.map +1 -0
- package/dist/socket-router.d.ts +153 -0
- package/dist/socket-router.d.ts.map +1 -0
- package/dist/socket-router.js +612 -0
- package/dist/socket-router.js.map +1 -0
- package/dist/sso.d.ts +90 -0
- package/dist/sso.d.ts.map +1 -0
- package/dist/sso.js +261 -0
- package/dist/sso.js.map +1 -0
- package/dist/ssr-context.d.ts +49 -0
- package/dist/ssr-context.d.ts.map +1 -0
- package/dist/ssr-context.js +85 -0
- package/dist/ssr-context.js.map +1 -0
- package/dist/ssr-globals.d.ts +32 -0
- package/dist/ssr-globals.d.ts.map +1 -0
- package/dist/ssr-globals.js +1010 -0
- package/dist/ssr-globals.js.map +1 -0
- package/dist/ssr-template.d.ts +73 -0
- package/dist/ssr-template.d.ts.map +1 -0
- package/dist/ssr-template.js +507 -0
- package/dist/ssr-template.js.map +1 -0
- package/dist/stack-mapper.d.ts +25 -0
- package/dist/stack-mapper.d.ts.map +1 -0
- package/dist/stack-mapper.js +139 -0
- package/dist/stack-mapper.js.map +1 -0
- package/dist/stream.d.ts +89 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +299 -0
- package/dist/stream.js.map +1 -0
- package/dist/upload.d.ts +69 -0
- package/dist/upload.d.ts.map +1 -0
- package/dist/upload.js +110 -0
- package/dist/upload.js.map +1 -0
- package/dist/validate.d.ts +58 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +89 -0
- package/dist/validate.js.map +1 -0
- package/dist/verify-package.d.ts +3 -0
- package/dist/verify-package.d.ts.map +1 -0
- package/dist/verify-package.js +128 -0
- package/dist/verify-package.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-ssr — server-fn.ts
|
|
3
|
+
*
|
|
4
|
+
* `serverFn` is the only API surface a developer touches to define a server
|
|
5
|
+
* function. It is a near-identity wrapper on the server and is NEVER executed
|
|
6
|
+
* in the browser — the Bun build plugin (`serverFnPlugin` in cli.ts) intercepts
|
|
7
|
+
* every import of a file inside `src/api/` during `Bun.build()` and replaces
|
|
8
|
+
* the entire module with lightweight RPC stubs before Bun ever tries to resolve
|
|
9
|
+
* the file's own imports (db, secrets, fs, etc.).
|
|
10
|
+
*
|
|
11
|
+
* ─── Server behaviour ────────────────────────────────────────────────────────
|
|
12
|
+
*
|
|
13
|
+
* import { serverFn } from "mates-ssr";
|
|
14
|
+
* export const getUsers = serverFn(async (filter?: string) => {
|
|
15
|
+
* return db.query("SELECT * FROM users WHERE name LIKE ?").all(filter);
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* On the server:
|
|
19
|
+
* - serverFn() is called once at module-load time.
|
|
20
|
+
* - It marks the function with metadata (__isMatesServerFn__, __fnName__)
|
|
21
|
+
* so the fn-registry can index it during startup scanning.
|
|
22
|
+
* - It returns the original async function unchanged.
|
|
23
|
+
* - When called during an SSR render pass (isSSR() === true) the function
|
|
24
|
+
* executes directly, in-process, with zero network overhead.
|
|
25
|
+
* - When called from a server-side API handler context the function also
|
|
26
|
+
* executes directly.
|
|
27
|
+
*
|
|
28
|
+
* ─── Client behaviour ────────────────────────────────────────────────────────
|
|
29
|
+
*
|
|
30
|
+
* The Bun plugin rewrites the entire src/api/*.ts module before bundling.
|
|
31
|
+
* What the browser receives is:
|
|
32
|
+
*
|
|
33
|
+
* import { __callServerFn } from "mates-ssr/client";
|
|
34
|
+
* export const getUsers = (...args) => __callServerFn("users", "getUsers", args);
|
|
35
|
+
* export const createUser = (...args) => __callServerFn("users", "createUser", args);
|
|
36
|
+
*
|
|
37
|
+
* `serverFn()` itself is never present in client.js.
|
|
38
|
+
* The original function body (db queries, secrets, file I/O) is never present
|
|
39
|
+
* in client.js.
|
|
40
|
+
* The imports of the api file (db, auth, etc.) are never resolved by Bun for
|
|
41
|
+
* the browser target — the plugin replaces the file before resolution.
|
|
42
|
+
*
|
|
43
|
+
* ─── Type safety ─────────────────────────────────────────────────────────────
|
|
44
|
+
*
|
|
45
|
+
* serverFn() is generic and preserves the full signature of the wrapped
|
|
46
|
+
* function:
|
|
47
|
+
*
|
|
48
|
+
* export const getUser = serverFn(async (id: number): Promise<User> => { … });
|
|
49
|
+
* // ^─────── type: (id: number) => Promise<User>
|
|
50
|
+
*
|
|
51
|
+
* The client stub generated by the plugin also accepts the same argument
|
|
52
|
+
* types because TypeScript resolves the import from the original .ts source
|
|
53
|
+
* file (which has the real types) — only the runtime implementation is
|
|
54
|
+
* replaced in the browser bundle. Types are never stripped by the plugin.
|
|
55
|
+
*
|
|
56
|
+
* ─── Error handling ──────────────────────────────────────────────────────────
|
|
57
|
+
*
|
|
58
|
+
* Errors thrown inside a serverFn are:
|
|
59
|
+
*
|
|
60
|
+
* On the server (direct call):
|
|
61
|
+
* - Propagated as normal JS exceptions.
|
|
62
|
+
* - The caller (asyncAction, onMount, etc.) handles them via try/catch
|
|
63
|
+
* or the error atom of asyncAction.
|
|
64
|
+
*
|
|
65
|
+
* On the client (RPC call via __callServerFn):
|
|
66
|
+
* - The RPC endpoint catches the error and returns:
|
|
67
|
+
* HTTP 500 { "error": "message", "code": "SERVER_FN_ERROR" }
|
|
68
|
+
* - __callServerFn re-throws as a plain Error with the server's message.
|
|
69
|
+
* - The caller handles it identically to a direct error.
|
|
70
|
+
*
|
|
71
|
+
* ─── Constraints ─────────────────────────────────────────────────────────────
|
|
72
|
+
*
|
|
73
|
+
* 1. serverFn MUST be used at the top level of a src/api/ file — not inside
|
|
74
|
+
* another function, class, or conditional. The plugin uses a static regex
|
|
75
|
+
* scan to extract export names; dynamic usage is not detected.
|
|
76
|
+
*
|
|
77
|
+
* 2. Arguments MUST be JSON-serialisable. The RPC layer uses JSON.stringify
|
|
78
|
+
* on the client and JSON.parse on the server. Dates, Sets, Maps, and class
|
|
79
|
+
* instances are not supported without a custom serialiser.
|
|
80
|
+
*
|
|
81
|
+
* 3. Return values MUST be JSON-serialisable for the same reason.
|
|
82
|
+
*
|
|
83
|
+
* 4. serverFn files must live under the configured apiDir (default: src/api/).
|
|
84
|
+
* Files outside that directory are not intercepted by the plugin and will
|
|
85
|
+
* not have their server-only imports stripped.
|
|
86
|
+
*
|
|
87
|
+
* 5. Do NOT import serverFn files from client-only code that is NOT also
|
|
88
|
+
* imported through a src/api/ path. If you import a serverFn file
|
|
89
|
+
* directly in src/client.ts (bypassing the api/ directory convention)
|
|
90
|
+
* the plugin will still intercept it by path, but this is a footgun —
|
|
91
|
+
* keep all server function definitions inside src/api/.
|
|
92
|
+
*/
|
|
93
|
+
// ─── Marker symbol ────────────────────────────────────────────────────────────
|
|
94
|
+
// Attached to every wrapped function so the fn-registry scanner can identify
|
|
95
|
+
// server functions at startup without re-parsing source files at runtime.
|
|
96
|
+
export const SERVER_FN_MARKER = Symbol("mates.serverFn");
|
|
97
|
+
// ─── Implicit server context ──────────────────────────────────────────────────
|
|
98
|
+
// Uses AsyncLocalStorage backed by a globalThis-shared instance (via
|
|
99
|
+
// Symbol.for) so that both the framework source and the node_modules copy
|
|
100
|
+
// share the same ALS — even though they are separate module evaluations.
|
|
101
|
+
// This is async-safe: concurrent requests each get their own ALS scope.
|
|
102
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
103
|
+
const _SERVER_CTX_KEY = Symbol.for("mates-ssr.serverCtxStorage");
|
|
104
|
+
function _getContextStorage() {
|
|
105
|
+
const g = globalThis;
|
|
106
|
+
if (!g[_SERVER_CTX_KEY]) {
|
|
107
|
+
g[_SERVER_CTX_KEY] = new AsyncLocalStorage();
|
|
108
|
+
}
|
|
109
|
+
return g[_SERVER_CTX_KEY];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Run a function with the given ServerContext available via getContext().
|
|
113
|
+
* Uses AsyncLocalStorage so concurrent requests are properly isolated.
|
|
114
|
+
* @internal — called by fn-registry's callServerFn
|
|
115
|
+
*/
|
|
116
|
+
export function runWithServerContext(ctx, fn) {
|
|
117
|
+
return _getContextStorage().run({ ctx }, fn);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Set the server context for the current function call.
|
|
121
|
+
* @internal — called by fn-registry's callServerFn
|
|
122
|
+
* @deprecated Use runWithServerContext() instead for async safety.
|
|
123
|
+
* Kept for backward compatibility.
|
|
124
|
+
*/
|
|
125
|
+
export function setCurrentServerContext(_ctx) {
|
|
126
|
+
// No-op — context is now managed via runWithServerContext + ALS.
|
|
127
|
+
// This function is retained so existing imports don't break.
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get the current server context.
|
|
131
|
+
* Used inside server functions to access auth, roles, and the raw request.
|
|
132
|
+
*
|
|
133
|
+
* The framework wraps each server function call in `runWithServerContext()`,
|
|
134
|
+
* which sets up an AsyncLocalStorage scope. `getContext()` reads from
|
|
135
|
+
* that scope — fully isolated per request even under high concurrency.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* export async function getUsers(filter: string) {
|
|
139
|
+
* const { auth } = getContext();
|
|
140
|
+
* checkAuth(auth);
|
|
141
|
+
* return UsersDAL.getAll(filter);
|
|
142
|
+
* }
|
|
143
|
+
*/
|
|
144
|
+
export function getContext() {
|
|
145
|
+
const store = _getContextStorage().getStore();
|
|
146
|
+
if (store)
|
|
147
|
+
return store.ctx;
|
|
148
|
+
// Fallback for when called outside a server context (e.g. in tests)
|
|
149
|
+
return {
|
|
150
|
+
auth: null,
|
|
151
|
+
roles: {
|
|
152
|
+
has: () => false,
|
|
153
|
+
hasAll: () => false,
|
|
154
|
+
list: () => [],
|
|
155
|
+
},
|
|
156
|
+
req: null,
|
|
157
|
+
custom: {},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// ─── ServerError ──────────────────────────────────────────────────────────────
|
|
161
|
+
/**
|
|
162
|
+
* Throw this from any server function to send a specific HTTP status,
|
|
163
|
+
* error message, and optional structured data to the client.
|
|
164
|
+
*
|
|
165
|
+
* The client receives an Error with .status, .code, and .data properties.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* // 404 — not found
|
|
169
|
+
* throw new ServerError(404, "Post not found");
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* // 403 — forbidden with extra context
|
|
173
|
+
* throw new ServerError(403, "Access denied", {
|
|
174
|
+
* code: "POST_PRIVATE",
|
|
175
|
+
* postId: id,
|
|
176
|
+
* });
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* // 400 — validation / business rule
|
|
180
|
+
* throw new ServerError(400, "Title too long", {
|
|
181
|
+
* code: "TITLE_TOO_LONG",
|
|
182
|
+
* max: 200,
|
|
183
|
+
* actual: body.title.length,
|
|
184
|
+
* });
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* // 409 — conflict
|
|
188
|
+
* throw new ServerError(409, "Email already registered", {
|
|
189
|
+
* code: "EMAIL_TAKEN",
|
|
190
|
+
* });
|
|
191
|
+
*/
|
|
192
|
+
export class ServerError extends Error {
|
|
193
|
+
/** HTTP status code sent to the client */
|
|
194
|
+
status;
|
|
195
|
+
/** Machine-readable error code. Defaults to HTTP status name if not provided. */
|
|
196
|
+
code;
|
|
197
|
+
/** Extra structured data sent alongside the error. Never throws — always JSON-serializable. */
|
|
198
|
+
data;
|
|
199
|
+
constructor(status, message, data) {
|
|
200
|
+
super(message);
|
|
201
|
+
this.name = "ServerError";
|
|
202
|
+
this.status = status;
|
|
203
|
+
this.data = data
|
|
204
|
+
? Object.fromEntries(Object.entries(data).filter(([k]) => k !== "code"))
|
|
205
|
+
: {};
|
|
206
|
+
this.code = data?.code ?? httpStatusCode(status);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Convert HTTP status number to a readable code string.
|
|
211
|
+
*/
|
|
212
|
+
function httpStatusCode(status) {
|
|
213
|
+
const codes = {
|
|
214
|
+
400: "BAD_REQUEST",
|
|
215
|
+
401: "UNAUTHORIZED",
|
|
216
|
+
403: "FORBIDDEN",
|
|
217
|
+
404: "NOT_FOUND",
|
|
218
|
+
405: "METHOD_NOT_ALLOWED",
|
|
219
|
+
408: "REQUEST_TIMEOUT",
|
|
220
|
+
409: "CONFLICT",
|
|
221
|
+
410: "GONE",
|
|
222
|
+
413: "PAYLOAD_TOO_LARGE",
|
|
223
|
+
422: "UNPROCESSABLE_ENTITY",
|
|
224
|
+
429: "TOO_MANY_REQUESTS",
|
|
225
|
+
500: "INTERNAL_SERVER_ERROR",
|
|
226
|
+
501: "NOT_IMPLEMENTED",
|
|
227
|
+
502: "BAD_GATEWAY",
|
|
228
|
+
503: "SERVICE_UNAVAILABLE",
|
|
229
|
+
504: "GATEWAY_TIMEOUT",
|
|
230
|
+
};
|
|
231
|
+
return codes[status] ?? "ERROR";
|
|
232
|
+
}
|
|
233
|
+
// ─── Core ─────────────────────────────────────────────────────────────────────
|
|
234
|
+
/**
|
|
235
|
+
* Wrap an async function as a server function.
|
|
236
|
+
*
|
|
237
|
+
* On the server the original function is returned as-is (with metadata).
|
|
238
|
+
* In the client bundle the entire module is replaced by the build plugin —
|
|
239
|
+
* this wrapper is never present in browser code.
|
|
240
|
+
*
|
|
241
|
+
* @param fn The async function to mark as server-only.
|
|
242
|
+
* @param name Optional explicit name. When omitted the function's `.name`
|
|
243
|
+
* property is used. Explicit names are useful for minified builds
|
|
244
|
+
* or when the inferred name would be ambiguous.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* export const getUsers = serverFn(async (filter?: string) => {
|
|
248
|
+
* return db.query("SELECT * FROM users WHERE name LIKE ?").all(filter);
|
|
249
|
+
* });
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* export const createUser = serverFn(
|
|
253
|
+
* async (data: { name: string; email: string }) => {
|
|
254
|
+
* if (!data.email) throw new Error("email is required");
|
|
255
|
+
* return db.query("INSERT INTO users (name,email) VALUES (?,?) RETURNING *")
|
|
256
|
+
* .get(data.name, data.email);
|
|
257
|
+
* }
|
|
258
|
+
* );
|
|
259
|
+
*/
|
|
260
|
+
export function serverFn(fn, name) {
|
|
261
|
+
// Resolve the name used for registry lookup and RPC routing.
|
|
262
|
+
// Priority: explicit name arg → fn.name → throw (name is required for routing).
|
|
263
|
+
const resolvedName = name ?? fn.name;
|
|
264
|
+
if (!resolvedName) {
|
|
265
|
+
throw new Error("[mates-ssr] serverFn(): could not determine function name.\n" +
|
|
266
|
+
"Pass an explicit name: serverFn(async () => { … }, 'myFnName')\n" +
|
|
267
|
+
"or use a named function expression: serverFn(async function myFn() { … })");
|
|
268
|
+
}
|
|
269
|
+
// Attach metadata as non-enumerable properties so they are invisible to
|
|
270
|
+
// spread operators, JSON.stringify, and iteration — but readable by the
|
|
271
|
+
// registry scanner and the RPC handler.
|
|
272
|
+
Object.defineProperties(fn, {
|
|
273
|
+
[SERVER_FN_MARKER]: {
|
|
274
|
+
value: true,
|
|
275
|
+
writable: false,
|
|
276
|
+
enumerable: false,
|
|
277
|
+
configurable: false,
|
|
278
|
+
},
|
|
279
|
+
__fnName__: {
|
|
280
|
+
value: resolvedName,
|
|
281
|
+
writable: false,
|
|
282
|
+
enumerable: false,
|
|
283
|
+
configurable: false,
|
|
284
|
+
},
|
|
285
|
+
__isMatesServerFn__: {
|
|
286
|
+
// String marker for fast duck-typing checks without importing the symbol
|
|
287
|
+
value: true,
|
|
288
|
+
writable: false,
|
|
289
|
+
enumerable: false,
|
|
290
|
+
configurable: false,
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
return fn;
|
|
294
|
+
}
|
|
295
|
+
// ─── Guard ────────────────────────────────────────────────────────────────────
|
|
296
|
+
/**
|
|
297
|
+
* Returns true when `value` is a function wrapped with serverFn().
|
|
298
|
+
*
|
|
299
|
+
* Useful for the fn-registry scanner and for defensive checks inside the
|
|
300
|
+
* RPC endpoint handler.
|
|
301
|
+
*/
|
|
302
|
+
export function isServerFn(value) {
|
|
303
|
+
return (typeof value === "function" && value.__isMatesServerFn__ === true);
|
|
304
|
+
}
|
|
305
|
+
// ─── Context helpers ──────────────────────────────────────────────────────────
|
|
306
|
+
//
|
|
307
|
+
// During a request (SSR render pass, API route, or serverFn RPC call) the
|
|
308
|
+
// original HTTP Request is stored in an AsyncLocalStorage context managed by
|
|
309
|
+
// ssr-context.ts. server.ts wraps every incoming fetch() in runWithContext()
|
|
310
|
+
// so the ALS slot is populated for the entire async call-chain — fully isolated
|
|
311
|
+
// per request even under high concurrency.
|
|
312
|
+
//
|
|
313
|
+
// serverFn implementations call getServerContext() to read cookies, auth
|
|
314
|
+
// headers, and other request-level data without needing the Request threaded
|
|
315
|
+
// explicitly through every call site.
|
|
316
|
+
import { getSSRRequest } from "./ssr-context.js";
|
|
317
|
+
/**
|
|
318
|
+
* Retrieve the original HTTP Request for the current request context.
|
|
319
|
+
*
|
|
320
|
+
* Returns null when called outside a request context (e.g. from a client-side
|
|
321
|
+
* asyncAction call via the RPC stub).
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* export const getProfile = serverFn(async () => {
|
|
325
|
+
* const req = getServerContext();
|
|
326
|
+
* const token = req?.headers.get("authorization");
|
|
327
|
+
* if (!token) throw new Error("Unauthorized");
|
|
328
|
+
* return verifyToken(token);
|
|
329
|
+
* });
|
|
330
|
+
*/
|
|
331
|
+
export function getServerContext() {
|
|
332
|
+
return getSSRRequest();
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Convenience helper — read a cookie from the current request context.
|
|
336
|
+
*
|
|
337
|
+
* Returns null when called on the client or when the cookie is absent.
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
* export const getSession = serverFn(async () => {
|
|
341
|
+
* const sessionId = getCookie("session_id");
|
|
342
|
+
* if (!sessionId) throw new Error("Not authenticated");
|
|
343
|
+
* return sessionStore.get(sessionId);
|
|
344
|
+
* });
|
|
345
|
+
*/
|
|
346
|
+
export function getCookie(name) {
|
|
347
|
+
const req = getSSRRequest();
|
|
348
|
+
if (!req)
|
|
349
|
+
return null;
|
|
350
|
+
const cookieHeader = req.headers.get("cookie");
|
|
351
|
+
if (!cookieHeader)
|
|
352
|
+
return null;
|
|
353
|
+
for (const part of cookieHeader.split(";")) {
|
|
354
|
+
const [key, ...rest] = part.trim().split("=");
|
|
355
|
+
if (key.trim() === name) {
|
|
356
|
+
return decodeURIComponent(rest.join("="));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Convenience helper — read a request header from the current request context.
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* export const getUser = serverFn(async () => {
|
|
366
|
+
* const auth = getHeader("authorization");
|
|
367
|
+
* return verifyJWT(auth);
|
|
368
|
+
* });
|
|
369
|
+
*/
|
|
370
|
+
export function getHeader(name) {
|
|
371
|
+
return getSSRRequest()?.headers.get(name) ?? null;
|
|
372
|
+
}
|
|
373
|
+
//# sourceMappingURL=server-fn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-fn.js","sourceRoot":"","sources":["../src/server-fn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack/server — server-safe public exports.
|
|
3
|
+
*
|
|
4
|
+
* This entry is intended for server/api, server/main, server/socket, and addons.
|
|
5
|
+
* Build/scanner/runtime internals are exported from mates-fullstack/internal.
|
|
6
|
+
*/
|
|
7
|
+
export * from "./index.js";
|
|
8
|
+
export { createContext, createContextFromHeaders, applyResHeaders, } from "./ctx.js";
|
|
9
|
+
export { writeStream } from "./stream.js";
|
|
10
|
+
export { writeDownload } from "./download.js";
|
|
11
|
+
export { runRequestHooks, runResponseHooks, clearMiddleware, middlewareStats, type RequestHookResult, } from "./middleware.js";
|
|
12
|
+
export { type SocketCtx, type SocketHandlers, type SocketLifecycleFn, type SocketRpcFn, } from "./socket-router.js";
|
|
13
|
+
//# sourceMappingURL=server-public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-public.d.ts","sourceRoot":"","sources":["../src/server-public.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,YAAY,CAAC;AAE3B,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,eAAe,GAChB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,WAAW,GACjB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack/server — server-safe public exports.
|
|
3
|
+
*
|
|
4
|
+
* This entry is intended for server/api, server/main, server/socket, and addons.
|
|
5
|
+
* Build/scanner/runtime internals are exported from mates-fullstack/internal.
|
|
6
|
+
*/
|
|
7
|
+
export * from "./index.js";
|
|
8
|
+
export { createContext, createContextFromHeaders, applyResHeaders, } from "./ctx.js";
|
|
9
|
+
export { writeStream } from "./stream.js";
|
|
10
|
+
export { writeDownload } from "./download.js";
|
|
11
|
+
export { runRequestHooks, runResponseHooks, clearMiddleware, middlewareStats, } from "./middleware.js";
|
|
12
|
+
//# sourceMappingURL=server-public.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-public.js","sourceRoot":"","sources":["../src/server-public.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,YAAY,CAAC;AAE3B,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,eAAe,GAChB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,eAAe,GAEhB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — server-timeout.ts
|
|
3
|
+
*
|
|
4
|
+
* Override the server-side request timeout.
|
|
5
|
+
* Must be called at module level in server/main.ts before the server starts.
|
|
6
|
+
*
|
|
7
|
+
* The timeout governs:
|
|
8
|
+
* - RPC calls (POST /api/**) — how long the function is allowed to run
|
|
9
|
+
* - SSR rendering — how long the renderer will wait
|
|
10
|
+
* - Graceful shutdown drain — 2× the request timeout
|
|
11
|
+
*
|
|
12
|
+
* @default 10 seconds
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Override the server request timeout.
|
|
16
|
+
*
|
|
17
|
+
* Call once at module level in server/main.ts.
|
|
18
|
+
* Must be called before the server starts.
|
|
19
|
+
*
|
|
20
|
+
* @param seconds Timeout in seconds. Must be >= 1.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // All requests get 30 seconds to complete
|
|
24
|
+
* setServerTimeout(30);
|
|
25
|
+
*
|
|
26
|
+
* // Real-time app — fail fast
|
|
27
|
+
* setServerTimeout(5);
|
|
28
|
+
*
|
|
29
|
+
* // Long-running exports
|
|
30
|
+
* setServerTimeout(60);
|
|
31
|
+
*/
|
|
32
|
+
export declare function setServerTimeout(seconds: number): void;
|
|
33
|
+
/**
|
|
34
|
+
* @internal — read by server.ts
|
|
35
|
+
* Returns the resolved timeout in milliseconds.
|
|
36
|
+
*/
|
|
37
|
+
export declare function _getServerTimeoutMs(): number;
|
|
38
|
+
//# sourceMappingURL=server-timeout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-timeout.d.ts","sourceRoot":"","sources":["../src/server-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAOtD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — server-timeout.ts
|
|
3
|
+
*
|
|
4
|
+
* Override the server-side request timeout.
|
|
5
|
+
* Must be called at module level in server/main.ts before the server starts.
|
|
6
|
+
*
|
|
7
|
+
* The timeout governs:
|
|
8
|
+
* - RPC calls (POST /api/**) — how long the function is allowed to run
|
|
9
|
+
* - SSR rendering — how long the renderer will wait
|
|
10
|
+
* - Graceful shutdown drain — 2× the request timeout
|
|
11
|
+
*
|
|
12
|
+
* @default 10 seconds
|
|
13
|
+
*/
|
|
14
|
+
let _timeoutMs = null;
|
|
15
|
+
/**
|
|
16
|
+
* Override the server request timeout.
|
|
17
|
+
*
|
|
18
|
+
* Call once at module level in server/main.ts.
|
|
19
|
+
* Must be called before the server starts.
|
|
20
|
+
*
|
|
21
|
+
* @param seconds Timeout in seconds. Must be >= 1.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // All requests get 30 seconds to complete
|
|
25
|
+
* setServerTimeout(30);
|
|
26
|
+
*
|
|
27
|
+
* // Real-time app — fail fast
|
|
28
|
+
* setServerTimeout(5);
|
|
29
|
+
*
|
|
30
|
+
* // Long-running exports
|
|
31
|
+
* setServerTimeout(60);
|
|
32
|
+
*/
|
|
33
|
+
export function setServerTimeout(seconds) {
|
|
34
|
+
if (!Number.isFinite(seconds) || seconds < 1) {
|
|
35
|
+
throw new Error(`[mates-fullstack] setServerTimeout: timeout must be >= 1 second, got ${seconds}.`);
|
|
36
|
+
}
|
|
37
|
+
_timeoutMs = Math.floor(seconds * 1000);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* @internal — read by server.ts
|
|
41
|
+
* Returns the resolved timeout in milliseconds.
|
|
42
|
+
*/
|
|
43
|
+
export function _getServerTimeoutMs() {
|
|
44
|
+
return _timeoutMs ?? 10000;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=server-timeout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-timeout.js","sourceRoot":"","sources":["../src/server-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,IAAI,UAAU,GAAkB,IAAI,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CACb,wEAAwE,OAAO,GAAG,CACnF,CAAC;IACJ,CAAC;IACD,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,UAAU,IAAI,KAAM,CAAC;AAC9B,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — server.ts
|
|
3
|
+
*
|
|
4
|
+
* Pure Node.js (node:http) HTTP server.
|
|
5
|
+
* No express, no hono, no fastify, no Bun APIs.
|
|
6
|
+
*
|
|
7
|
+
* Request routing order:
|
|
8
|
+
* 1. GET /health, /healthz → 200 JSON { status: "ok", timestamp }
|
|
9
|
+
* 2. GET /__mates_reload (dev only) → SSE live-reload stream
|
|
10
|
+
* 3. POST /__mates_log (dev only) → console.log browser messages
|
|
11
|
+
* 4. GET /_mates/* → virtual files (rpc-client.js, errors.js, etc.)
|
|
12
|
+
* 5. Upgrade: websocket → emit "upgrade" (caller handles WS)
|
|
13
|
+
* 6. onRequest hooks → raw HTTP escape hatch
|
|
14
|
+
* 7. GET /api/docs → docs page (dev or API_DOCS=true)
|
|
15
|
+
* 8. POST /api/** → RPC runner
|
|
16
|
+
* 9. /api/** (non-POST) → 405
|
|
17
|
+
* 10. Static assets: /assets/** or public/→ serveStatic()
|
|
18
|
+
* 11. GET /** → renderPage() (SSR)
|
|
19
|
+
* 12. (other methods) /** → 405
|
|
20
|
+
* 13. fallthrough → 404
|
|
21
|
+
*/
|
|
22
|
+
/// <reference types="node" />
|
|
23
|
+
import http from "node:http";
|
|
24
|
+
import type { ResolvedPaths } from "./project-resolver.js";
|
|
25
|
+
/** Module-level server configuration for limits that aren't per-request */
|
|
26
|
+
interface ServerConfig {
|
|
27
|
+
staticStreamTimeout: number;
|
|
28
|
+
maxSseClients: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Configure server-level limits. Call before startServer().
|
|
32
|
+
*/
|
|
33
|
+
export declare function configureServer(options: Partial<ServerConfig>): void;
|
|
34
|
+
export interface ServerOptions {
|
|
35
|
+
paths: ResolvedPaths;
|
|
36
|
+
dev: boolean;
|
|
37
|
+
/** Project root — used to locate client/index.html */
|
|
38
|
+
projectRoot: string;
|
|
39
|
+
/** Absolute path to built client JS file. Optional in dev no-bundle mode. */
|
|
40
|
+
clientBundlePath?: string | null;
|
|
41
|
+
/** Serve client modules directly from source in dev. */
|
|
42
|
+
noBundle?: boolean;
|
|
43
|
+
/** Root used by /_src and /_asset routes. Defaults to projectRoot. */
|
|
44
|
+
sourceRoot?: string;
|
|
45
|
+
/** Absolute browser entry source file for no-bundle dev. */
|
|
46
|
+
sourceClientEntry?: string | null;
|
|
47
|
+
/** Source server/api directory for no-bundle RPC stub generation. */
|
|
48
|
+
sourceApiDir?: string | null;
|
|
49
|
+
/** CSS bundle filename in dist/assets/ */
|
|
50
|
+
cssFilename?: string | null;
|
|
51
|
+
/** For SSR shortcut wiring */
|
|
52
|
+
matesPath: string;
|
|
53
|
+
/** Default 10_000 (10 seconds) */
|
|
54
|
+
timeoutMs?: number;
|
|
55
|
+
/** Default false */
|
|
56
|
+
trustProxy?: boolean;
|
|
57
|
+
/** Maximum concurrent connections. Default: 1000 */
|
|
58
|
+
maxConnections?: number;
|
|
59
|
+
/** Static file streaming timeout in ms. Default: 60000 */
|
|
60
|
+
staticStreamTimeout?: number;
|
|
61
|
+
/** Maximum SSE reload clients. Default: 500 */
|
|
62
|
+
maxSseClients?: number;
|
|
63
|
+
}
|
|
64
|
+
/** Shape of an HMR update broadcast over the SSE channel. */
|
|
65
|
+
export type HmrUpdate = {
|
|
66
|
+
kind: "reload";
|
|
67
|
+
} | {
|
|
68
|
+
kind: "css";
|
|
69
|
+
css?: string;
|
|
70
|
+
path?: string;
|
|
71
|
+
} | {
|
|
72
|
+
kind: "js";
|
|
73
|
+
path: string;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Trigger an HMR event for all connected dev clients.
|
|
77
|
+
* Called by the CLI (via the runtime-reload endpoint) when a file change
|
|
78
|
+
* triggers a rebuild.
|
|
79
|
+
*
|
|
80
|
+
* `update.kind === "css"` swaps the stylesheet in place (no page reload,
|
|
81
|
+
* preserving application state); anything else falls back to a full reload.
|
|
82
|
+
*/
|
|
83
|
+
export declare function notifyReload(generation: string, update?: HmrUpdate): void;
|
|
84
|
+
/**
|
|
85
|
+
* Returns the current number of in-flight requests.
|
|
86
|
+
*/
|
|
87
|
+
export declare function getActiveRequests(): number;
|
|
88
|
+
/**
|
|
89
|
+
* Returns the client IP address from the request.
|
|
90
|
+
* When trustProxy=true, reads X-Forwarded-For / X-Real-IP first.
|
|
91
|
+
*/
|
|
92
|
+
export declare function getClientIp(req: http.IncomingMessage, trustProxy: boolean): string;
|
|
93
|
+
export declare function buildDevImportMap(projectRoot: string): Record<string, string>;
|
|
94
|
+
/**
|
|
95
|
+
* Create and start the Node.js HTTP server.
|
|
96
|
+
* Returns a cleanup/shutdown function.
|
|
97
|
+
*/
|
|
98
|
+
export declare function startServer(options: ServerOptions): Promise<() => void>;
|
|
99
|
+
export {};
|
|
100
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAW7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAoB3D,2EAA2E;AAC3E,UAAU,YAAY;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB;AAOD;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAKpE;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,GAAG,EAAE,OAAO,CAAC;IACb,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAiFD,6DAA6D;AAC7D,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAajC;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,SAA8B,GACrC,IAAI,CAcN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,UAAU,EAAE,OAAO,GAClB,MAAM,CAeR;AA0WD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmC7E;AA2sBD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAmJ7E"}
|