@fugood/buttress-server 2.25.0-beta.9 → 2.25.0

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 (42) hide show
  1. package/README.md +338 -19
  2. package/config/sample.toml +9 -0
  3. package/lib/autodiscover/index.d.ts +20 -0
  4. package/lib/autodiscover/sign.d.ts +10 -0
  5. package/lib/autodiscover/types.d.ts +32 -0
  6. package/lib/autodiscover/udp.d.ts +22 -0
  7. package/lib/cli.d.ts +3 -0
  8. package/lib/index.d.ts +29 -0
  9. package/lib/index.mjs +1282 -63
  10. package/lib/package.d.ts +7 -0
  11. package/lib/routes/anthropic-messages.d.ts +55 -0
  12. package/lib/routes/file.d.ts +10 -0
  13. package/lib/routes/index.d.ts +5 -0
  14. package/lib/routes/info.check.d.ts +1 -0
  15. package/lib/routes/info.d.ts +4 -0
  16. package/lib/routes/llm-shared.d.ts +54 -0
  17. package/lib/routes/openai-compat.d.ts +17 -0
  18. package/lib/routes/status.d.ts +4 -0
  19. package/lib/services/common.d.ts +29 -0
  20. package/lib/services/create-llm-service.d.ts +24 -0
  21. package/lib/services/ggml-llm.d.ts +5 -0
  22. package/lib/services/ggml-stt.d.ts +26 -0
  23. package/lib/services/index.d.ts +39 -0
  24. package/lib/services/mlx-llm.d.ts +5 -0
  25. package/lib/services/onnx-stt.d.ts +77 -0
  26. package/lib/services/onnx-tts.d.ts +48 -0
  27. package/lib/types.d.ts +158 -0
  28. package/lib/utils/SessionFileManager.d.ts +16 -0
  29. package/lib/utils/buttressAuth.d.ts +25 -0
  30. package/lib/utils/config.d.ts +21 -0
  31. package/lib/utils/httpAuthGuard.d.ts +1 -0
  32. package/lib/utils/net.d.ts +6 -0
  33. package/lib/utils/router.d.ts +2 -0
  34. package/lib/utils/serialize.d.ts +2 -0
  35. package/lib/utils/serverCaps.d.ts +4 -0
  36. package/lib/utils/sessionGuard.d.ts +33 -0
  37. package/lib/utils/test-caps.d.ts +61 -0
  38. package/lib/utils/workspaceState.d.ts +21 -0
  39. package/package.json +10 -8
  40. package/public/status.html +162 -1
  41. package/lib/chunk-C8PTHxhX.mjs +0 -2
  42. package/lib/index.d.mts +0 -370
@@ -0,0 +1,6 @@
1
+ export declare const getLocalIpAddress: () => string | null;
2
+ export interface BroadcastInterface {
3
+ address: string;
4
+ broadcast: string;
5
+ }
6
+ export declare const getBroadcastInterfaces: () => BroadcastInterface[];
@@ -0,0 +1,2 @@
1
+ import type { ButtressApp } from '../types';
2
+ export declare const createRouter: (options?: any) => ButtressApp;
@@ -0,0 +1,2 @@
1
+ export declare const deserialize: (input: string) => any;
2
+ export declare const serialize: (output: any) => string;
@@ -0,0 +1,4 @@
1
+ import type { GeneratorInfo, GeneratorType } from '../types';
2
+ export declare const enrichGeneratorsWithCaps: (generators: {
3
+ type: GeneratorType;
4
+ }[]) => Promise<GeneratorInfo[]>;
@@ -0,0 +1,33 @@
1
+ import type { Session } from '../types';
2
+ type AnyRecord = Record<string, unknown>;
3
+ /**
4
+ * Extract a session id from the `X-Buttress-Sess-Id` request header.
5
+ * Query-param fallback is intentionally not supported: session ids would
6
+ * otherwise show up in proxy access logs and browser history, and there is
7
+ * no transport in our supported clients that can't set custom headers.
8
+ */
9
+ export declare const extractSessionIdFromRequest: (headers: Record<string, string | undefined> | undefined) => string | null;
10
+ /**
11
+ * Elysia `beforeHandle` guard for HTTP routes that operate on a buttress
12
+ * session (file upload/download). Verifies:
13
+ *
14
+ * 1. A session id is supplied via the `X-Buttress-Sess-Id` header.
15
+ * 2. The session exists in the in-memory map (i.e. `init` has been issued
16
+ * over WS for this client).
17
+ * 3. When the server is bound to a workspace, the request's access token
18
+ * identity matches the identity recorded on the session — preventing
19
+ * one device in a workspace from acting on another device's session.
20
+ *
21
+ * Handlers can re-extract the resolved session via `resolveGuardedSession`.
22
+ */
23
+ export declare const buttressSessionGuard: any;
24
+ /**
25
+ * Re-resolve the session that `buttressSessionGuard` validated. Returns null
26
+ * only if called outside the guard's protection (programming error). Handlers
27
+ * should treat null as 500 / unreachable.
28
+ */
29
+ export declare const resolveGuardedSession: (store: AnyRecord, headers: Record<string, string | undefined>) => {
30
+ sessionId: string;
31
+ session: Session;
32
+ } | null;
33
+ export {};
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Display model capabilities in a Markdown table format
3
+ * @param {Object} options - Display options
4
+ * @param {Array<string>} options.modelIds - Array of model repository IDs
5
+ * @param {Object|null} options.defaultConfig - Default configuration from TOML
6
+ * @returns {Promise<void>}
7
+ */
8
+ export declare function showModelsTable({ modelIds, defaultConfig, }?: {
9
+ modelIds?: string[];
10
+ defaultConfig?: any;
11
+ }): Promise<void>;
12
+ /**
13
+ * Test ggml-llm capabilities for a backend type with optional model configuration
14
+ * @param {Object} options - Test options
15
+ * @param {string|null} options.modelId - Model repository ID
16
+ * @param {Object|null} options.defaultConfig - Default configuration from TOML
17
+ * @returns {Promise<void>}
18
+ */
19
+ export declare function testGgmlLlmCapabilities({ modelId, defaultConfig, }?: {
20
+ modelId?: string | null;
21
+ defaultConfig?: any;
22
+ }): Promise<void>;
23
+ /**
24
+ * Display STT model capabilities in a Markdown table format
25
+ * @param {Object} options - Display options
26
+ * @param {Array<string>} options.modelIds - Array of model IDs (format: repo_id:filename)
27
+ * @param {Object|null} options.defaultConfig - Default configuration from TOML
28
+ * @returns {Promise<void>}
29
+ */
30
+ export declare function showSttModelsTable({ modelIds, defaultConfig, }?: {
31
+ modelIds?: string[];
32
+ defaultConfig?: any;
33
+ }): Promise<void>;
34
+ /**
35
+ * Test ggml-stt capabilities for a backend type with optional model configuration
36
+ * @param {Object} options - Test options
37
+ * @param {string|null} options.modelId - Model ID (format: repo_id:filename)
38
+ * @param {Object|null} options.defaultConfig - Default configuration from TOML
39
+ * @returns {Promise<void>}
40
+ */
41
+ /**
42
+ * Display MLX model capabilities in a Markdown table format.
43
+ *
44
+ * MLX getCapabilities is a platform/python check (no per-model GGUF metadata),
45
+ * so the table shows hardware fit based on unified memory and model repo IDs.
46
+ */
47
+ export declare function showMlxModelsTable({ modelIds, defaultConfig, }?: {
48
+ modelIds?: string[];
49
+ defaultConfig?: any;
50
+ }): Promise<void>;
51
+ /**
52
+ * Test MLX LLM capabilities for a single model with detailed output
53
+ */
54
+ export declare function testMlxLlmCapabilities({ modelId, defaultConfig, }?: {
55
+ modelId?: string | null;
56
+ defaultConfig?: any;
57
+ }): Promise<void>;
58
+ export declare function testGgmlSttCapabilities({ modelId, defaultConfig, }?: {
59
+ modelId?: string | null;
60
+ defaultConfig?: any;
61
+ }): Promise<void>;
@@ -0,0 +1,21 @@
1
+ export interface WorkspaceBinding {
2
+ id: string;
3
+ name?: string;
4
+ serverId: string;
5
+ issuerPublicKey: string;
6
+ kid: string;
7
+ boundAt: string;
8
+ }
9
+ export interface ServerKeyPair {
10
+ publicKeySpki: string;
11
+ privateKeyPkcs8: string;
12
+ kid: string;
13
+ }
14
+ export interface WorkspaceState {
15
+ workspace: WorkspaceBinding | null;
16
+ serverKeyPair: ServerKeyPair | null;
17
+ }
18
+ export declare const resolveStateDir: () => string;
19
+ export declare const resolveStatePath: () => string;
20
+ export declare const loadWorkspaceState: () => WorkspaceState;
21
+ export declare const saveWorkspaceState: (state: WorkspaceState) => Promise<void>;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@fugood/buttress-server",
3
- "version": "2.25.0-beta.9",
3
+ "version": "2.25.0",
4
4
  "main": "lib/index.mjs",
5
- "types": "lib/index.d.mts",
5
+ "types": "lib/index.d.ts",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "bricks-buttress": "./bin/bricks-buttress"
@@ -15,7 +15,7 @@
15
15
  ],
16
16
  "scripts": {
17
17
  "typecheck": "tsc --noEmit",
18
- "build": "tsdown -c rolldown.config.js",
18
+ "build": "tsdown -c rolldown.config.js --config-loader native && tsc --noCheck --emitDeclarationOnly",
19
19
  "prepublish": "bun run build",
20
20
  "dev": "bun src/index.ts",
21
21
  "start": "bun lib/index.mjs",
@@ -30,8 +30,8 @@
30
30
  "dependencies": {
31
31
  "@elysiajs/cors": "^1.1.1",
32
32
  "@elysiajs/node": "^1.4.2",
33
- "@fugood/llama.node": "^1.7.0-rc.11",
34
- "@fugood/whisper.node": "^1.0.18",
33
+ "@fugood/llama.node": "1.7.11",
34
+ "@fugood/whisper.node": "^1.1.1",
35
35
  "@huggingface/gguf": "^0.3.2",
36
36
  "@iarna/toml": "^3.0.0",
37
37
  "bytes": "^3.1.0",
@@ -39,11 +39,13 @@
39
39
  "jose": "^5.9.6",
40
40
  "ms": "^2.1.1",
41
41
  "node-machine-id": "^1.1.12",
42
+ "onnxruntime-node": "1.24.3",
43
+ "sharp": "^0.34.1",
42
44
  "zod": "^3.25.76"
43
45
  },
44
46
  "devDependencies": {
45
- "tsdown": "^0.20.1",
46
- "typescript": "^5.9.3"
47
+ "tsdown": "^0.22.4",
48
+ "typescript": "^7.0.2"
47
49
  },
48
- "gitHead": "9274cc21f1e882d26f80e45a972d814d648c861a"
50
+ "gitHead": "a2690b315c7043b65d71f21609b65358cd50d9a4"
49
51
  }
@@ -539,6 +539,48 @@
539
539
  </div>
540
540
  </div>
541
541
  </div>
542
+
543
+ <!-- ONNX-STT Status (hidden unless active) -->
544
+ <div class="card" id="onnxSttCard" style="display:none">
545
+ <div class="card-header">
546
+ <span class="card-title">ONNX-STT Status</span>
547
+ <span class="badge badge-info" id="onnxSttGeneratorCount">0 generators</span>
548
+ </div>
549
+ <div id="onnxSttGenerators"></div>
550
+ <div class="section">
551
+ <div class="section-title collapsible" onclick="toggleSection(this)">Model Load History</div>
552
+ <div class="collapsible-content" id="onnxSttModelHistory">
553
+ <div class="empty-state">No model load history</div>
554
+ </div>
555
+ </div>
556
+ <div class="section">
557
+ <div class="section-title collapsible" onclick="toggleSection(this)">Transcription History</div>
558
+ <div class="collapsible-content" id="onnxSttTranscriptionHistory">
559
+ <div class="empty-state">No transcription history</div>
560
+ </div>
561
+ </div>
562
+ </div>
563
+
564
+ <!-- ONNX-TTS Status (hidden unless active) -->
565
+ <div class="card" id="onnxTtsCard" style="display:none">
566
+ <div class="card-header">
567
+ <span class="card-title">ONNX-TTS Status</span>
568
+ <span class="badge badge-info" id="onnxTtsGeneratorCount">0 generators</span>
569
+ </div>
570
+ <div id="onnxTtsGenerators"></div>
571
+ <div class="section">
572
+ <div class="section-title collapsible" onclick="toggleSection(this)">Model Load History</div>
573
+ <div class="collapsible-content" id="onnxTtsModelHistory">
574
+ <div class="empty-state">No model load history</div>
575
+ </div>
576
+ </div>
577
+ <div class="section">
578
+ <div class="section-title collapsible" onclick="toggleSection(this)">Synthesis History</div>
579
+ <div class="collapsible-content" id="onnxTtsSynthesisHistory">
580
+ <div class="empty-state">No synthesis history</div>
581
+ </div>
582
+ </div>
583
+ </div>
542
584
  </div>
543
585
  </div>
544
586
 
@@ -844,6 +886,59 @@
844
886
  })
845
887
  }
846
888
 
889
+ function formatBytes(bytes) {
890
+ if (!bytes || bytes === 0) return '-'
891
+ if (bytes < 1024) return bytes + ' B'
892
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'
893
+ if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
894
+ return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB'
895
+ }
896
+
897
+ function renderOnnxGenerators(containerId, countId, generators, label) {
898
+ const container = document.getElementById(containerId)
899
+ document.getElementById(countId).textContent = `${generators.length} generator${generators.length !== 1 ? 's' : ''}`
900
+
901
+ withScrollPreserve(container, () => {
902
+ if (generators.length === 0) {
903
+ container.innerHTML = `<div class="empty-state">No ${label} generators loaded</div>`
904
+ return
905
+ }
906
+
907
+ container.innerHTML = `
908
+ <div class="table-wrapper">
909
+ <div class="table-inner">
910
+ <table>
911
+ <thead>
912
+ <tr>
913
+ <th>ID</th>
914
+ <th>Model</th>
915
+ <th>DType</th>
916
+ <th>Provider</th>
917
+ <th>Device</th>
918
+ <th>Model Size</th>
919
+ <th>Pipelines</th>
920
+ </tr>
921
+ </thead>
922
+ <tbody>
923
+ ${generators.map(g => `
924
+ <tr>
925
+ <td class="mono">${escapeHtml(g.id?.slice(0, 8) || '-')}</td>
926
+ <td>${formatModelName(g.repoId)}${g.vocoderRepoId ? '<br><span style="font-size:11px;color:var(--text-muted)">+ ' + formatModelName(g.vocoderRepoId) + '</span>' : ''}</td>
927
+ <td>${escapeHtml(typeof g.dtype === 'object' ? JSON.stringify(g.dtype) : g.dtype || '-')}</td>
928
+ <td><span class="badge ${g.provider === 'cpu' ? 'badge-info' : 'badge-success'}">${escapeHtml(g.provider || '-')}</span></td>
929
+ <td>${escapeHtml(g.device || '-')}</td>
930
+ <td>${formatBytes(g.modelBytes)}</td>
931
+ <td>${g.pipelines ?? 0}</td>
932
+ </tr>
933
+ `).join('')}
934
+ </tbody>
935
+ </table>
936
+ </div>
937
+ </div>
938
+ `
939
+ })
940
+ }
941
+
847
942
  // Escape HTML
848
943
  function escapeHtml(str) {
849
944
  if (str == null) return ''
@@ -869,6 +964,8 @@
869
964
  const llm = status.ggmlLlm || {}
870
965
  const stt = status.ggmlStt || {}
871
966
  const mlx = status.mlxLlm || {}
967
+ const onnxStt = status.onnxStt || {}
968
+ const onnxTts = status.onnxTts || {}
872
969
 
873
970
  // LLM
874
971
  renderLlmGenerators(llm.generators || [])
@@ -983,6 +1080,70 @@
983
1080
  }
984
1081
  },
985
1082
  ])
1083
+
1084
+ // ONNX-STT
1085
+ const hasOnnxStt = (onnxStt.generators?.length > 0) ||
1086
+ (onnxStt.history?.modelLoads?.length > 0) ||
1087
+ (onnxStt.history?.transcriptions?.length > 0)
1088
+ document.getElementById('onnxSttCard').style.display = hasOnnxStt ? '' : 'none'
1089
+ renderOnnxGenerators('onnxSttGenerators', 'onnxSttGeneratorCount', onnxStt.generators || [], 'ONNX STT')
1090
+
1091
+ renderHistory('onnxSttModelHistory', onnxStt.history?.modelLoads || [], [
1092
+ { label: 'Time', render: i => `<span class="timestamp">${formatRelativeTime(i.timestamp)}</span>` },
1093
+ { label: 'Model', render: i => formatModelName(i.repoId) },
1094
+ { label: 'DType', render: i => escapeHtml(typeof i.dtype === 'object' ? JSON.stringify(i.dtype) : i.dtype || '-') },
1095
+ { label: 'Provider', render: i => `<span class="badge ${i.provider === 'cpu' ? 'badge-info' : 'badge-success'}">${escapeHtml(i.provider || '-')}</span>` },
1096
+ { label: 'Duration', render: i => `${(i.durationMs / 1000).toFixed(1)}s` },
1097
+ { label: 'Status', render: i => i.success ?
1098
+ '<span class="badge badge-success">Success</span>' :
1099
+ `<span class="badge badge-error">Failed: ${escapeHtml(i.error || 'Unknown')}</span>`
1100
+ },
1101
+ ])
1102
+
1103
+ renderHistory('onnxSttTranscriptionHistory', onnxStt.history?.transcriptions || [], [
1104
+ { label: 'Time', render: i => `<span class="timestamp">${formatRelativeTime(i.timestamp)}</span>` },
1105
+ { label: 'Model', render: i => formatModelName(i.repoId) },
1106
+ { label: 'Provider', render: i => escapeHtml(i.provider || '-') },
1107
+ { label: 'Segments', render: i => i.segmentCount ?? '-' },
1108
+ { label: 'Text Len', render: i => i.textLength ?? '-' },
1109
+ { label: 'Duration', render: i => `${(i.durationMs / 1000).toFixed(1)}s` },
1110
+ { label: 'Status', render: i => i.success ?
1111
+ '<span class="badge badge-success">Success</span>' :
1112
+ `<span class="badge badge-error">Failed</span>`
1113
+ },
1114
+ ])
1115
+
1116
+ // ONNX-TTS
1117
+ const hasOnnxTts = (onnxTts.generators?.length > 0) ||
1118
+ (onnxTts.history?.modelLoads?.length > 0) ||
1119
+ (onnxTts.history?.syntheses?.length > 0)
1120
+ document.getElementById('onnxTtsCard').style.display = hasOnnxTts ? '' : 'none'
1121
+ renderOnnxGenerators('onnxTtsGenerators', 'onnxTtsGeneratorCount', onnxTts.generators || [], 'ONNX TTS')
1122
+
1123
+ renderHistory('onnxTtsModelHistory', onnxTts.history?.modelLoads || [], [
1124
+ { label: 'Time', render: i => `<span class="timestamp">${formatRelativeTime(i.timestamp)}</span>` },
1125
+ { label: 'Model', render: i => formatModelName(i.repoId) },
1126
+ { label: 'DType', render: i => escapeHtml(typeof i.dtype === 'object' ? JSON.stringify(i.dtype) : i.dtype || '-') },
1127
+ { label: 'Provider', render: i => `<span class="badge ${i.provider === 'cpu' ? 'badge-info' : 'badge-success'}">${escapeHtml(i.provider || '-')}</span>` },
1128
+ { label: 'Vocoder', render: i => i.vocoderRepoId ? formatModelName(i.vocoderRepoId) : '-' },
1129
+ { label: 'Duration', render: i => `${(i.durationMs / 1000).toFixed(1)}s` },
1130
+ { label: 'Status', render: i => i.success ?
1131
+ '<span class="badge badge-success">Success</span>' :
1132
+ `<span class="badge badge-error">Failed: ${escapeHtml(i.error || 'Unknown')}</span>`
1133
+ },
1134
+ ])
1135
+
1136
+ renderHistory('onnxTtsSynthesisHistory', onnxTts.history?.syntheses || [], [
1137
+ { label: 'Time', render: i => `<span class="timestamp">${formatRelativeTime(i.timestamp)}</span>` },
1138
+ { label: 'Model', render: i => formatModelName(i.repoId) },
1139
+ { label: 'Provider', render: i => escapeHtml(i.provider || '-') },
1140
+ { label: 'Text Len', render: i => i.textLength ?? '-' },
1141
+ { label: 'Duration', render: i => i.cached ? '<span class="badge badge-info">Cached</span>' : `${(i.durationMs / 1000).toFixed(1)}s` },
1142
+ { label: 'Status', render: i => i.success ?
1143
+ '<span class="badge badge-success">Success</span>' :
1144
+ `<span class="badge badge-error">Failed</span>`
1145
+ },
1146
+ ])
986
1147
  }
987
1148
 
988
1149
  // Fallback: Fetch status via HTTP polling
@@ -994,7 +1155,7 @@
994
1155
  const response = await fetch('/buttress/status')
995
1156
  const data = await response.json()
996
1157
  // Direct JSON response (not tRPC wrapped)
997
- if (data.ggmlLlm || data.ggmlStt || data.mlxLlm) {
1158
+ if (data.ggmlLlm || data.ggmlStt || data.mlxLlm || data.onnxStt || data.onnxTts) {
998
1159
  updateUI(data)
999
1160
  setConnectionStatus('connected')
1000
1161
  }
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n&&e(r,Symbol.toStringTag,{value:`Module`}),r};export{t};