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.
Files changed (202) hide show
  1. package/README.md +311 -0
  2. package/dist/arctic-auth.d.ts +101 -0
  3. package/dist/arctic-auth.d.ts.map +1 -0
  4. package/dist/arctic-auth.js +538 -0
  5. package/dist/arctic-auth.js.map +1 -0
  6. package/dist/asset-manifest.d.ts +14 -0
  7. package/dist/asset-manifest.d.ts.map +1 -0
  8. package/dist/asset-manifest.js +102 -0
  9. package/dist/asset-manifest.js.map +1 -0
  10. package/dist/browser.d.ts +18 -0
  11. package/dist/browser.d.ts.map +1 -0
  12. package/dist/browser.js +25 -0
  13. package/dist/browser.js.map +1 -0
  14. package/dist/build-esbuild.d.ts +29 -0
  15. package/dist/build-esbuild.d.ts.map +1 -0
  16. package/dist/build-esbuild.js +699 -0
  17. package/dist/build-esbuild.js.map +1 -0
  18. package/dist/build-prod.d.ts +126 -0
  19. package/dist/build-prod.d.ts.map +1 -0
  20. package/dist/build-prod.js +1014 -0
  21. package/dist/build-prod.js.map +1 -0
  22. package/dist/cli-new.d.ts +14 -0
  23. package/dist/cli-new.d.ts.map +1 -0
  24. package/dist/cli-new.js +637 -0
  25. package/dist/cli-new.js.map +1 -0
  26. package/dist/client.d.ts +43 -0
  27. package/dist/client.d.ts.map +1 -0
  28. package/dist/client.js +130 -0
  29. package/dist/client.js.map +1 -0
  30. package/dist/cors.d.ts +16 -0
  31. package/dist/cors.d.ts.map +1 -0
  32. package/dist/cors.js +60 -0
  33. package/dist/cors.js.map +1 -0
  34. package/dist/ctx.d.ts +78 -0
  35. package/dist/ctx.d.ts.map +1 -0
  36. package/dist/ctx.js +280 -0
  37. package/dist/ctx.js.map +1 -0
  38. package/dist/dev-watcher.d.ts +23 -0
  39. package/dist/dev-watcher.d.ts.map +1 -0
  40. package/dist/dev-watcher.js +136 -0
  41. package/dist/dev-watcher.js.map +1 -0
  42. package/dist/docs-generator.d.ts +69 -0
  43. package/dist/docs-generator.d.ts.map +1 -0
  44. package/dist/docs-generator.js +557 -0
  45. package/dist/docs-generator.js.map +1 -0
  46. package/dist/docs-page.d.ts +20 -0
  47. package/dist/docs-page.d.ts.map +1 -0
  48. package/dist/docs-page.js +1152 -0
  49. package/dist/docs-page.js.map +1 -0
  50. package/dist/download.d.ts +78 -0
  51. package/dist/download.d.ts.map +1 -0
  52. package/dist/download.js +202 -0
  53. package/dist/download.js.map +1 -0
  54. package/dist/env-loader.d.ts +76 -0
  55. package/dist/env-loader.d.ts.map +1 -0
  56. package/dist/env-loader.js +213 -0
  57. package/dist/env-loader.js.map +1 -0
  58. package/dist/errors.d.ts +146 -0
  59. package/dist/errors.d.ts.map +1 -0
  60. package/dist/errors.js +386 -0
  61. package/dist/errors.js.map +1 -0
  62. package/dist/head.d.ts +31 -0
  63. package/dist/head.d.ts.map +1 -0
  64. package/dist/head.js +245 -0
  65. package/dist/head.js.map +1 -0
  66. package/dist/index.d.ts +30 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +30 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/internal-prefixes.d.ts +16 -0
  71. package/dist/internal-prefixes.d.ts.map +1 -0
  72. package/dist/internal-prefixes.js +16 -0
  73. package/dist/internal-prefixes.js.map +1 -0
  74. package/dist/internal.d.ts +25 -0
  75. package/dist/internal.d.ts.map +1 -0
  76. package/dist/internal.js +25 -0
  77. package/dist/internal.js.map +1 -0
  78. package/dist/jwt.d.ts +166 -0
  79. package/dist/jwt.d.ts.map +1 -0
  80. package/dist/jwt.js +261 -0
  81. package/dist/jwt.js.map +1 -0
  82. package/dist/log.d.ts +44 -0
  83. package/dist/log.d.ts.map +1 -0
  84. package/dist/log.js +66 -0
  85. package/dist/log.js.map +1 -0
  86. package/dist/logger.d.ts +76 -0
  87. package/dist/logger.d.ts.map +1 -0
  88. package/dist/logger.js +138 -0
  89. package/dist/logger.js.map +1 -0
  90. package/dist/main-runner.d.ts +59 -0
  91. package/dist/main-runner.d.ts.map +1 -0
  92. package/dist/main-runner.js +157 -0
  93. package/dist/main-runner.js.map +1 -0
  94. package/dist/mates-auth.d.ts +82 -0
  95. package/dist/mates-auth.d.ts.map +1 -0
  96. package/dist/mates-auth.js +323 -0
  97. package/dist/mates-auth.js.map +1 -0
  98. package/dist/middleware.d.ts +30 -0
  99. package/dist/middleware.d.ts.map +1 -0
  100. package/dist/middleware.js +67 -0
  101. package/dist/middleware.js.map +1 -0
  102. package/dist/project-resolver.d.ts +102 -0
  103. package/dist/project-resolver.d.ts.map +1 -0
  104. package/dist/project-resolver.js +271 -0
  105. package/dist/project-resolver.js.map +1 -0
  106. package/dist/rate-limit.d.ts +37 -0
  107. package/dist/rate-limit.d.ts.map +1 -0
  108. package/dist/rate-limit.js +109 -0
  109. package/dist/rate-limit.js.map +1 -0
  110. package/dist/redirect.d.ts +84 -0
  111. package/dist/redirect.d.ts.map +1 -0
  112. package/dist/redirect.js +105 -0
  113. package/dist/redirect.js.map +1 -0
  114. package/dist/renderer.d.ts +91 -0
  115. package/dist/renderer.d.ts.map +1 -0
  116. package/dist/renderer.js +630 -0
  117. package/dist/renderer.js.map +1 -0
  118. package/dist/request-logger.d.ts +12 -0
  119. package/dist/request-logger.d.ts.map +1 -0
  120. package/dist/request-logger.js +55 -0
  121. package/dist/request-logger.js.map +1 -0
  122. package/dist/rest.d.ts +25 -0
  123. package/dist/rest.d.ts.map +1 -0
  124. package/dist/rest.js +93 -0
  125. package/dist/rest.js.map +1 -0
  126. package/dist/router.d.ts +71 -0
  127. package/dist/router.d.ts.map +1 -0
  128. package/dist/router.js +222 -0
  129. package/dist/router.js.map +1 -0
  130. package/dist/rpc-registry.d.ts +84 -0
  131. package/dist/rpc-registry.d.ts.map +1 -0
  132. package/dist/rpc-registry.js +271 -0
  133. package/dist/rpc-registry.js.map +1 -0
  134. package/dist/rpc-runner.d.ts +82 -0
  135. package/dist/rpc-runner.d.ts.map +1 -0
  136. package/dist/rpc-runner.js +564 -0
  137. package/dist/rpc-runner.js.map +1 -0
  138. package/dist/sanitize.d.ts +61 -0
  139. package/dist/sanitize.d.ts.map +1 -0
  140. package/dist/sanitize.js +193 -0
  141. package/dist/sanitize.js.map +1 -0
  142. package/dist/security-headers.d.ts +114 -0
  143. package/dist/security-headers.d.ts.map +1 -0
  144. package/dist/security-headers.js +121 -0
  145. package/dist/security-headers.js.map +1 -0
  146. package/dist/server-fn.d.ts +323 -0
  147. package/dist/server-fn.d.ts.map +1 -0
  148. package/dist/server-fn.js +373 -0
  149. package/dist/server-fn.js.map +1 -0
  150. package/dist/server-public.d.ts +13 -0
  151. package/dist/server-public.d.ts.map +1 -0
  152. package/dist/server-public.js +12 -0
  153. package/dist/server-public.js.map +1 -0
  154. package/dist/server-timeout.d.ts +38 -0
  155. package/dist/server-timeout.d.ts.map +1 -0
  156. package/dist/server-timeout.js +46 -0
  157. package/dist/server-timeout.js.map +1 -0
  158. package/dist/server.d.ts +100 -0
  159. package/dist/server.d.ts.map +1 -0
  160. package/dist/server.js +1218 -0
  161. package/dist/server.js.map +1 -0
  162. package/dist/socket-router.d.ts +153 -0
  163. package/dist/socket-router.d.ts.map +1 -0
  164. package/dist/socket-router.js +612 -0
  165. package/dist/socket-router.js.map +1 -0
  166. package/dist/sso.d.ts +90 -0
  167. package/dist/sso.d.ts.map +1 -0
  168. package/dist/sso.js +261 -0
  169. package/dist/sso.js.map +1 -0
  170. package/dist/ssr-context.d.ts +49 -0
  171. package/dist/ssr-context.d.ts.map +1 -0
  172. package/dist/ssr-context.js +85 -0
  173. package/dist/ssr-context.js.map +1 -0
  174. package/dist/ssr-globals.d.ts +32 -0
  175. package/dist/ssr-globals.d.ts.map +1 -0
  176. package/dist/ssr-globals.js +1010 -0
  177. package/dist/ssr-globals.js.map +1 -0
  178. package/dist/ssr-template.d.ts +73 -0
  179. package/dist/ssr-template.d.ts.map +1 -0
  180. package/dist/ssr-template.js +507 -0
  181. package/dist/ssr-template.js.map +1 -0
  182. package/dist/stack-mapper.d.ts +25 -0
  183. package/dist/stack-mapper.d.ts.map +1 -0
  184. package/dist/stack-mapper.js +139 -0
  185. package/dist/stack-mapper.js.map +1 -0
  186. package/dist/stream.d.ts +89 -0
  187. package/dist/stream.d.ts.map +1 -0
  188. package/dist/stream.js +299 -0
  189. package/dist/stream.js.map +1 -0
  190. package/dist/upload.d.ts +69 -0
  191. package/dist/upload.d.ts.map +1 -0
  192. package/dist/upload.js +110 -0
  193. package/dist/upload.js.map +1 -0
  194. package/dist/validate.d.ts +58 -0
  195. package/dist/validate.d.ts.map +1 -0
  196. package/dist/validate.js +89 -0
  197. package/dist/validate.js.map +1 -0
  198. package/dist/verify-package.d.ts +3 -0
  199. package/dist/verify-package.d.ts.map +1 -0
  200. package/dist/verify-package.js +128 -0
  201. package/dist/verify-package.js.map +1 -0
  202. package/package.json +79 -0
@@ -0,0 +1,1152 @@
1
+ /**
2
+ * mates-fullstack — docs-page.ts
3
+ *
4
+ * Builds and serves a self-contained HTML API documentation page at /api/docs.
5
+ * Takes RouteDoc objects from docs-generator.ts and renders a dark-themed,
6
+ * developer-focused interactive docs UI with a Try-it panel.
7
+ */
8
+ import { ERRORS_MODULE } from "./internal-prefixes.js";
9
+ // ─── Public API ───────────────────────────────────────────────────────────────
10
+ /**
11
+ * Build a complete self-contained HTML string for the /api/docs page.
12
+ * No external dependencies — all CSS and JS are inlined.
13
+ */
14
+ export function buildDocsHtml(docs, dev) {
15
+ const endpointCount = docs.length;
16
+ const sidebarHtml = buildSidebar(docs);
17
+ const contentHtml = buildContent(docs);
18
+ const emptyNotice = docs.length === 0
19
+ ? `<div class="empty-notice">
20
+ <p>No RPC functions found. Make sure <code>server/api/</code> exists and ts-morph is installed.</p>
21
+ <pre>npm install -D ts-morph</pre>
22
+ </div>`
23
+ : "";
24
+ return `<!DOCTYPE html>
25
+ <html lang="en">
26
+ <head>
27
+ <meta charset="UTF-8">
28
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
29
+ <title>RPC Docs — mates-fullstack</title>
30
+ <style>${CSS}</style>
31
+ </head>
32
+ <body>
33
+ <header class="header">
34
+ <div class="header-left">
35
+ <span class="header-logo">mates-fullstack RPC</span>
36
+ <span class="header-path">/api/docs</span>
37
+ </div>
38
+ <div class="header-right">
39
+ <span class="badge badge-dev">${dev ? "DEV" : "PROD"}</span>
40
+ </div>
41
+ </header>
42
+
43
+ <div class="meta-bar">
44
+ <span>${endpointCount} RPC function${endpointCount !== 1 ? "s" : ""}</span>
45
+ <span class="dot">·</span>
46
+ <span>POST transport</span>
47
+ <span class="dot">·</span>
48
+ <span>first argument + return type</span>
49
+ </div>
50
+
51
+ ${emptyNotice}
52
+
53
+ ${docs.length > 0
54
+ ? `<div class="layout">
55
+ <nav class="sidebar" id="sidebar">
56
+ ${sidebarHtml}
57
+ </nav>
58
+ <main class="content" id="content">
59
+ ${contentHtml}
60
+ </main>
61
+ </div>`
62
+ : ""}
63
+
64
+ <script>${JS}</script>
65
+ </body>
66
+ </html>`;
67
+ }
68
+ /**
69
+ * Write the docs HTML page to an HTTP ServerResponse.
70
+ */
71
+ export function serveDocsPage(res, docs, dev) {
72
+ const html = buildDocsHtml(docs, dev);
73
+ res.writeHead(200, {
74
+ "Content-Type": "text/html; charset=utf-8",
75
+ "Cache-Control": "no-store",
76
+ });
77
+ res.end(html);
78
+ }
79
+ // ─── Sidebar ──────────────────────────────────────────────────────────────────
80
+ function buildSidebar(docs) {
81
+ // Group by file
82
+ const groups = new Map();
83
+ for (const doc of docs) {
84
+ const file = doc.fileRelPath ?? "unknown";
85
+ if (!groups.has(file))
86
+ groups.set(file, []);
87
+ groups.get(file).push(doc);
88
+ }
89
+ let html = "";
90
+ for (const [file, routes] of groups) {
91
+ const sectionId = fileToId(file);
92
+ html += `<div class="sidebar-group">
93
+ <div class="sidebar-file">${escHtml(file)}</div>
94
+ ${routes
95
+ .map((r) => {
96
+ const id = routeToId(r);
97
+ return `<a class="sidebar-link" href="#${id}" data-target="${id}">${escHtml(r.fnName)}</a>`;
98
+ })
99
+ .join("\n ")}
100
+ </div>`;
101
+ }
102
+ return html;
103
+ }
104
+ // ─── Content ──────────────────────────────────────────────────────────────────
105
+ function buildContent(docs) {
106
+ return docs
107
+ .map((doc) => {
108
+ const id = routeToId(doc);
109
+ const examplePayload = generateExamplePayload(doc.payload);
110
+ const exampleJson = JSON.stringify(examplePayload, null, 2);
111
+ return `<section class="route-section" id="${id}">
112
+ <div class="route-header">
113
+ <span class="method-badge">POST</span>
114
+ <span class="route-url">${escHtml(doc.url)}</span>
115
+ </div>
116
+
117
+ <div class="rpc-title">
118
+ <span class="rpc-file">${escHtml(doc.fileRelPath ?? "")}</span>
119
+ <span class="rpc-separator">:</span>
120
+ <span class="rpc-function">${escHtml(doc.fnName)}</span>
121
+ </div>
122
+
123
+ ${doc.description ? `<p class="route-desc">${escHtml(doc.description)}</p>` : ""}
124
+
125
+ ${doc.typed ? buildPayloadDocs(doc) : buildUntypedDocs()}
126
+
127
+ ${doc.typed ? buildResponseDocs(doc.response) : ""}
128
+
129
+ <div class="try-it-container">
130
+ <button class="try-it-toggle" data-id="${id}" aria-expanded="false">
131
+ ▶ Try it
132
+ </button>
133
+ <div class="try-it-panel" id="try-${id}" hidden>
134
+ <div class="try-it-body">
135
+ <label class="try-label">Payload</label>
136
+ <textarea class="try-textarea" id="payload-${id}" spellcheck="false">${escHtml(exampleJson)}</textarea>
137
+
138
+ <button class="try-send-btn" data-id="${id}" data-url="${escHtml(doc.url)}">Send</button>
139
+
140
+ <div class="try-response" id="resp-${id}" hidden>
141
+ <div class="try-response-meta" id="resp-meta-${id}"></div>
142
+ <pre class="try-response-body" id="resp-body-${id}"></pre>
143
+ </div>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </section>`;
148
+ })
149
+ .join("\n");
150
+ }
151
+ // ─── Type rendering ───────────────────────────────────────────────────────────
152
+ function buildUntypedDocs() {
153
+ return `<div class="type-section">
154
+ <div class="type-section-title">Payload</div>
155
+ <div class="type-note">Type extraction is only available for TypeScript RPC files.</div>
156
+ </div>`;
157
+ }
158
+ function buildPayloadDocs(doc) {
159
+ const shape = doc.payload;
160
+ const argName = doc.firstArgName ?? "payload";
161
+ if (!shape) {
162
+ return `<div class="type-section">
163
+ <div class="type-section-title">First argument</div>
164
+ <span class="type-muted">(none)</span>
165
+ </div>`;
166
+ }
167
+ const header = `<div class="type-section-title">Payload ${confidenceBadge(shape.confidence)}</div>`;
168
+ return `<div class="type-section">
169
+ ${header}
170
+ ${renderTypeTree(shape, argName)}
171
+ </div>`;
172
+ }
173
+ function buildResponseDocs(shape) {
174
+ if (!shape) {
175
+ return `<div class="type-section">
176
+ <div class="type-section-title">Returns</div>
177
+ <span class="type-muted">void</span>
178
+ </div>`;
179
+ }
180
+ const header = `<div class="type-section-title">Response ${confidenceBadge(shape.confidence)}</div>`;
181
+ return `<div class="type-section">
182
+ ${header}
183
+ ${renderTypeTree(shape, "response")}
184
+ </div>`;
185
+ }
186
+ function renderTypeTree(shape, label) {
187
+ if (shape.kind === "array") {
188
+ const itemType = cleanTypeName(shape.itemType ?? shape.typeName);
189
+ if (shape.fields && shape.fields.length > 0) {
190
+ return `<details class="type-tree" open>
191
+ <summary><span class="tree-label">${escHtml(label)}</span><span class="tree-type">Array</span></summary>
192
+ <div class="tree-children">
193
+ <details class="type-tree type-tree-nested" open>
194
+ <summary><span class="tree-label">item</span><span class="tree-type">object</span></summary>
195
+ <ul class="tree-list">
196
+ ${shape.fields.map(renderTreeField).join("\n ")}
197
+ </ul>
198
+ </details>
199
+ </div>
200
+ </details>`;
201
+ }
202
+ return `<details class="type-tree" open>
203
+ <summary><span class="tree-label">${escHtml(label)}</span><span class="tree-type">Array&lt;${escHtml(itemType)}&gt;</span></summary>
204
+ </details>`;
205
+ }
206
+ if (shape.kind === "object") {
207
+ const fields = shape.fields ?? [];
208
+ return `<details class="type-tree" open>
209
+ <summary><span class="tree-label">${escHtml(label)}</span><span class="tree-type">object</span></summary>
210
+ ${fields.length > 0
211
+ ? `<ul class="tree-list">
212
+ ${fields.map(renderTreeField).join("\n ")}
213
+ </ul>`
214
+ : `<div class="tree-empty">no fields</div>`}
215
+ </details>`;
216
+ }
217
+ return `<div class="type-leaf">
218
+ <span class="tree-label">${escHtml(label)}</span>
219
+ <span class="tree-type">${escHtml(shapeLabel(shape))}</span>
220
+ </div>`;
221
+ }
222
+ function renderTreeField(field) {
223
+ const requiredBadge = field.required
224
+ ? `<span class="badge badge-required">required</span>`
225
+ : `<span class="badge badge-optional">optional</span>`;
226
+ const description = field.description
227
+ ? `<div class="tree-desc">${escHtml(field.description)}</div>`
228
+ : "";
229
+ return `<li class="tree-field">
230
+ <div class="tree-field-line">
231
+ <span class="tree-field-name">${escHtml(field.name)}</span><span class="tree-punct">:</span>
232
+ <code class="tree-field-type">${escHtml(cleanTypeName(field.type))}</code>
233
+ ${requiredBadge}
234
+ </div>
235
+ ${description}
236
+ </li>`;
237
+ }
238
+ function shapeLabel(shape) {
239
+ if (!shape || !shape.kind)
240
+ return "unknown";
241
+ if (shape.kind === "array" && shape.fields && shape.fields.length > 0) {
242
+ return `${fieldsToInlineType(shape.fields)}[]`;
243
+ }
244
+ if (shape.kind === "object" && shape.fields && shape.fields.length > 0) {
245
+ return fieldsToInlineType(shape.fields);
246
+ }
247
+ return cleanTypeName(shape.typeName || shape.kind);
248
+ }
249
+ function fieldsToInlineType(fields) {
250
+ return `{ ${fields
251
+ .map((field) => {
252
+ const name = field.required ? field.name : `${field.name}?`;
253
+ return `${name}: ${cleanTypeName(field.type)}`;
254
+ })
255
+ .join("; ")} }`;
256
+ }
257
+ function cleanTypeName(typeName) {
258
+ return typeName
259
+ .replace(/import\(["'][^)]+["']\)\./g, "")
260
+ .replace(/import\(["'][^)]+["']\)/g, "");
261
+ }
262
+ function confidenceBadge(confidence) {
263
+ const label = confidence === "explicit"
264
+ ? "explicit"
265
+ : confidence === "inferred"
266
+ ? "inferred"
267
+ : "unknown";
268
+ return `<span class="confidence-badge confidence-${label}">${label}</span>`;
269
+ }
270
+ // ─── Example payload generation ───────────────────────────────────────────────
271
+ function generateExamplePayload(shape) {
272
+ if (!shape)
273
+ return {};
274
+ switch (shape.kind) {
275
+ case "primitive": {
276
+ const t = shape.typeName;
277
+ if (t === "string")
278
+ return "";
279
+ if (t === "number")
280
+ return 0;
281
+ if (t === "boolean")
282
+ return false;
283
+ return null;
284
+ }
285
+ case "array":
286
+ return [];
287
+ case "object": {
288
+ if (!shape.fields || shape.fields.length === 0)
289
+ return {};
290
+ const obj = {};
291
+ for (const field of shape.fields) {
292
+ // FieldDoc.type is a string — produce a simple example based on the type string
293
+ obj[field.name] = exampleFromTypeString(field.type);
294
+ }
295
+ return obj;
296
+ }
297
+ case "union":
298
+ case "unknown":
299
+ default:
300
+ return {};
301
+ }
302
+ }
303
+ function exampleFromTypeString(typeName) {
304
+ switch (typeName) {
305
+ case "string":
306
+ return "";
307
+ case "number":
308
+ return 0;
309
+ case "boolean":
310
+ return false;
311
+ default:
312
+ if (typeName.endsWith("[]"))
313
+ return [];
314
+ return null;
315
+ }
316
+ }
317
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
318
+ function escHtml(str) {
319
+ return str
320
+ .replace(/&/g, "&amp;")
321
+ .replace(/</g, "&lt;")
322
+ .replace(/>/g, "&gt;")
323
+ .replace(/"/g, "&quot;")
324
+ .replace(/'/g, "&#39;");
325
+ }
326
+ function fileToId(file) {
327
+ return "file-" + file.replace(/[^a-zA-Z0-9]/g, "-");
328
+ }
329
+ function routeToId(doc) {
330
+ return doc.url.replace(/\//g, "-").replace(/^-/, "");
331
+ }
332
+ // ─── Inline CSS ───────────────────────────────────────────────────────────────
333
+ const CSS = `
334
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
335
+
336
+ :root {
337
+ --bg: #0f1117;
338
+ --surface: #1a1d27;
339
+ --surface-2: #1e2130;
340
+ --border: #2a2d3a;
341
+ --text: #e2e8f0;
342
+ --muted: #718096;
343
+ --accent: #4ade80;
344
+ --accent-bg: #14532d;
345
+ --required: #fbbf24;
346
+ --optional: #718096;
347
+ --code-bg: #111827;
348
+ --error: #f87171;
349
+ --link: #60a5fa;
350
+ --radius: 6px;
351
+ --font-mono: "Cascadia Code", "Fira Code", "Consolas", monospace;
352
+ --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
353
+ }
354
+
355
+ html, body {
356
+ height: 100%;
357
+ background: var(--bg);
358
+ color: var(--text);
359
+ font-family: var(--font-sans);
360
+ font-size: 14px;
361
+ line-height: 1.6;
362
+ }
363
+
364
+ /* Header */
365
+ .header {
366
+ display: flex;
367
+ align-items: center;
368
+ justify-content: space-between;
369
+ padding: 0 24px;
370
+ height: 52px;
371
+ background: var(--surface);
372
+ border-bottom: 1px solid var(--border);
373
+ position: sticky;
374
+ top: 0;
375
+ z-index: 100;
376
+ }
377
+
378
+ .header-left {
379
+ display: flex;
380
+ align-items: center;
381
+ gap: 12px;
382
+ }
383
+
384
+ .header-logo {
385
+ font-weight: 700;
386
+ font-size: 15px;
387
+ color: var(--text);
388
+ letter-spacing: -0.3px;
389
+ }
390
+
391
+ .header-path {
392
+ color: var(--muted);
393
+ font-family: var(--font-mono);
394
+ font-size: 12px;
395
+ }
396
+
397
+ .header-right {
398
+ display: flex;
399
+ align-items: center;
400
+ gap: 8px;
401
+ }
402
+
403
+ /* Meta bar */
404
+ .meta-bar {
405
+ display: flex;
406
+ align-items: center;
407
+ gap: 8px;
408
+ padding: 8px 24px;
409
+ font-size: 12px;
410
+ color: var(--muted);
411
+ background: var(--surface);
412
+ border-bottom: 1px solid var(--border);
413
+ }
414
+
415
+ .dot { color: var(--border); }
416
+
417
+ /* Badges */
418
+ .badge {
419
+ display: inline-block;
420
+ padding: 2px 7px;
421
+ border-radius: 4px;
422
+ font-size: 11px;
423
+ font-weight: 600;
424
+ letter-spacing: 0.4px;
425
+ text-transform: uppercase;
426
+ }
427
+
428
+ .badge-dev { background: #1e3a5f; color: #60a5fa; }
429
+ .badge-prod { background: #1a2e1a; color: var(--accent); }
430
+ .badge-post { background: var(--accent-bg); color: var(--accent); }
431
+ .badge-required { color: var(--required); background: transparent; padding: 0; font-size: 11px; font-weight: 500; text-transform: none; letter-spacing: 0; }
432
+ .badge-optional { color: var(--optional); background: transparent; padding: 0; font-size: 11px; font-weight: 400; text-transform: none; letter-spacing: 0; }
433
+
434
+ /* Layout */
435
+ .layout {
436
+ display: flex;
437
+ height: calc(100vh - 88px);
438
+ }
439
+
440
+ /* Sidebar */
441
+ .sidebar {
442
+ width: 220px;
443
+ min-width: 180px;
444
+ background: var(--surface);
445
+ border-right: 1px solid var(--border);
446
+ overflow-y: auto;
447
+ flex-shrink: 0;
448
+ padding: 16px 0;
449
+ }
450
+
451
+ .sidebar-group {
452
+ margin-bottom: 20px;
453
+ }
454
+
455
+ .sidebar-file {
456
+ padding: 4px 16px;
457
+ font-size: 11px;
458
+ font-weight: 600;
459
+ color: var(--muted);
460
+ text-transform: uppercase;
461
+ letter-spacing: 0.6px;
462
+ font-family: var(--font-mono);
463
+ white-space: nowrap;
464
+ overflow: hidden;
465
+ text-overflow: ellipsis;
466
+ }
467
+
468
+ .sidebar-link {
469
+ display: block;
470
+ padding: 5px 16px 5px 24px;
471
+ font-size: 13px;
472
+ color: var(--muted);
473
+ text-decoration: none;
474
+ border-left: 2px solid transparent;
475
+ transition: color 0.12s, border-color 0.12s, background 0.12s;
476
+ white-space: nowrap;
477
+ overflow: hidden;
478
+ text-overflow: ellipsis;
479
+ font-family: var(--font-mono);
480
+ }
481
+
482
+ .sidebar-link:hover {
483
+ color: var(--text);
484
+ background: var(--surface-2);
485
+ }
486
+
487
+ .sidebar-link.active {
488
+ color: var(--accent);
489
+ border-left-color: var(--accent);
490
+ background: rgba(74, 222, 128, 0.06);
491
+ }
492
+
493
+ /* Content */
494
+ .content {
495
+ flex: 1;
496
+ overflow-y: auto;
497
+ padding: 0;
498
+ }
499
+
500
+ /* Route section */
501
+ .route-section {
502
+ padding: 28px 32px 28px 32px;
503
+ border-bottom: 1px solid var(--border);
504
+ }
505
+
506
+ .route-section:last-child {
507
+ border-bottom: none;
508
+ }
509
+
510
+ .route-header {
511
+ display: flex;
512
+ align-items: center;
513
+ gap: 10px;
514
+ margin-bottom: 10px;
515
+ flex-wrap: wrap;
516
+ }
517
+
518
+ .method-badge {
519
+ display: inline-block;
520
+ background: var(--accent-bg);
521
+ color: var(--accent);
522
+ font-size: 11px;
523
+ font-weight: 700;
524
+ padding: 3px 8px;
525
+ border-radius: 4px;
526
+ letter-spacing: 0.5px;
527
+ font-family: var(--font-mono);
528
+ flex-shrink: 0;
529
+ }
530
+
531
+ .route-url {
532
+ font-family: var(--font-mono);
533
+ font-size: 15px;
534
+ font-weight: 600;
535
+ color: var(--text);
536
+ word-break: break-all;
537
+ }
538
+
539
+ .rpc-title {
540
+ display: flex;
541
+ align-items: baseline;
542
+ gap: 8px;
543
+ margin: 10px 0 14px;
544
+ font-family: var(--font-mono);
545
+ flex-wrap: wrap;
546
+ }
547
+
548
+ .rpc-file {
549
+ color: var(--muted);
550
+ font-size: 13px;
551
+ }
552
+
553
+ .rpc-separator {
554
+ color: var(--border);
555
+ }
556
+
557
+ .rpc-function {
558
+ color: var(--text);
559
+ font-size: 18px;
560
+ font-weight: 700;
561
+ }
562
+
563
+ .route-file {
564
+ font-family: var(--font-mono);
565
+ font-size: 11px;
566
+ color: var(--muted);
567
+ margin-left: auto;
568
+ }
569
+
570
+ .route-desc {
571
+ color: var(--muted);
572
+ font-size: 13px;
573
+ margin-bottom: 16px;
574
+ max-width: 640px;
575
+ }
576
+
577
+ /* Type sections */
578
+ .type-section {
579
+ margin: 14px 0;
580
+ }
581
+
582
+ .type-section-title {
583
+ font-size: 12px;
584
+ font-weight: 600;
585
+ text-transform: uppercase;
586
+ letter-spacing: 0.5px;
587
+ color: var(--muted);
588
+ margin-bottom: 8px;
589
+ }
590
+
591
+ .type-name {
592
+ text-transform: none;
593
+ font-weight: 500;
594
+ color: var(--text);
595
+ font-family: var(--font-mono);
596
+ letter-spacing: 0;
597
+ }
598
+
599
+ .type-line {
600
+ color: var(--text);
601
+ font-family: var(--font-mono);
602
+ font-size: 13px;
603
+ margin-bottom: 8px;
604
+ }
605
+
606
+ .type-line code {
607
+ color: var(--accent);
608
+ background: transparent;
609
+ }
610
+
611
+ .type-note {
612
+ max-width: 760px;
613
+ background: var(--code-bg);
614
+ border: 1px solid var(--border);
615
+ border-radius: var(--radius);
616
+ color: var(--muted);
617
+ font-size: 13px;
618
+ padding: 10px 12px;
619
+ }
620
+
621
+ .type-primitive {
622
+ font-family: var(--font-mono);
623
+ font-size: 13px;
624
+ color: var(--text);
625
+ }
626
+
627
+ .confidence-badge {
628
+ display: inline-block;
629
+ vertical-align: 1px;
630
+ margin-left: 6px;
631
+ padding: 1px 6px;
632
+ border-radius: 999px;
633
+ font-size: 10px;
634
+ font-weight: 600;
635
+ text-transform: uppercase;
636
+ letter-spacing: 0.4px;
637
+ }
638
+
639
+ .confidence-explicit { color: var(--accent); background: rgba(74, 222, 128, 0.12); }
640
+ .confidence-inferred { color: var(--link); background: rgba(96, 165, 250, 0.12); }
641
+ .confidence-unknown { color: var(--required); background: rgba(251, 191, 36, 0.12); }
642
+
643
+ .type-muted {
644
+ font-family: var(--font-mono);
645
+ font-size: 13px;
646
+ color: var(--muted);
647
+ }
648
+
649
+ /* Type tree */
650
+ .type-tree,
651
+ .type-leaf {
652
+ max-width: 760px;
653
+ background: var(--code-bg);
654
+ border: 1px solid var(--border);
655
+ border-radius: var(--radius);
656
+ font-family: var(--font-mono);
657
+ font-size: 13px;
658
+ overflow: hidden;
659
+ }
660
+
661
+ .type-tree summary {
662
+ cursor: pointer;
663
+ list-style: none;
664
+ display: flex;
665
+ align-items: center;
666
+ gap: 8px;
667
+ padding: 8px 12px;
668
+ color: var(--text);
669
+ user-select: none;
670
+ }
671
+
672
+ .type-tree summary::-webkit-details-marker { display: none; }
673
+
674
+ .type-tree summary::before {
675
+ content: "▶";
676
+ color: var(--muted);
677
+ font-size: 10px;
678
+ transition: transform 0.12s ease;
679
+ }
680
+
681
+ .type-tree[open] > summary::before { transform: rotate(90deg); }
682
+
683
+ .type-tree summary:hover {
684
+ background: rgba(255, 255, 255, 0.025);
685
+ }
686
+
687
+ .type-tree-nested {
688
+ margin: 8px 12px 12px;
689
+ background: rgba(255, 255, 255, 0.02);
690
+ }
691
+
692
+ .tree-children {
693
+ border-top: 1px solid var(--border);
694
+ }
695
+
696
+ .tree-list {
697
+ list-style: none;
698
+ padding: 4px 12px 10px 28px;
699
+ border-top: 1px solid var(--border);
700
+ }
701
+
702
+ .type-tree > .tree-list {
703
+ border-top: 1px solid var(--border);
704
+ }
705
+
706
+ .tree-field {
707
+ position: relative;
708
+ padding: 5px 0;
709
+ }
710
+
711
+ .tree-field::before {
712
+ content: "";
713
+ position: absolute;
714
+ left: -13px;
715
+ top: 0;
716
+ bottom: 0;
717
+ border-left: 1px solid var(--border);
718
+ }
719
+
720
+ .tree-field::after {
721
+ content: "";
722
+ position: absolute;
723
+ left: -13px;
724
+ top: 15px;
725
+ width: 9px;
726
+ border-top: 1px solid var(--border);
727
+ }
728
+
729
+ .tree-field:last-child::before { bottom: calc(100% - 15px); }
730
+
731
+ .tree-field-line {
732
+ display: flex;
733
+ align-items: baseline;
734
+ gap: 6px;
735
+ flex-wrap: wrap;
736
+ }
737
+
738
+ .tree-label,
739
+ .tree-field-name {
740
+ color: var(--text);
741
+ font-weight: 600;
742
+ }
743
+
744
+ .tree-type,
745
+ .tree-field-type {
746
+ color: var(--accent);
747
+ background: transparent;
748
+ font-family: var(--font-mono);
749
+ }
750
+
751
+ .tree-punct {
752
+ color: var(--muted);
753
+ }
754
+
755
+ .tree-desc {
756
+ color: var(--muted);
757
+ font-family: var(--font-sans);
758
+ font-size: 12px;
759
+ margin: 2px 0 0 0;
760
+ }
761
+
762
+ .tree-empty,
763
+ .type-leaf {
764
+ color: var(--muted);
765
+ padding: 8px 12px;
766
+ }
767
+
768
+ .type-leaf {
769
+ display: flex;
770
+ align-items: center;
771
+ gap: 8px;
772
+ }
773
+
774
+ /* Field table */
775
+ .field-table {
776
+ border-collapse: collapse;
777
+ width: 100%;
778
+ max-width: 640px;
779
+ font-size: 13px;
780
+ }
781
+
782
+ .field-table tr {
783
+ border-bottom: 1px solid var(--border);
784
+ }
785
+
786
+ .field-table tr:last-child {
787
+ border-bottom: none;
788
+ }
789
+
790
+ .field-name {
791
+ font-family: var(--font-mono);
792
+ color: var(--text);
793
+ padding: 6px 14px 6px 0;
794
+ min-width: 120px;
795
+ white-space: nowrap;
796
+ }
797
+
798
+ .field-type {
799
+ font-family: var(--font-mono);
800
+ color: var(--muted);
801
+ padding: 6px 14px 6px 0;
802
+ min-width: 80px;
803
+ }
804
+
805
+ .field-badge {
806
+ padding: 6px 14px 6px 0;
807
+ white-space: nowrap;
808
+ }
809
+
810
+ .field-desc {
811
+ color: var(--muted);
812
+ padding: 6px 0;
813
+ font-size: 12px;
814
+ }
815
+
816
+ /* Try-it */
817
+ .try-it-container {
818
+ margin-top: 18px;
819
+ }
820
+
821
+ .try-it-toggle {
822
+ background: transparent;
823
+ border: 1px solid var(--border);
824
+ color: var(--muted);
825
+ font-size: 12px;
826
+ font-family: var(--font-mono);
827
+ padding: 5px 12px;
828
+ border-radius: var(--radius);
829
+ cursor: pointer;
830
+ transition: color 0.12s, border-color 0.12s, background 0.12s;
831
+ user-select: none;
832
+ }
833
+
834
+ .try-it-toggle:hover,
835
+ .try-it-toggle[aria-expanded="true"] {
836
+ color: var(--accent);
837
+ border-color: var(--accent);
838
+ background: rgba(74, 222, 128, 0.06);
839
+ }
840
+
841
+ .try-it-panel {
842
+ background: var(--surface-2);
843
+ border: 1px solid var(--border);
844
+ border-radius: var(--radius);
845
+ margin-top: 10px;
846
+ overflow: hidden;
847
+ }
848
+
849
+ .try-it-body {
850
+ padding: 16px;
851
+ display: flex;
852
+ flex-direction: column;
853
+ gap: 10px;
854
+ }
855
+
856
+ .try-label {
857
+ font-size: 11px;
858
+ font-weight: 600;
859
+ text-transform: uppercase;
860
+ letter-spacing: 0.5px;
861
+ color: var(--muted);
862
+ }
863
+
864
+ .try-textarea {
865
+ background: var(--code-bg);
866
+ border: 1px solid var(--border);
867
+ color: var(--text);
868
+ font-family: var(--font-mono);
869
+ font-size: 12px;
870
+ padding: 10px 12px;
871
+ border-radius: 4px;
872
+ resize: vertical;
873
+ min-height: 80px;
874
+ outline: none;
875
+ width: 100%;
876
+ max-width: 640px;
877
+ }
878
+
879
+ .try-textarea:focus {
880
+ border-color: var(--accent);
881
+ }
882
+
883
+
884
+
885
+ .try-send-btn {
886
+ width: fit-content;
887
+ background: var(--accent-bg);
888
+ color: var(--accent);
889
+ border: 1px solid rgba(74, 222, 128, 0.3);
890
+ font-size: 13px;
891
+ font-weight: 600;
892
+ font-family: var(--font-sans);
893
+ padding: 6px 18px;
894
+ border-radius: var(--radius);
895
+ cursor: pointer;
896
+ transition: background 0.12s, border-color 0.12s;
897
+ }
898
+
899
+ .try-send-btn:hover {
900
+ background: rgba(74, 222, 128, 0.2);
901
+ border-color: var(--accent);
902
+ }
903
+
904
+ .try-send-btn:disabled {
905
+ opacity: 0.5;
906
+ cursor: not-allowed;
907
+ }
908
+
909
+ /* Response */
910
+ .try-response {
911
+ max-width: 640px;
912
+ }
913
+
914
+ .try-response-meta {
915
+ font-size: 12px;
916
+ font-weight: 600;
917
+ font-family: var(--font-mono);
918
+ margin-bottom: 6px;
919
+ }
920
+
921
+ .try-response-meta.ok { color: var(--accent); }
922
+ .try-response-meta.err { color: var(--error); }
923
+
924
+ .try-response-body {
925
+ background: var(--code-bg);
926
+ border: 1px solid var(--border);
927
+ border-radius: 4px;
928
+ padding: 10px 12px;
929
+ font-family: var(--font-mono);
930
+ font-size: 12px;
931
+ color: var(--text);
932
+ overflow-x: auto;
933
+ white-space: pre-wrap;
934
+ word-break: break-word;
935
+ max-height: 360px;
936
+ overflow-y: auto;
937
+ }
938
+
939
+ .try-response-body.error-body { color: var(--error); }
940
+
941
+ /* Empty notice */
942
+ .empty-notice {
943
+ max-width: 520px;
944
+ margin: 64px auto;
945
+ padding: 32px;
946
+ background: var(--surface);
947
+ border: 1px solid var(--border);
948
+ border-radius: 8px;
949
+ text-align: center;
950
+ }
951
+
952
+ .empty-notice p {
953
+ color: var(--muted);
954
+ margin-bottom: 16px;
955
+ font-size: 14px;
956
+ }
957
+
958
+ .empty-notice code {
959
+ font-family: var(--font-mono);
960
+ font-size: 13px;
961
+ background: var(--code-bg);
962
+ padding: 2px 6px;
963
+ border-radius: 3px;
964
+ color: var(--text);
965
+ }
966
+
967
+ .empty-notice pre {
968
+ background: var(--code-bg);
969
+ border: 1px solid var(--border);
970
+ border-radius: 4px;
971
+ padding: 10px 14px;
972
+ font-family: var(--font-mono);
973
+ font-size: 13px;
974
+ color: var(--accent);
975
+ display: inline-block;
976
+ }
977
+
978
+ /* Scrollbar styling */
979
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
980
+ ::-webkit-scrollbar-track { background: transparent; }
981
+ ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
982
+ ::-webkit-scrollbar-thumb:hover { background: #3a3f52; }
983
+ `;
984
+ // ─── Inline JS ────────────────────────────────────────────────────────────────
985
+ const JS = `
986
+ (function () {
987
+ "use strict";
988
+
989
+ // ── Try-it toggle ────────────────────────────────────────────────────────
990
+ document.querySelectorAll(".try-it-toggle").forEach(function (btn) {
991
+ btn.addEventListener("click", function () {
992
+ var id = btn.getAttribute("data-id");
993
+ var panel = document.getElementById("try-" + id);
994
+ if (!panel) return;
995
+ var expanded = btn.getAttribute("aria-expanded") === "true";
996
+ if (expanded) {
997
+ btn.setAttribute("aria-expanded", "false");
998
+ btn.textContent = "▶ Try it";
999
+ panel.hidden = true;
1000
+ } else {
1001
+ btn.setAttribute("aria-expanded", "true");
1002
+ btn.textContent = "▼ Try it";
1003
+ panel.hidden = false;
1004
+ }
1005
+ });
1006
+ });
1007
+
1008
+ // ── Send button ──────────────────────────────────────────────────────────
1009
+ document.querySelectorAll(".try-send-btn").forEach(function (btn) {
1010
+ btn.addEventListener("click", async function () {
1011
+ var id = btn.getAttribute("data-id");
1012
+ var url = btn.getAttribute("data-url");
1013
+ var textarea = document.getElementById("payload-" + id);
1014
+ var respContainer = document.getElementById("resp-" + id);
1015
+ var respMeta = document.getElementById("resp-meta-" + id);
1016
+ var respBody = document.getElementById("resp-body-" + id);
1017
+
1018
+ if (!textarea || !respContainer || !respMeta || !respBody) return;
1019
+
1020
+ var payload = textarea.value.trim();
1021
+
1022
+ var headers = { "Content-Type": "application/json" };
1023
+
1024
+ btn.disabled = true;
1025
+ btn.textContent = "Sending…";
1026
+ respMeta.textContent = "";
1027
+ respMeta.className = "try-response-meta";
1028
+ respBody.textContent = "";
1029
+ respBody.className = "try-response-body";
1030
+ respContainer.hidden = false;
1031
+
1032
+ var t0 = performance.now();
1033
+
1034
+ try {
1035
+ var res = await fetch(url, {
1036
+ method: "POST",
1037
+ headers: headers,
1038
+ credentials: "same-origin",
1039
+ body: payload || "{}",
1040
+ });
1041
+
1042
+ var elapsed = Math.round(performance.now() - t0);
1043
+ var contentType = res.headers.get("content-type") || "";
1044
+ var isOk = res.ok;
1045
+
1046
+ respMeta.className = "try-response-meta " + (isOk ? "ok" : "err");
1047
+ respMeta.textContent = res.status + " " + res.statusText + " " + elapsed + "ms";
1048
+
1049
+ if (contentType.includes("text/event-stream")) {
1050
+ // Streaming response
1051
+ respBody.textContent = "";
1052
+ var reader = res.body.getReader();
1053
+ var decoder = new TextDecoder();
1054
+ var done = false;
1055
+ while (!done) {
1056
+ var chunk = await reader.read();
1057
+ done = chunk.done;
1058
+ if (chunk.value) {
1059
+ respBody.textContent += decoder.decode(chunk.value, { stream: !done });
1060
+ }
1061
+ }
1062
+ } else {
1063
+ var text = await res.text();
1064
+ try {
1065
+ var json = JSON.parse(text);
1066
+ if (!isOk) {
1067
+ var errors = await import("${ERRORS_MODULE}");
1068
+ if (errors.isMatesError(json)) {
1069
+ var err = errors.reconstructError(json);
1070
+ respBody.textContent = JSON.stringify({
1071
+ name: err.name,
1072
+ message: err.message,
1073
+ status: err.status,
1074
+ code: err.code,
1075
+ fields: err.fields,
1076
+ retryAfter: err.retryAfter,
1077
+ }, null, 2);
1078
+ } else {
1079
+ respBody.textContent = JSON.stringify(json, null, 2);
1080
+ }
1081
+ } else {
1082
+ respBody.textContent = JSON.stringify(json, null, 2);
1083
+ }
1084
+ } catch (_) {
1085
+ respBody.textContent = text;
1086
+ }
1087
+ if (!isOk) {
1088
+ respBody.classList.add("error-body");
1089
+ }
1090
+ }
1091
+ } catch (err) {
1092
+ var elapsed2 = Math.round(performance.now() - t0);
1093
+ respMeta.className = "try-response-meta err";
1094
+ respMeta.textContent = "Error " + elapsed2 + "ms";
1095
+ respBody.textContent = err && err.message ? err.message : String(err);
1096
+ respBody.classList.add("error-body");
1097
+ } finally {
1098
+ btn.disabled = false;
1099
+ btn.textContent = "Send";
1100
+ }
1101
+ });
1102
+ });
1103
+
1104
+ // ── Sidebar active link (scroll spy) ─────────────────────────────────────
1105
+ var sections = Array.from(document.querySelectorAll(".route-section"));
1106
+ var links = Array.from(document.querySelectorAll(".sidebar-link"));
1107
+ var content = document.getElementById("content");
1108
+
1109
+ function updateActive() {
1110
+ var scrollTop = content ? content.scrollTop : window.scrollY;
1111
+ var active = null;
1112
+ for (var i = 0; i < sections.length; i++) {
1113
+ var s = sections[i];
1114
+ if (s.offsetTop <= scrollTop + 80) {
1115
+ active = s.id;
1116
+ }
1117
+ }
1118
+ links.forEach(function (link) {
1119
+ var target = link.getAttribute("data-target");
1120
+ if (target === active) {
1121
+ link.classList.add("active");
1122
+ } else {
1123
+ link.classList.remove("active");
1124
+ }
1125
+ });
1126
+ }
1127
+
1128
+ if (content) {
1129
+ content.addEventListener("scroll", updateActive, { passive: true });
1130
+ } else {
1131
+ window.addEventListener("scroll", updateActive, { passive: true });
1132
+ }
1133
+
1134
+ // Smooth scroll on sidebar link click
1135
+ links.forEach(function (link) {
1136
+ link.addEventListener("click", function (e) {
1137
+ e.preventDefault();
1138
+ var target = link.getAttribute("data-target");
1139
+ var el = document.getElementById(target);
1140
+ if (!el) return;
1141
+ if (content) {
1142
+ content.scrollTo({ top: el.offsetTop - 16, behavior: "smooth" });
1143
+ } else {
1144
+ el.scrollIntoView({ behavior: "smooth", block: "start" });
1145
+ }
1146
+ });
1147
+ });
1148
+
1149
+ updateActive();
1150
+ })();
1151
+ `;
1152
+ //# sourceMappingURL=docs-page.js.map