raffel 1.1.39 → 1.1.42-next.50bacca

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 (65) hide show
  1. package/dist/docs/ui/assets/raffel-docs.css +164 -59
  2. package/dist/docs/ui/assets/raffel-docs.js +235 -2
  3. package/dist/docs/ui/client-script/content.d.ts.map +1 -1
  4. package/dist/docs/ui/client-script/content.js +60 -0
  5. package/dist/docs/ui/client-script/content.js.map +1 -1
  6. package/dist/docs/ui/client-script/endpoint-details.d.ts +1 -1
  7. package/dist/docs/ui/client-script/endpoint-details.d.ts.map +1 -1
  8. package/dist/docs/ui/client-script/endpoint-details.js +1 -1
  9. package/dist/docs/ui/client-script/endpoint-details.js.map +1 -1
  10. package/dist/docs/ui/client-script/navigation.d.ts.map +1 -1
  11. package/dist/docs/ui/client-script/navigation.js +20 -0
  12. package/dist/docs/ui/client-script/navigation.js.map +1 -1
  13. package/dist/docs/ui/client-script/protocols.d.ts +1 -1
  14. package/dist/docs/ui/client-script/protocols.d.ts.map +1 -1
  15. package/dist/docs/ui/client-script/protocols.js +1 -1
  16. package/dist/docs/ui/client-script/protocols.js.map +1 -1
  17. package/dist/docs/ui/html-builder.js +1 -1
  18. package/dist/docs/ui/runtime/index.js +235 -2
  19. package/dist/docs/ui/runtime/index.js.map +1 -1
  20. package/dist/docs/ui/style-sections/content.d.ts +1 -1
  21. package/dist/docs/ui/style-sections/content.d.ts.map +1 -1
  22. package/dist/docs/ui/style-sections/content.js +112 -37
  23. package/dist/docs/ui/style-sections/content.js.map +1 -1
  24. package/dist/docs/ui/style-sections/layout-navigation.d.ts +1 -1
  25. package/dist/docs/ui/style-sections/layout-navigation.d.ts.map +1 -1
  26. package/dist/docs/ui/style-sections/layout-navigation.js +52 -22
  27. package/dist/docs/ui/style-sections/layout-navigation.js.map +1 -1
  28. package/dist/server/fs-routes/index.d.ts +1 -1
  29. package/dist/server/fs-routes/index.d.ts.map +1 -1
  30. package/dist/server/fs-routes/index.js.map +1 -1
  31. package/dist/server/fs-routes/types.d.ts +12 -3
  32. package/dist/server/fs-routes/types.d.ts.map +1 -1
  33. package/dist/server/index.d.ts +1 -1
  34. package/dist/server/index.d.ts.map +1 -1
  35. package/dist/server/index.js.map +1 -1
  36. package/dist/server/rest-middleware.d.ts.map +1 -1
  37. package/dist/server/rest-middleware.js +6 -2
  38. package/dist/server/rest-middleware.js.map +1 -1
  39. package/dist/tcp/telemetry.d.ts +15 -0
  40. package/dist/tcp/telemetry.d.ts.map +1 -0
  41. package/dist/tcp/telemetry.js +25 -0
  42. package/dist/tcp/telemetry.js.map +1 -0
  43. package/dist/udp/metrics.d.ts +15 -0
  44. package/dist/udp/metrics.d.ts.map +1 -0
  45. package/dist/udp/metrics.js +22 -0
  46. package/dist/udp/metrics.js.map +1 -0
  47. package/dist/ui/docs/ui/client-script/content.d.ts.map +1 -1
  48. package/dist/ui/docs/ui/client-script/endpoint-details.d.ts +1 -1
  49. package/dist/ui/docs/ui/client-script/endpoint-details.d.ts.map +1 -1
  50. package/dist/ui/docs/ui/client-script/navigation.d.ts.map +1 -1
  51. package/dist/ui/docs/ui/client-script/protocols.d.ts +1 -1
  52. package/dist/ui/docs/ui/client-script/protocols.d.ts.map +1 -1
  53. package/dist/ui/docs/ui/style-sections/content.d.ts +1 -1
  54. package/dist/ui/docs/ui/style-sections/content.d.ts.map +1 -1
  55. package/dist/ui/docs/ui/style-sections/layout-navigation.d.ts +1 -1
  56. package/dist/ui/docs/ui/style-sections/layout-navigation.d.ts.map +1 -1
  57. package/dist/ui/server/fs-routes/index.d.ts +1 -1
  58. package/dist/ui/server/fs-routes/index.d.ts.map +1 -1
  59. package/dist/ui/server/fs-routes/types.d.ts +12 -3
  60. package/dist/ui/server/fs-routes/types.d.ts.map +1 -1
  61. package/dist/websocket/notifications.d.ts +38 -0
  62. package/dist/websocket/notifications.d.ts.map +1 -0
  63. package/dist/websocket/notifications.js +38 -0
  64. package/dist/websocket/notifications.js.map +1 -0
  65. package/package.json +1 -1
@@ -678,9 +678,10 @@
678
678
 
679
679
  .main-shell {
680
680
  display: grid;
681
- grid-template-columns: 1fr 220px;
682
- align-items: start;
681
+ grid-template-columns: 1fr 380px;
682
+ align-items: stretch;
683
683
  min-width: 0;
684
+ gap: 0;
684
685
  }
685
686
 
686
687
  /* ========== SIDEBAR ========== */
@@ -1089,17 +1090,25 @@
1089
1090
  opacity: 0.7;
1090
1091
  }
1091
1092
 
1092
- /* ========== TOC (On this page) editorial sidenote ========== */
1093
+ /* ========== TOC / TRY IT OUT PANEL (ReDoc-style right panel) ========== */
1093
1094
  .toc {
1094
- align-self: start;
1095
+ align-self: stretch;
1095
1096
  position: sticky;
1096
- top: 24px;
1097
- padding: 8px 0 8px 16px;
1097
+ top: 0;
1098
+ padding: 24px;
1098
1099
  border-left: 1px solid var(--border-color);
1099
1100
  font-size: var(--font-size-small);
1100
1101
  line-height: 1.5;
1101
- max-height: calc(100vh - 48px);
1102
+ max-height: 100vh;
1102
1103
  overflow-y: auto;
1104
+ background: #263238;
1105
+ color: #eceff1;
1106
+ }
1107
+
1108
+ [data-theme="light"] .toc {
1109
+ background: #f5f7fa;
1110
+ color: #263238;
1111
+ border-left-color: #e0e0e0;
1103
1112
  }
1104
1113
 
1105
1114
  .toc:empty {
@@ -1108,40 +1117,61 @@
1108
1117
  }
1109
1118
 
1110
1119
  .toc-title {
1111
- color: var(--text-muted);
1120
+ color: #90caf9;
1112
1121
  font-size: var(--font-size-xs);
1113
1122
  font-weight: 600;
1114
1123
  letter-spacing: 0.04em;
1115
- margin: 0 0 8px;
1124
+ margin: 0 0 16px;
1116
1125
  text-transform: uppercase;
1117
1126
  }
1118
1127
 
1128
+ [data-theme="light"] .toc-title {
1129
+ color: #1976d2;
1130
+ }
1131
+
1119
1132
  .toc-link {
1120
1133
  display: block;
1121
- padding: 3px 0;
1122
- color: var(--text-secondary);
1134
+ padding: 6px 0;
1135
+ color: #b0bec5;
1123
1136
  text-decoration: none;
1124
- border-left: 2px solid transparent;
1125
- margin-left: -16px;
1126
- padding-left: 14px;
1137
+ border-left: 3px solid transparent;
1138
+ margin-left: -24px;
1139
+ padding-left: 21px;
1127
1140
  transition: color 0.15s, border-color 0.15s;
1141
+ font-family: 'SF Mono', 'Monaco', monospace;
1142
+ font-size: 12px;
1128
1143
  }
1129
1144
 
1130
1145
  .toc-link:hover {
1131
- color: var(--text-primary);
1146
+ color: #e0e0e0;
1147
+ border-left-color: #90caf9;
1148
+ }
1149
+
1150
+ [data-theme="light"] .toc-link {
1151
+ color: #666;
1152
+ }
1153
+
1154
+ [data-theme="light"] .toc-link:hover {
1155
+ color: #263238;
1156
+ border-left-color: #1976d2;
1132
1157
  }
1133
1158
 
1134
1159
  .toc-link.active {
1135
- color: var(--text-primary);
1136
- border-left-color: var(--primary-color);
1160
+ color: #e0e0e0;
1161
+ border-left-color: #90caf9;
1137
1162
  font-weight: 600;
1138
1163
  }
1139
1164
 
1140
- .toc-level-2 { padding-left: 14px; }
1141
- .toc-level-3 { padding-left: 26px; }
1142
- .toc-level-4 { padding-left: 38px; }
1143
- .toc-level-5 { padding-left: 50px; }
1144
- .toc-level-6 { padding-left: 62px; }
1165
+ [data-theme="light"] .toc-link.active {
1166
+ color: #263238;
1167
+ border-left-color: #1976d2;
1168
+ }
1169
+
1170
+ .toc-level-2 { padding-left: 27px; }
1171
+ .toc-level-3 { padding-left: 39px; }
1172
+ .toc-level-4 { padding-left: 51px; }
1173
+ .toc-level-5 { padding-left: 63px; }
1174
+ .toc-level-6 { padding-left: 75px; }
1145
1175
  /* ========== SEARCH MODAL (cmd+K) ========== */
1146
1176
  dialog.search-modal {
1147
1177
  padding: 0;
@@ -2230,25 +2260,35 @@
2230
2260
  /* ========== REDOC-STYLE PARAMETERS ========== */
2231
2261
  .param-row {
2232
2262
  display: flex;
2233
- padding: 16px 0;
2234
- border-bottom: 1px solid var(--border-color);
2263
+ padding: 12px;
2264
+ margin-bottom: 12px;
2265
+ border: 1px solid var(--border-color);
2266
+ border-radius: 6px;
2267
+ background: var(--surface-color);
2268
+ transition: border-color 0.15s, background 0.15s;
2269
+ }
2270
+
2271
+ .param-row:hover {
2272
+ border-color: var(--primary-color);
2273
+ background: var(--hover-bg);
2235
2274
  }
2236
2275
 
2237
2276
  .param-row:last-child {
2238
- border-bottom: none;
2277
+ margin-bottom: 0;
2239
2278
  }
2240
2279
 
2241
2280
  .param-tree {
2242
- width: 24px;
2281
+ width: 20px;
2243
2282
  display: flex;
2244
2283
  align-items: flex-start;
2245
- padding-top: 4px;
2284
+ padding-top: 2px;
2246
2285
  color: var(--border-color);
2286
+ margin-right: 8px;
2247
2287
  }
2248
2288
 
2249
2289
  .param-tree-line {
2250
- width: 12px;
2251
- height: 12px;
2290
+ width: 10px;
2291
+ height: 10px;
2252
2292
  border-left: 1px solid var(--border-color);
2253
2293
  border-bottom: 1px solid var(--border-color);
2254
2294
  }
@@ -2259,9 +2299,9 @@
2259
2299
 
2260
2300
  .param-header {
2261
2301
  display: flex;
2262
- align-items: baseline;
2263
- gap: 8px;
2264
- margin-bottom: 4px;
2302
+ align-items: center;
2303
+ gap: 12px;
2304
+ margin-bottom: 8px;
2265
2305
  flex-wrap: wrap;
2266
2306
  }
2267
2307
 
@@ -2273,31 +2313,54 @@
2273
2313
  }
2274
2314
 
2275
2315
  .param-required-badge {
2276
- font-size: 11px;
2277
- font-weight: 600;
2278
- color: #ef4444;
2279
- text-transform: lowercase;
2316
+ font-size: 10px;
2317
+ font-weight: 700;
2318
+ padding: 3px 8px;
2319
+ border-radius: 4px;
2320
+ background: #fee2e2;
2321
+ color: #991b1b;
2322
+ text-transform: uppercase;
2323
+ letter-spacing: 0.3px;
2324
+ }
2325
+
2326
+ [data-theme="dark"] .param-required-badge {
2327
+ background: #7f1d1d;
2328
+ color: #fca5a5;
2280
2329
  }
2281
2330
 
2282
2331
  .param-type-info {
2283
2332
  font-family: 'SF Mono', 'Monaco', monospace;
2284
- font-size: 13px;
2285
- color: var(--text-muted);
2333
+ font-size: 12px;
2334
+ padding: 2px 8px;
2335
+ border-radius: 4px;
2336
+ background: rgba(99, 102, 241, 0.1);
2337
+ color: #6366f1;
2338
+ }
2339
+
2340
+ [data-theme="dark"] .param-type-info {
2341
+ background: rgba(129, 140, 248, 0.15);
2342
+ color: #a5b4fc;
2286
2343
  }
2287
2344
 
2288
2345
  .param-type-info .format {
2289
2346
  color: #8b5cf6;
2290
2347
  }
2291
2348
 
2349
+ [data-theme="dark"] .param-type-info .format {
2350
+ color: #c4b5fd;
2351
+ }
2352
+
2292
2353
  .param-constraint {
2293
2354
  display: inline-block;
2294
- font-size: 11px;
2295
- padding: 2px 6px;
2355
+ font-size: 10px;
2356
+ padding: 3px 8px;
2296
2357
  border-radius: 4px;
2297
2358
  background: #fef3c7;
2298
2359
  color: #92400e;
2299
2360
  font-family: 'SF Mono', 'Monaco', monospace;
2300
2361
  margin-left: 4px;
2362
+ text-transform: uppercase;
2363
+ letter-spacing: 0.3px;
2301
2364
  }
2302
2365
 
2303
2366
  [data-theme="dark"] .param-constraint {
@@ -2306,53 +2369,61 @@
2306
2369
  }
2307
2370
 
2308
2371
  .param-default {
2309
- font-size: 13px;
2372
+ font-size: 12px;
2310
2373
  color: var(--text-muted);
2311
- margin-top: 4px;
2374
+ margin-top: 6px;
2312
2375
  }
2313
2376
 
2314
2377
  .param-default code {
2315
2378
  background: var(--code-bg);
2316
- padding: 2px 6px;
2317
- border-radius: 4px;
2379
+ padding: 3px 6px;
2380
+ border-radius: 3px;
2318
2381
  font-family: 'SF Mono', 'Monaco', monospace;
2382
+ font-size: 11px;
2319
2383
  }
2320
2384
 
2321
2385
  .param-example {
2322
- font-size: 13px;
2386
+ font-size: 12px;
2323
2387
  color: var(--text-muted);
2324
- margin-top: 4px;
2388
+ margin-top: 6px;
2325
2389
  }
2326
2390
 
2327
2391
  .param-example code {
2328
2392
  background: var(--code-bg);
2329
- padding: 2px 6px;
2330
- border-radius: 4px;
2393
+ padding: 3px 6px;
2394
+ border-radius: 3px;
2331
2395
  font-family: 'SF Mono', 'Monaco', monospace;
2396
+ font-size: 11px;
2332
2397
  }
2333
2398
 
2334
2399
  .param-description {
2335
- font-size: 14px;
2400
+ font-size: 13px;
2336
2401
  color: var(--text-color);
2337
2402
  line-height: 1.5;
2338
- margin-top: 6px;
2403
+ margin-top: 8px;
2339
2404
  }
2340
2405
 
2341
2406
  /* ========== REDOC-STYLE RESPONSES ========== */
2342
2407
  .response-item {
2343
2408
  border: 1px solid var(--border-color);
2344
- border-radius: 4px;
2345
- margin-bottom: 8px;
2409
+ border-radius: 6px;
2410
+ margin-bottom: 12px;
2346
2411
  overflow: hidden;
2412
+ transition: border-color 0.15s, box-shadow 0.15s;
2413
+ }
2414
+
2415
+ .response-item:hover {
2416
+ border-color: var(--primary-color);
2347
2417
  }
2348
2418
 
2349
2419
  .response-header {
2350
2420
  display: flex;
2351
2421
  align-items: center;
2352
2422
  gap: 12px;
2353
- padding: 12px 16px;
2423
+ padding: 14px 16px;
2354
2424
  cursor: pointer;
2355
2425
  transition: background 0.15s;
2426
+ background: var(--surface-color);
2356
2427
  }
2357
2428
 
2358
2429
  .response-header:hover {
@@ -2360,9 +2431,11 @@
2360
2431
  }
2361
2432
 
2362
2433
  .response-arrow {
2363
- font-size: 10px;
2434
+ font-size: 11px;
2364
2435
  transition: transform 0.2s;
2365
2436
  color: var(--text-muted);
2437
+ width: 16px;
2438
+ text-align: center;
2366
2439
  }
2367
2440
 
2368
2441
  .response-item.expanded .response-arrow {
@@ -2370,13 +2443,45 @@
2370
2443
  }
2371
2444
 
2372
2445
  .response-status {
2373
- font-size: 14px;
2374
- font-weight: 600;
2446
+ font-size: 13px;
2447
+ font-weight: 700;
2448
+ padding: 4px 10px;
2449
+ border-radius: 4px;
2450
+ min-width: 50px;
2451
+ text-align: center;
2452
+ text-transform: uppercase;
2453
+ letter-spacing: 0.5px;
2454
+ }
2455
+
2456
+ .response-status.status-2xx {
2457
+ background: #dcfce7;
2458
+ color: #166534;
2375
2459
  }
2376
2460
 
2377
- .response-status.status-2xx { color: #10b981; }
2378
- .response-status.status-4xx { color: #f59e0b; }
2379
- .response-status.status-5xx { color: #ef4444; }
2461
+ [data-theme="dark"] .response-status.status-2xx {
2462
+ background: #064e3b;
2463
+ color: #86efac;
2464
+ }
2465
+
2466
+ .response-status.status-4xx {
2467
+ background: #fed7aa;
2468
+ color: #92400e;
2469
+ }
2470
+
2471
+ [data-theme="dark"] .response-status.status-4xx {
2472
+ background: #78350f;
2473
+ color: #fdba74;
2474
+ }
2475
+
2476
+ .response-status.status-5xx {
2477
+ background: #fee2e2;
2478
+ color: #991b1b;
2479
+ }
2480
+
2481
+ [data-theme="dark"] .response-status.status-5xx {
2482
+ background: #7f1d1d;
2483
+ color: #fca5a5;
2484
+ }
2380
2485
 
2381
2486
  .response-desc {
2382
2487
  font-size: 14px;
@@ -1186,14 +1186,244 @@ function appendSidebarGroup(nav, title, items) {
1186
1186
  group.appendChild(itemContainer);
1187
1187
  nav.appendChild(group);
1188
1188
  }
1189
+ function generateExampleFromSchema(schema) {
1190
+ if (!schema)
1191
+ return null;
1192
+ if (schema.$ref)
1193
+ return { $ref: schema.$ref };
1194
+ if (schema.example !== undefined)
1195
+ return schema.example;
1196
+ if (schema.default !== undefined)
1197
+ return schema.default;
1198
+ if (schema.enum && schema.enum.length > 0)
1199
+ return schema.enum[0];
1200
+ switch (schema.type) {
1201
+ case 'string': return schema.format === 'email' ? 'user@example.com' : 'string';
1202
+ case 'number': return 0;
1203
+ case 'integer': return 0;
1204
+ case 'boolean': return true;
1205
+ case 'array': return schema.items ? [generateExampleFromSchema(schema.items)] : [];
1206
+ case 'object':
1207
+ if (!schema.properties)
1208
+ return {};
1209
+ const obj = {};
1210
+ Object.entries(schema.properties).forEach(([key, prop]) => {
1211
+ obj[key] = generateExampleFromSchema(prop);
1212
+ });
1213
+ return obj;
1214
+ default: return null;
1215
+ }
1216
+ }
1217
+ function renderCodeExamples(endpoint, data) {
1218
+ const container = doc.createElement('div');
1219
+ container.style.marginTop = '20px';
1220
+ container.style.paddingTop = '16px';
1221
+ container.style.borderTop = '1px solid var(--border-color)';
1222
+ // cURL example
1223
+ const method = endpoint.method?.toUpperCase() || 'GET';
1224
+ const path = endpoint.path || '/';
1225
+ const baseUrl = 'http://localhost:3000';
1226
+ const curlSection = doc.createElement('div');
1227
+ curlSection.style.marginBottom = '20px';
1228
+ curlSection.innerHTML = '<div style="font-size: 12px; font-weight: 600; color: var(--text-secondary); margin-bottom: 8px;">cURL EXAMPLE</div>';
1229
+ const curlCode = doc.createElement('pre');
1230
+ curlCode.style.backgroundColor = 'var(--bg-secondary)';
1231
+ curlCode.style.padding = '12px';
1232
+ curlCode.style.borderRadius = '4px';
1233
+ curlCode.style.fontSize = '12px';
1234
+ curlCode.style.overflow = 'auto';
1235
+ let curlCmd = `curl -X ${method} "${baseUrl}${path}"`;
1236
+ const reqBody = data.requestBody?.content?.[Object.keys(data.requestBody.content)[0]];
1237
+ if (reqBody && ['POST', 'PUT', 'PATCH'].includes(method)) {
1238
+ const example = generateExampleFromSchema(reqBody.schema);
1239
+ curlCmd += ` \\\n -H "Content-Type: application/json" \\\n -d '${JSON.stringify(example, null, 2).split('\n').join('\n ')}'`;
1240
+ }
1241
+ curlCode.textContent = curlCmd;
1242
+ curlSection.appendChild(curlCode);
1243
+ container.appendChild(curlSection);
1244
+ // Response example
1245
+ if (data.responses) {
1246
+ const responses = Object.entries(data.responses);
1247
+ if (responses.length > 0) {
1248
+ const [status, resp] = responses[0];
1249
+ const respSection = doc.createElement('div');
1250
+ respSection.innerHTML = `<div style="font-size: 12px; font-weight: 600; color: var(--text-secondary); margin-bottom: 8px;">RESPONSE ${status}</div>`;
1251
+ const respCode = doc.createElement('pre');
1252
+ respCode.style.backgroundColor = 'var(--bg-secondary)';
1253
+ respCode.style.padding = '12px';
1254
+ respCode.style.borderRadius = '4px';
1255
+ respCode.style.fontSize = '12px';
1256
+ respCode.style.overflow = 'auto';
1257
+ if (resp.content) {
1258
+ const contentType = Object.keys(resp.content)[0];
1259
+ const schema = resp.content[contentType]?.schema;
1260
+ const example = generateExampleFromSchema(schema);
1261
+ respCode.textContent = JSON.stringify(example, null, 2);
1262
+ }
1263
+ else {
1264
+ respCode.textContent = `{}`;
1265
+ }
1266
+ respSection.appendChild(respCode);
1267
+ container.appendChild(respSection);
1268
+ }
1269
+ }
1270
+ return container;
1271
+ }
1272
+ function renderSchemaTree(parent, schema, depth = 0) {
1273
+ if (!schema)
1274
+ return;
1275
+ const div = doc.createElement('div');
1276
+ div.style.paddingLeft = depth > 0 ? `${depth * 12}px` : '0';
1277
+ div.style.marginTop = depth === 0 ? '8px' : '0';
1278
+ if (schema.$ref) {
1279
+ const refName = String(schema.$ref).split('/').pop();
1280
+ const row = doc.createElement('div');
1281
+ row.style.padding = '4px 0';
1282
+ row.innerHTML = `<span style="color: #888; font-style: italic;">$ref: ${esc(refName)}</span>`;
1283
+ div.appendChild(row);
1284
+ }
1285
+ else if (schema.type === 'object' && schema.properties) {
1286
+ Object.entries(schema.properties).forEach(([key, prop]) => {
1287
+ const row = doc.createElement('div');
1288
+ row.style.padding = '6px 0';
1289
+ row.style.borderLeft = depth === 0 ? '2px solid var(--border-color)' : 'none';
1290
+ row.style.paddingLeft = depth === 0 ? '8px' : '0';
1291
+ const type = prop.type || 'any';
1292
+ const required = schema.required?.includes(key) ? '<span style="color: #ef4444; margin-left: 4px;">*</span>' : '';
1293
+ const format = prop.format ? ` (${prop.format})` : '';
1294
+ row.innerHTML = `<div style="font-weight: 500; color: var(--text-primary); display: flex; align-items: center;">${esc(key)}${required} <span style="color: var(--text-secondary); font-weight: normal; margin-left: 8px;">${type}${format}</span></div>`;
1295
+ if (prop.description) {
1296
+ const desc = doc.createElement('div');
1297
+ desc.style.fontSize = '12px';
1298
+ desc.style.color = 'var(--text-muted)';
1299
+ desc.style.marginTop = '4px';
1300
+ desc.textContent = prop.description;
1301
+ row.appendChild(desc);
1302
+ }
1303
+ if (prop.example !== undefined) {
1304
+ const ex = doc.createElement('div');
1305
+ ex.style.fontSize = '11px';
1306
+ ex.style.color = '#888';
1307
+ ex.style.marginTop = '2px';
1308
+ ex.style.fontFamily = 'monospace';
1309
+ ex.textContent = `Example: ${JSON.stringify(prop.example)}`;
1310
+ row.appendChild(ex);
1311
+ }
1312
+ if (prop.enum) {
1313
+ const en = doc.createElement('div');
1314
+ en.style.fontSize = '11px';
1315
+ en.style.color = '#888';
1316
+ en.style.marginTop = '2px';
1317
+ en.textContent = `Values: ${prop.enum.join(', ')}`;
1318
+ row.appendChild(en);
1319
+ }
1320
+ div.appendChild(row);
1321
+ if (prop.properties) {
1322
+ renderSchemaTree(div, prop, depth + 1);
1323
+ }
1324
+ });
1325
+ }
1326
+ else if (schema.type === 'array' && schema.items) {
1327
+ const row = doc.createElement('div');
1328
+ row.style.padding = '6px 0';
1329
+ row.innerHTML = `<span style="color: var(--text-primary); font-weight: 500;">array</span> <span style="color: var(--text-secondary);">of ${schema.items.type || 'object'}</span>`;
1330
+ div.appendChild(row);
1331
+ if (schema.items.properties) {
1332
+ renderSchemaTree(div, schema.items, depth + 1);
1333
+ }
1334
+ }
1335
+ else {
1336
+ const row = doc.createElement('div');
1337
+ row.style.padding = '6px 0';
1338
+ row.innerHTML = `<span style="color: var(--text-secondary);">${esc(schema.type || 'any')}</span>`;
1339
+ div.appendChild(row);
1340
+ }
1341
+ parent.appendChild(div);
1342
+ }
1189
1343
  function renderEndpointDetails(endpoint) {
1190
1344
  const container = doc.createElement('div');
1191
1345
  container.className = 'endpoint-details';
1192
1346
  const data = (endpoint.data ?? {});
1193
1347
  appendProtocolConsole(container, { doc, spec, wsSpec, streamsSpec, jsonrpcSpec, activeProtocol, endpoint, data, esc, escapeAttr });
1194
1348
  const appendMany = (items) => items.forEach(([title, value]) => appendSchemaSubsection(container, title, value));
1195
- if (activeProtocol === 'http')
1196
- appendMany([['Parameters', data.parameters], ['Request Body', getFirstContentSchema(data.requestBody?.content)], ['Responses', data.responses]]);
1349
+ if (activeProtocol === 'http') {
1350
+ const params = (data.parameters ?? []);
1351
+ if (params.length > 0) {
1352
+ const section = doc.createElement('div');
1353
+ section.className = 'endpoint-subsection';
1354
+ section.innerHTML = '<div class="subsection-label">PARAMETERS</div>';
1355
+ const grid = doc.createElement('div');
1356
+ grid.className = 'info-grid';
1357
+ params.forEach(p => {
1358
+ grid.innerHTML += `<div class="info-card"><div class="info-card-title">${esc(p.name)}</div><div class="info-card-value">${esc(p.in || 'query')} • ${esc(p.schema?.type || 'string')}${p.required ? ' *' : ''}</div></div>`;
1359
+ });
1360
+ section.appendChild(grid);
1361
+ container.appendChild(section);
1362
+ }
1363
+ const reqBody = data.requestBody;
1364
+ if (reqBody?.content) {
1365
+ const section = doc.createElement('div');
1366
+ section.className = 'endpoint-subsection';
1367
+ section.innerHTML = '<div class="subsection-label">REQUEST BODY</div>';
1368
+ const content = reqBody.content[Object.keys(reqBody.content)[0]];
1369
+ if (content?.schema) {
1370
+ renderSchemaTree(section, content.schema);
1371
+ }
1372
+ container.appendChild(section);
1373
+ }
1374
+ const responses = data.responses;
1375
+ if (responses && Object.keys(responses).length > 0) {
1376
+ const section = doc.createElement('div');
1377
+ section.className = 'endpoint-subsection';
1378
+ section.innerHTML = '<div class="subsection-label">RESPONSES</div>';
1379
+ Object.entries(responses).forEach(([status, resp]) => {
1380
+ const statusClass = status.startsWith('2') ? 'status-2xx' : status.startsWith('4') ? 'status-4xx' : 'status-5xx';
1381
+ const item = doc.createElement('div');
1382
+ item.style.marginBottom = '16px';
1383
+ item.style.padding = '12px';
1384
+ item.style.borderRadius = '6px';
1385
+ item.style.backgroundColor = 'var(--bg-secondary)';
1386
+ item.innerHTML = `<div style="color: var(--text-secondary); font-size: 14px; margin-bottom: 12px; display: flex; align-items: center; gap: 8px;"><span class="badge badge-${statusClass}">${status}</span> <strong>${esc(resp.description || '')}</strong></div>`;
1387
+ // Headers
1388
+ if (resp.headers && Object.keys(resp.headers).length > 0) {
1389
+ const headersDiv = doc.createElement('div');
1390
+ headersDiv.style.marginBottom = '12px';
1391
+ headersDiv.innerHTML = '<div style="font-size: 12px; font-weight: 600; color: var(--text-secondary); margin-bottom: 6px;">HEADERS</div>';
1392
+ const headersList = doc.createElement('div');
1393
+ headersList.style.fontSize = '12px';
1394
+ Object.entries(resp.headers).forEach(([headerName, headerDef]) => {
1395
+ const headerRow = doc.createElement('div');
1396
+ headerRow.style.padding = '4px 0';
1397
+ headerRow.style.borderLeft = '2px solid var(--border-color)';
1398
+ headerRow.style.paddingLeft = '8px';
1399
+ const headerType = headerDef.schema?.type || 'string';
1400
+ headerRow.innerHTML = `<div style="font-weight: 500; color: var(--text-primary);">${esc(headerName)}</div><div style="color: var(--text-muted); font-size: 11px;">${headerType}</div>${headerDef.description ? `<div style="color: var(--text-muted); font-size: 11px; margin-top: 2px;">${esc(headerDef.description)}</div>` : ''}`;
1401
+ headersList.appendChild(headerRow);
1402
+ });
1403
+ headersDiv.appendChild(headersList);
1404
+ item.appendChild(headersDiv);
1405
+ }
1406
+ // Schema
1407
+ if (resp.content) {
1408
+ const contentType = Object.keys(resp.content)[0];
1409
+ const schema = resp.content[contentType]?.schema;
1410
+ if (schema) {
1411
+ const schemaDiv = doc.createElement('div');
1412
+ schemaDiv.innerHTML = '<div style="font-size: 12px; font-weight: 600; color: var(--text-secondary); margin-bottom: 6px;">SCHEMA</div>';
1413
+ renderSchemaTree(schemaDiv, schema);
1414
+ item.appendChild(schemaDiv);
1415
+ }
1416
+ }
1417
+ section.appendChild(item);
1418
+ });
1419
+ container.appendChild(section);
1420
+ }
1421
+ // Code examples
1422
+ const examplesSection = doc.createElement('div');
1423
+ examplesSection.className = 'endpoint-subsection';
1424
+ examplesSection.appendChild(renderCodeExamples(endpoint, data));
1425
+ container.appendChild(examplesSection);
1426
+ }
1197
1427
  if (activeProtocol === 'websocket') {
1198
1428
  appendInfoGrid(container, [['Channel Type', data.type], ['Path', endpoint.path]]);
1199
1429
  appendMany([['Parameters', parameterMapToSchema(data.parameters)], ['Subscribe Message', resolveMessagePayload(data.subscribe?.message)], ['Publish Message', resolveMessagePayload(data.publish?.message)]]);
@@ -2026,6 +2256,9 @@ function init() {
2026
2256
  render();
2027
2257
  startDocsStatePolling();
2028
2258
  // Mount cmd+K / ctrl+K search modal (skipped when sidebar search is disabled).
2259
+ // Dispose any previously-mounted modal so a re-initialised runtime never
2260
+ // leaves a duplicate dialog or a stale keydown listener behind.
2261
+ win.RaffelDocs?.searchModal?.dispose?.();
2029
2262
  const modal = createDocsSearchModal({
2030
2263
  doc, win, enabled: sidebarConfig?.search !== false,
2031
2264
  altShortcut: typeof sidebarConfig?.searchModalAltShortcut === 'string' ? String(sidebarConfig.searchModalAltShortcut) : '',
@@ -1 +1 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../../src/docs/ui/client-script/content.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,mBAAmB,QA2V/B,CAAA"}
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../../src/docs/ui/client-script/content.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,mBAAmB,QAuZ/B,CAAA"}