llm-simple-router 0.7.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/admin/proxy-enhancement.js +3 -1
  2. package/dist/admin/routes.d.ts +1 -0
  3. package/dist/admin/routes.js +3 -1
  4. package/dist/admin/settings-import-export.d.ts +1 -0
  5. package/dist/admin/settings-import-export.js +7 -0
  6. package/dist/admin/transform-rules.d.ts +8 -0
  7. package/dist/admin/transform-rules.js +38 -0
  8. package/dist/admin/usage.js +1 -1
  9. package/dist/core/container.d.ts +1 -0
  10. package/dist/core/container.js +1 -0
  11. package/dist/db/migrations/034_create_provider_transform_rules.sql +11 -0
  12. package/dist/db/transform-rules.d.ts +16 -0
  13. package/dist/db/transform-rules.js +51 -0
  14. package/dist/index.js +30 -1
  15. package/dist/metrics/sse-parser.d.ts +2 -0
  16. package/dist/metrics/sse-parser.js +4 -0
  17. package/dist/monitor/request-tracker.d.ts +2 -0
  18. package/dist/monitor/request-tracker.js +22 -1
  19. package/dist/monitor/types.d.ts +1 -1
  20. package/dist/proxy/enhancement/response-cleaner.js +14 -6
  21. package/dist/proxy/handler/openai.js +13 -4
  22. package/dist/proxy/handler/proxy-handler-utils.js +2 -7
  23. package/dist/proxy/handler/proxy-handler.js +85 -18
  24. package/dist/proxy/patch/deepseek/index.d.ts +15 -3
  25. package/dist/proxy/patch/deepseek/index.js +29 -6
  26. package/dist/proxy/patch/deepseek/patch-cache-control.d.ts +6 -0
  27. package/dist/proxy/patch/deepseek/patch-cache-control.js +30 -0
  28. package/dist/proxy/patch/deepseek/patch-non-deepseek-tools.d.ts +16 -0
  29. package/dist/proxy/patch/deepseek/patch-non-deepseek-tools.js +74 -0
  30. package/dist/proxy/patch/deepseek/patch-orphan-tool-results.d.ts +10 -1
  31. package/dist/proxy/patch/deepseek/patch-orphan-tool-results.js +58 -15
  32. package/dist/proxy/patch/deepseek/patch-thinking-blocks.d.ts +5 -1
  33. package/dist/proxy/patch/deepseek/patch-thinking-blocks.js +37 -4
  34. package/dist/proxy/patch/deepseek/patch-thinking-param.d.ts +6 -0
  35. package/dist/proxy/patch/deepseek/patch-thinking-param.js +32 -0
  36. package/dist/proxy/patch/deepseek/utils.d.ts +8 -0
  37. package/dist/proxy/patch/deepseek/utils.js +38 -0
  38. package/dist/proxy/patch/index.d.ts +2 -2
  39. package/dist/proxy/patch/index.js +50 -4
  40. package/dist/proxy/patch/router-cleanup.js +1 -24
  41. package/dist/proxy/patch/safe-sse-parser.d.ts +9 -0
  42. package/dist/proxy/patch/safe-sse-parser.js +16 -0
  43. package/dist/proxy/patch/tool-round-limiter.d.ts +38 -0
  44. package/dist/proxy/patch/tool-round-limiter.js +115 -0
  45. package/dist/proxy/pipeline-snapshot.d.ts +4 -0
  46. package/dist/proxy/proxy-core.js +1 -0
  47. package/dist/proxy/proxy-logging.d.ts +1 -1
  48. package/dist/proxy/proxy-logging.js +3 -3
  49. package/dist/proxy/routing/enhancement-config.d.ts +1 -0
  50. package/dist/proxy/routing/enhancement-config.js +2 -0
  51. package/dist/proxy/transform/id-utils.d.ts +3 -0
  52. package/dist/proxy/transform/id-utils.js +9 -0
  53. package/dist/proxy/transform/message-mapper.d.ts +15 -0
  54. package/dist/proxy/transform/message-mapper.js +173 -0
  55. package/dist/proxy/transform/plugin-registry.d.ts +23 -0
  56. package/dist/proxy/transform/plugin-registry.js +130 -0
  57. package/dist/proxy/transform/plugin-types.d.ts +46 -0
  58. package/dist/proxy/transform/plugin-types.js +15 -0
  59. package/dist/proxy/transform/provider-meta.d.ts +29 -0
  60. package/dist/proxy/transform/provider-meta.js +72 -0
  61. package/dist/proxy/transform/request-transform.d.ts +4 -0
  62. package/dist/proxy/transform/request-transform.js +151 -0
  63. package/dist/proxy/transform/response-transform.d.ts +4 -0
  64. package/dist/proxy/transform/response-transform.js +99 -0
  65. package/dist/proxy/transform/sanitize.d.ts +3 -0
  66. package/dist/proxy/transform/sanitize.js +24 -0
  67. package/dist/proxy/transform/stream-ant2oa.d.ts +20 -0
  68. package/dist/proxy/transform/stream-ant2oa.js +200 -0
  69. package/dist/proxy/transform/stream-oa2ant.d.ts +25 -0
  70. package/dist/proxy/transform/stream-oa2ant.js +201 -0
  71. package/dist/proxy/transform/stream-transform-base.d.ts +19 -0
  72. package/dist/proxy/transform/stream-transform-base.js +61 -0
  73. package/dist/proxy/transform/thinking-mapper.d.ts +4 -0
  74. package/dist/proxy/transform/thinking-mapper.js +15 -0
  75. package/dist/proxy/transform/tool-mapper.d.ts +8 -0
  76. package/dist/proxy/transform/tool-mapper.js +67 -0
  77. package/dist/proxy/transform/transform-coordinator.d.ts +11 -0
  78. package/dist/proxy/transform/transform-coordinator.js +32 -0
  79. package/dist/proxy/transform/types.d.ts +43 -0
  80. package/dist/proxy/transform/types.js +1 -0
  81. package/dist/proxy/transform/usage-mapper.d.ts +8 -0
  82. package/dist/proxy/transform/usage-mapper.js +46 -0
  83. package/dist/proxy/transport/stream.d.ts +1 -1
  84. package/dist/proxy/transport/stream.js +19 -10
  85. package/dist/proxy/transport/transport-fn.d.ts +3 -0
  86. package/dist/proxy/transport/transport-fn.js +11 -4
  87. package/dist/storage/log-file-compressor.js +5 -6
  88. package/dist/storage/log-file-writer.js +11 -13
  89. package/dist/storage/types.d.ts +2 -0
  90. package/dist/storage/types.js +7 -0
  91. package/frontend-dist/assets/{CardContent-CxOF1feY.js → CardContent-BVMQ2_pg.js} +1 -1
  92. package/frontend-dist/assets/{CardTitle-BSEFcEOM.js → CardTitle-GLv7QyIY.js} +1 -1
  93. package/frontend-dist/assets/{CascadingModelSelect-DTwksDPZ.js → CascadingModelSelect-CBhqKFDX.js} +1 -1
  94. package/frontend-dist/assets/{Checkbox-RfsERG07.js → Checkbox-HPVDmEdV.js} +1 -1
  95. package/frontend-dist/assets/{CollapsibleTrigger-Dsjo7QlC.js → CollapsibleTrigger-DhxD9tpM.js} +1 -1
  96. package/frontend-dist/assets/{Collection-rQ4eIYfa.js → Collection-BRt7YxN8.js} +1 -1
  97. package/frontend-dist/assets/{Dashboard-YejfAPiB.js → Dashboard-D1Ys8Zog.js} +1 -1
  98. package/frontend-dist/assets/{DialogTitle-DeFTnmgC.js → DialogTitle-23q73lwF.js} +1 -1
  99. package/frontend-dist/assets/{Input-CENz_g9t.js → Input-CAnKUBBK.js} +1 -1
  100. package/frontend-dist/assets/{Label-BAciBrrd.js → Label-DWdYtVMI.js} +1 -1
  101. package/frontend-dist/assets/{Login-DQkYFq7R.js → Login-w5WFOinP.js} +1 -1
  102. package/frontend-dist/assets/{Logs-Dol8AX7z.js → Logs-C1F1ZmWF.js} +1 -1
  103. package/frontend-dist/assets/{ModelMappings-VEYW1TrW.js → ModelMappings-BzmecWEH.js} +1 -1
  104. package/frontend-dist/assets/{Monitor-C0r9WefB.js → Monitor-DrAZFTKR.js} +1 -1
  105. package/frontend-dist/assets/{PopoverTrigger-Cyqik5SE.js → PopoverTrigger-Bj65uUbv.js} +1 -1
  106. package/frontend-dist/assets/{PopperContent-B7IuAHeq.js → PopperContent-gzzf1XHe.js} +1 -1
  107. package/frontend-dist/assets/Providers-DSgf4mb6.js +1 -0
  108. package/frontend-dist/assets/ProxyEnhancement-Bb1cCP6d.js +5 -0
  109. package/frontend-dist/assets/{RetryRules-F0295m4_.js → RetryRules-BwPfEZtm.js} +1 -1
  110. package/frontend-dist/assets/{RouterKeys-CFbPtUE_.js → RouterKeys-CzTSq1Mx.js} +1 -1
  111. package/frontend-dist/assets/{RovingFocusItem-D291Vjh8.js → RovingFocusItem-CXM_Yfkm.js} +1 -1
  112. package/frontend-dist/assets/{Schedules-DWhF3uod.js → Schedules-DVilCXrC.js} +1 -1
  113. package/frontend-dist/assets/{SelectValue-BWlgUZa3.js → SelectValue-C0-LzGQY.js} +1 -1
  114. package/frontend-dist/assets/{Settings-BnIzEF_k.js → Settings-Bpk53zVX.js} +1 -1
  115. package/frontend-dist/assets/{Setup-BglKyQKq.js → Setup-Dn7EgC49.js} +1 -1
  116. package/frontend-dist/assets/{Switch-DyCR-CPu.js → Switch-BO8Ooae6.js} +1 -1
  117. package/frontend-dist/assets/{TableHeader-DVUlBL35.js → TableHeader-Bded9VTC.js} +1 -1
  118. package/frontend-dist/assets/{TabsTrigger-BU1DY-C8.js → TabsTrigger-BzKMi9AF.js} +1 -1
  119. package/frontend-dist/assets/{Teleport-BQgusr9g.js → Teleport-DizRK5O3.js} +1 -1
  120. package/frontend-dist/assets/{TooltipTrigger-Bv_QoBns.js → TooltipTrigger-EiIy2zn8.js} +1 -1
  121. package/frontend-dist/assets/{UnifiedRequestDialog-f_evI835.js → UnifiedRequestDialog-BABsTaGb.js} +1 -1
  122. package/frontend-dist/assets/{VisuallyHidden-Con10z4F.js → VisuallyHidden-5AozJQza.js} +1 -1
  123. package/frontend-dist/assets/{VisuallyHiddenInput-yrDtxucb.js → VisuallyHiddenInput-DdiZrV2i.js} +1 -1
  124. package/frontend-dist/assets/{alert-dialog-2Db6Z7JQ.js → alert-dialog-DlKUuTPe.js} +1 -1
  125. package/frontend-dist/assets/arrow-down-CxWKmZ2I.js +1 -0
  126. package/frontend-dist/assets/{badge-DEhZfeI0.js → badge-9KJEMa53.js} +1 -1
  127. package/frontend-dist/assets/button-Ul8WlrM5.js +12 -0
  128. package/frontend-dist/assets/check-7ahK--N4.js +1 -0
  129. package/frontend-dist/assets/{copy-CwqZSuIG.js → copy-DzU2pAMG.js} +1 -1
  130. package/frontend-dist/assets/{dialog-CVMKSdPr.js → dialog-B9j-FMrd.js} +1 -1
  131. package/frontend-dist/assets/{file-text-D0K8Hovo.js → file-text-Bj3ZIo-E.js} +1 -1
  132. package/frontend-dist/assets/index-Bz_ZaXNn.css +1 -0
  133. package/frontend-dist/assets/{index-Ct718O93.js → index-MedWZMHB.js} +1 -1
  134. package/frontend-dist/assets/{lib-H3YI7EK4.js → lib-Hhs3NqfD.js} +1 -1
  135. package/frontend-dist/assets/loader-circle-5TJUukEe.js +1 -0
  136. package/frontend-dist/assets/{useClipboard-Cd7k-5Yq.js → useClipboard-BmmsNSGV.js} +1 -1
  137. package/frontend-dist/assets/{useFocusGuards-luoLXnwV.js → useFocusGuards-A-9V2Y-b.js} +1 -1
  138. package/frontend-dist/assets/useFormControl-DEO19lRe.js +1 -0
  139. package/frontend-dist/assets/{useLogRetention-DB4Iu6o_.js → useLogRetention-BfnBFZ5K.js} +1 -1
  140. package/frontend-dist/assets/useNonce-BfwUJ1Ci.js +1 -0
  141. package/frontend-dist/assets/x-Cfopt3QL.js +1 -0
  142. package/frontend-dist/index.html +20 -20
  143. package/package.json +1 -1
  144. package/frontend-dist/assets/Providers-D8Z97edN.js +0 -1
  145. package/frontend-dist/assets/ProxyEnhancement-Kn8r2SN6.js +0 -5
  146. package/frontend-dist/assets/arrow-down-WyouvE7T.js +0 -1
  147. package/frontend-dist/assets/button-Cnkbp_6J.js +0 -12
  148. package/frontend-dist/assets/check-BuqB5Nyb.js +0 -1
  149. package/frontend-dist/assets/index-xjdbFKXJ.css +0 -1
  150. package/frontend-dist/assets/loader-circle-Be82FnVY.js +0 -1
  151. package/frontend-dist/assets/useFormControl-Da4ViGZF.js +0 -1
  152. package/frontend-dist/assets/useNonce-DvAdQ48J.js +0 -1
  153. package/frontend-dist/assets/x-DB22csQl.js +0 -1
@@ -0,0 +1,43 @@
1
+ /** 格式转换方向 */
2
+ export type TransformDirection = "openai-to-anthropic" | "anthropic-to-openai";
3
+ export interface AnthropicTextBlock {
4
+ type: "text";
5
+ text: string;
6
+ }
7
+ export interface AnthropicThinkingBlock {
8
+ type: "thinking";
9
+ thinking: string;
10
+ }
11
+ export interface AnthropicToolUseBlock {
12
+ type: "tool_use";
13
+ id: string;
14
+ name: string;
15
+ input: Record<string, unknown>;
16
+ }
17
+ export interface AnthropicToolResultBlock {
18
+ type: "tool_result";
19
+ tool_use_id: string;
20
+ content: string;
21
+ }
22
+ export interface AnthropicImageBlock {
23
+ type: "image";
24
+ source: {
25
+ type: "url" | "base64";
26
+ url?: string;
27
+ media_type?: string;
28
+ data?: string;
29
+ };
30
+ }
31
+ export type AnthropicContentBlock = AnthropicTextBlock | AnthropicThinkingBlock | AnthropicToolUseBlock | AnthropicToolResultBlock | AnthropicImageBlock;
32
+ export interface OpenAIToolCall {
33
+ id: string;
34
+ type: "function";
35
+ function: {
36
+ name: string;
37
+ arguments: string;
38
+ };
39
+ }
40
+ export interface TransformResult {
41
+ body: Record<string, unknown>;
42
+ upstreamPath: string;
43
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ /** finish_reason (OpenAI) → stop_reason (Anthropic) */
2
+ export declare function mapFinishReasonToStopReason(reason: string): string;
3
+ /** stop_reason (Anthropic) → finish_reason (OpenAI) */
4
+ export declare function mapStopReasonToFinishReason(reason: string): string;
5
+ /** OpenAI usage → Anthropic usage */
6
+ export declare function mapUsageOA2Ant(u: Record<string, unknown> | undefined): Record<string, unknown>;
7
+ /** Anthropic usage → OpenAI usage */
8
+ export declare function mapUsageAnt2OA(u: Record<string, unknown> | undefined): Record<string, unknown>;
@@ -0,0 +1,46 @@
1
+ // ---------- Stop reason / finish_reason 映射 ----------
2
+ const OA_TO_ANT_STOP = {
3
+ stop: "end_turn",
4
+ length: "max_tokens",
5
+ tool_calls: "tool_use",
6
+ };
7
+ const ANT_TO_OA_STOP = {
8
+ end_turn: "stop",
9
+ max_tokens: "length",
10
+ stop_sequence: "stop",
11
+ tool_use: "tool_calls",
12
+ };
13
+ /** finish_reason (OpenAI) → stop_reason (Anthropic) */
14
+ export function mapFinishReasonToStopReason(reason) {
15
+ return OA_TO_ANT_STOP[reason] ?? "end_turn";
16
+ }
17
+ /** stop_reason (Anthropic) → finish_reason (OpenAI) */
18
+ export function mapStopReasonToFinishReason(reason) {
19
+ return ANT_TO_OA_STOP[reason] ?? "stop";
20
+ }
21
+ // ---------- Usage 映射 ----------
22
+ /** OpenAI usage → Anthropic usage */
23
+ export function mapUsageOA2Ant(u) {
24
+ if (!u)
25
+ return { input_tokens: 0, output_tokens: 0, cache_read_input_tokens: 0, cache_creation_input_tokens: 0 };
26
+ const details = u.prompt_tokens_details;
27
+ return {
28
+ input_tokens: u.prompt_tokens ?? 0,
29
+ output_tokens: u.completion_tokens ?? 0,
30
+ cache_read_input_tokens: details?.cached_tokens ?? 0,
31
+ cache_creation_input_tokens: details?.cached_write_tokens ?? 0,
32
+ };
33
+ }
34
+ /** Anthropic usage → OpenAI usage */
35
+ export function mapUsageAnt2OA(u) {
36
+ if (!u)
37
+ return { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 };
38
+ const input = (u.input_tokens ?? 0) + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0);
39
+ const output = u.output_tokens ?? 0;
40
+ return {
41
+ prompt_tokens: input,
42
+ completion_tokens: output,
43
+ total_tokens: input + output,
44
+ prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens ?? 0, cached_write_tokens: u.cache_creation_input_tokens ?? 0 },
45
+ };
46
+ }
@@ -5,4 +5,4 @@ import type { StreamLoopGuard } from "../loop-prevention/stream-loop-guard.js";
5
5
  import { type BuildHeadersFn } from "./http.js";
6
6
  export declare function callStream(backend: {
7
7
  base_url: string;
8
- }, apiKey: string, body: Record<string, unknown>, clientHeaders: RawHeaders, reply: FastifyReply, timeoutMs: number, upstreamPath: string, buildHeaders: BuildHeadersFn, metricsTransform?: SSEMetricsTransform, checkEarlyError?: (bufferedData: string) => boolean, compatResolve?: (result: TransportResult) => void, loopGuard?: StreamLoopGuard): Promise<TransportResult>;
8
+ }, apiKey: string, body: Record<string, unknown>, clientHeaders: RawHeaders, reply: FastifyReply, timeoutMs: number, upstreamPath: string, buildHeaders: BuildHeadersFn, metricsTransform?: SSEMetricsTransform, checkEarlyError?: (bufferedData: string) => boolean, compatResolve?: (result: TransportResult) => void, loopGuard?: StreamLoopGuard, formatTransform?: import("stream").Transform): Promise<TransportResult>;
@@ -24,10 +24,11 @@ class StreamProxy {
24
24
  sseHeaders;
25
25
  passThrough = new PassThrough();
26
26
  pipeEntry;
27
+ formatTransform;
27
28
  // 流式阶段 SSE error 扫描缓冲(跨 chunk 边界匹配)
28
29
  sseScanBuffer = "";
29
- static SSE_SCAN_MAX = 8192;
30
- constructor(statusCode, rawUpstreamHeaders, sentUpstreamHeaders, reply, metricsTransform, checkEarlyError, timeoutMs, loopGuard) {
30
+ static SSE_SCAN_MAX = 8 * 1024; // eslint-disable-line no-magic-numbers -- 8KB scan buffer
31
+ constructor(statusCode, rawUpstreamHeaders, sentUpstreamHeaders, reply, metricsTransform, checkEarlyError, timeoutMs, loopGuard, formatTransform) {
31
32
  this.statusCode = statusCode;
32
33
  this.sentUpstreamHeaders = sentUpstreamHeaders;
33
34
  this.reply = reply;
@@ -35,6 +36,7 @@ class StreamProxy {
35
36
  this.checkEarlyError = checkEarlyError;
36
37
  this.timeoutMs = timeoutMs;
37
38
  this.loopGuard = loopGuard;
39
+ this.formatTransform = formatTransform;
38
40
  this.sseHeaders = filterHeaders(rawUpstreamHeaders);
39
41
  this.sseHeaders["Content-Type"] = "text/event-stream";
40
42
  this.sseHeaders["Cache-Control"] = "no-cache";
@@ -93,10 +95,13 @@ class StreamProxy {
93
95
  else {
94
96
  // stream_abort 且 headers 已发送时,必须 end reply 避免客户端挂起
95
97
  if (kind === "stream_abort" && this.headersSent) {
98
+ // eslint-disable-next-line taste/no-silent-catch -- reply may already be destroyed, warn is sufficient
96
99
  try {
97
100
  this.reply.raw.end();
98
101
  }
99
- catch { /* reply may already be destroyed */ }
102
+ catch {
103
+ console.warn("[stream-proxy] reply.raw.end() failed, likely already destroyed");
104
+ }
100
105
  }
101
106
  this.cleanup();
102
107
  if (this.resolveFn) {
@@ -111,6 +116,8 @@ class StreamProxy {
111
116
  if (this.idleTimer)
112
117
  clearTimeout(this.idleTimer);
113
118
  this.idleTimer = null;
119
+ if (this.formatTransform && !this.formatTransform.destroyed)
120
+ this.formatTransform.destroy();
114
121
  if (!this.passThrough.destroyed)
115
122
  this.passThrough.destroy();
116
123
  if (this.metricsTransform && !this.metricsTransform.destroyed)
@@ -145,7 +152,10 @@ class StreamProxy {
145
152
  this.headersSent = true;
146
153
  this.reply.raw.writeHead(this.statusCode, this.sseHeaders);
147
154
  if (this.metricsTransform) {
148
- this.metricsTransform.pipe(this.passThrough, { end: true });
155
+ this.metricsTransform.pipe(this.formatTransform ?? this.passThrough, { end: true });
156
+ }
157
+ if (this.formatTransform) {
158
+ this.formatTransform.pipe(this.passThrough, { end: true });
149
159
  }
150
160
  // 手动转发而非 pipe,避免 Node.js 在 dest 上自动注册 close/finish handler
151
161
  this.passThrough.on("data", (chunk) => {
@@ -179,8 +189,8 @@ class StreamProxy {
179
189
  if (this.resolved)
180
190
  return;
181
191
  this.resetIdleTimer();
182
- this.captureChunks.push(chunk);
183
192
  if (this.state === "BUFFERING") {
193
+ this.captureChunks.push(chunk);
184
194
  this.bufferChunks.push(chunk);
185
195
  const buf = Buffer.concat(this.bufferChunks);
186
196
  const text = buf.toString("utf-8");
@@ -206,9 +216,8 @@ class StreamProxy {
206
216
  }
207
217
  // 快速启发式:只在扫描窗口出现 SSE error 标记时才执行正则匹配
208
218
  if (this.sseScanBuffer.includes("event: error") || this.sseScanBuffer.includes('"type":"error"')) {
209
- const body = Buffer.concat(this.captureChunks).toString("utf-8");
210
- if (this.checkEarlyError(body)) {
211
- this.terminal("stream_error", { body });
219
+ if (this.checkEarlyError(this.sseScanBuffer)) {
220
+ this.terminal("stream_error", { body: this.sseScanBuffer });
212
221
  // headers 已发送:必须结束 reply 避免 client hang
213
222
  if (this.headersSent) {
214
223
  setImmediate(() => {
@@ -283,7 +292,7 @@ class StreamProxy {
283
292
  }
284
293
  }
285
294
  // ---------- callStream ----------
286
- export function callStream(backend, apiKey, body, clientHeaders, reply, timeoutMs, upstreamPath, buildHeaders, metricsTransform, checkEarlyError, compatResolve, loopGuard) {
295
+ export function callStream(backend, apiKey, body, clientHeaders, reply, timeoutMs, upstreamPath, buildHeaders, metricsTransform, checkEarlyError, compatResolve, loopGuard, formatTransform) {
287
296
  return new Promise((resolve) => {
288
297
  const effectiveResolve = compatResolve ?? resolve;
289
298
  const url = new URL(buildUpstreamUrl(backend.base_url, upstreamPath));
@@ -307,7 +316,7 @@ export function callStream(backend, apiKey, body, clientHeaders, reply, timeoutM
307
316
  });
308
317
  return;
309
318
  }
310
- const proxy = new StreamProxy(statusCode, upstreamRes.headers, upstreamHeaders, reply, metricsTransform, checkEarlyError, timeoutMs, loopGuard);
319
+ const proxy = new StreamProxy(statusCode, upstreamRes.headers, upstreamHeaders, reply, metricsTransform, checkEarlyError, timeoutMs, loopGuard, formatTransform);
311
320
  proxy.bindResolve(effectiveResolve);
312
321
  proxy.registerCloseHandler();
313
322
  // 无 early error checker 时直接开始流式传输
@@ -22,5 +22,8 @@ export interface TransportFnParams {
22
22
  matcher?: RetryRuleMatcher;
23
23
  request: FastifyRequest;
24
24
  streamLoopEnabled: boolean;
25
+ formatTransform?: import("stream").Transform;
26
+ responseTransform?: (body: string) => string;
27
+ injectedHeaders?: Record<string, string>;
25
28
  }
26
29
  export declare function buildTransportFn(p: TransportFnParams): (target: Target) => Promise<TransportResult>;
@@ -32,7 +32,10 @@ function toStreamMetrics(m) {
32
32
  };
33
33
  }
34
34
  export function buildTransportFn(p) {
35
- const buildHeaders = (cliHdrs, key, bytes) => buildUpstreamHeaders(cliHdrs, key, bytes, p.apiType);
35
+ const buildHeaders = (cliHdrs, key, bytes) => {
36
+ const base = buildUpstreamHeaders(cliHdrs, key, bytes, p.apiType);
37
+ return p.injectedHeaders ? { ...base, ...p.injectedHeaders } : base;
38
+ };
36
39
  // _target 未使用 — resilience 层始终传入当前 resolved target;
37
40
  // 跨 target failover 由外层 executeFailoverLoop 的 ProviderSwitchNeeded 处理
38
41
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -50,19 +53,23 @@ export function buildTransportFn(p) {
50
53
  onContentDelta: streamLoopGuard ? (text) => streamLoopGuard.feed(text) : undefined,
51
54
  });
52
55
  const checkEarlyError = p.matcher ? (data) => p.matcher.test(UPSTREAM_SUCCESS, data) : undefined;
53
- const streamResult = await callStream(p.provider, p.apiKey, p.body, p.cliHdrs, p.reply, p.streamTimeoutMs, p.upstreamPath, buildHeaders, metricsTransform, checkEarlyError, undefined, streamLoopGuard);
56
+ const streamResult = await callStream(p.provider, p.apiKey, p.body, p.cliHdrs, p.reply, p.streamTimeoutMs, p.upstreamPath, buildHeaders, metricsTransform, checkEarlyError, undefined, streamLoopGuard, p.formatTransform);
54
57
  const m = (streamResult.kind === "stream_success" || streamResult.kind === "stream_abort")
55
58
  ? streamResult.metrics : undefined;
56
59
  if (m)
57
60
  p.tracker?.update(p.logId, { streamMetrics: toStreamMetrics(m) });
58
61
  return streamResult;
59
62
  }
60
- const result = await callNonStream(p.provider, p.apiKey, p.body, p.cliHdrs, p.upstreamPath, buildHeaders);
63
+ let result = await callNonStream(p.provider, p.apiKey, p.body, p.cliHdrs, p.upstreamPath, buildHeaders);
61
64
  if (result.kind === "success") {
62
65
  const mr = MetricsExtractor.fromNonStreamResponse(p.apiType, result.body);
63
66
  if (mr)
64
67
  p.tracker?.update(p.logId, { streamMetrics: toStreamMetrics(mr) });
65
68
  }
69
+ // Apply format transformation (responseTransform handles both success and error internally)
70
+ if (p.responseTransform && "body" in result && result.body) {
71
+ result = { ...result, body: p.responseTransform(result.body) };
72
+ }
66
73
  if (p.originalModel && result.kind === "success" && result.statusCode === UPSTREAM_SUCCESS) {
67
74
  try {
68
75
  const bodyObj = JSON.parse(result.body);
@@ -72,7 +79,7 @@ export function buildTransportFn(p) {
72
79
  }
73
80
  }
74
81
  catch {
75
- p.request.log.debug("Failed to inject model-info tag into non-JSON response");
82
+ p.request.log.warn("Failed to inject model-info tag into non-JSON response");
76
83
  }
77
84
  }
78
85
  return result;
@@ -1,7 +1,7 @@
1
1
  import { readdirSync, readFileSync, writeFileSync, unlinkSync, rmSync, existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { gzipSync } from "node:zlib";
4
- import { WINDOW_MINUTES, TIME_PAD_WIDTH, ISO_DATE_LENGTH } from "./types.js";
4
+ import { WINDOW_MINUTES, localDateStr } from "./types.js";
5
5
  const SECONDS_PER_MINUTE = 60;
6
6
  const MS_PER_SECOND = 1000;
7
7
  const COMPRESSION_INTERVAL_MS = WINDOW_MINUTES * SECONDS_PER_MINUTE * MS_PER_SECOND;
@@ -23,8 +23,9 @@ export function compressFinishedFiles(baseDir, now) {
23
23
  continue;
24
24
  const fileHour = parseInt(match[1], 10);
25
25
  const fileMinute = parseInt(match[2], 10);
26
- const windowEnd = new Date(`${dayDir.name}T${String(fileHour).padStart(TIME_PAD_WIDTH, "0")}:${String(fileMinute).padStart(TIME_PAD_WIDTH, "0")}:00Z`);
27
- windowEnd.setUTCMinutes(windowEnd.getUTCMinutes() + WINDOW_MINUTES);
26
+ // 使用本地时间构建窗口结束时间(使用 Date 构造函数,避免字符串解析的 V8 依赖)
27
+ const dateParts = dayDir.name.split("-").map(Number);
28
+ const windowEnd = new Date(dateParts[0], dateParts[1] - 1, dateParts[2], fileHour, fileMinute + WINDOW_MINUTES);
28
29
  if (now >= windowEnd) {
29
30
  const filePath = join(dirPath, file);
30
31
  try {
@@ -47,9 +48,7 @@ export function compressFinishedFiles(baseDir, now) {
47
48
  export function cleanExpiredDirs(baseDir, retentionDays, now) {
48
49
  if (!existsSync(baseDir))
49
50
  return 0;
50
- const cutoff = new Date(now);
51
- cutoff.setUTCDate(cutoff.getUTCDate() - retentionDays);
52
- const cutoffStr = cutoff.toISOString().slice(0, ISO_DATE_LENGTH);
51
+ const cutoffStr = localDateStr(new Date(now.getFullYear(), now.getMonth(), now.getDate() - retentionDays));
53
52
  let deleted = 0;
54
53
  const dayDirs = readdirSync(baseDir, { withFileTypes: true })
55
54
  .filter(d => d.isDirectory() && /^\d{4}-\d{2}-\d{2}$/.test(d.name));
@@ -1,7 +1,15 @@
1
1
  import { appendFileSync, mkdirSync, existsSync, readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { gunzipSync } from "node:zlib";
4
- import { WINDOW_MINUTES, TIME_PAD_WIDTH, ISO_DATE_LENGTH } from "./types.js";
4
+ import { WINDOW_MINUTES, TIME_PAD_WIDTH, localDateStr } from "./types.js";
5
+ /** 从日期对象生成本地时区的日志文件路径片段 */
6
+ function localFilePathParts(d) {
7
+ const dateStr = localDateStr(d);
8
+ const hour = d.getHours().toString().padStart(TIME_PAD_WIDTH, "0");
9
+ const minute = Math.floor(d.getMinutes() / WINDOW_MINUTES) * WINDOW_MINUTES;
10
+ const minuteStr = minute.toString().padStart(TIME_PAD_WIDTH, "0");
11
+ return { dateStr, fileName: `${hour}-${minuteStr}.jsonl` };
12
+ }
5
13
  export class LogFileWriter {
6
14
  baseDir;
7
15
  enabled;
@@ -15,12 +23,7 @@ export class LogFileWriter {
15
23
  write(entry) {
16
24
  if (!this.enabled)
17
25
  return;
18
- const date = new Date(entry.created_at);
19
- const dateStr = date.toISOString().slice(0, ISO_DATE_LENGTH);
20
- const hour = date.getUTCHours().toString().padStart(TIME_PAD_WIDTH, "0");
21
- const minute = Math.floor(date.getUTCMinutes() / WINDOW_MINUTES) * WINDOW_MINUTES;
22
- const minuteStr = minute.toString().padStart(TIME_PAD_WIDTH, "0");
23
- const fileName = `${hour}-${minuteStr}.jsonl`;
26
+ const { dateStr, fileName } = localFilePathParts(new Date(entry.created_at));
24
27
  const dayDir = join(this.baseDir, dateStr);
25
28
  if (!existsSync(dayDir)) {
26
29
  mkdirSync(dayDir, { recursive: true });
@@ -43,12 +46,7 @@ export class LogFileWriter {
43
46
  read(id, createdAt) {
44
47
  if (!this.enabled)
45
48
  return null;
46
- const date = new Date(createdAt);
47
- const dateStr = date.toISOString().slice(0, ISO_DATE_LENGTH);
48
- const hour = date.getUTCHours().toString().padStart(TIME_PAD_WIDTH, "0");
49
- const minute = Math.floor(date.getUTCMinutes() / WINDOW_MINUTES) * WINDOW_MINUTES;
50
- const minuteStr = minute.toString().padStart(TIME_PAD_WIDTH, "0");
51
- const fileName = `${hour}-${minuteStr}.jsonl`;
49
+ const { dateStr, fileName } = localFilePathParts(new Date(createdAt));
52
50
  const dayDir = join(this.baseDir, dateStr);
53
51
  // 尝试未压缩文件
54
52
  const filePath = join(dayDir, fileName);
@@ -3,6 +3,8 @@ export declare const WINDOW_MINUTES = 10;
3
3
  export declare const TIME_PAD_WIDTH = 2;
4
4
  /** ISO 日期字符串长度("YYYY-MM-DD") */
5
5
  export declare const ISO_DATE_LENGTH = 10;
6
+ /** 格式化本地日期为 YYYY-MM-DD */
7
+ export declare function localDateStr(d: Date): string;
6
8
  export interface LogFileEntry {
7
9
  id: string;
8
10
  created_at: string;
@@ -3,3 +3,10 @@ export const WINDOW_MINUTES = 10;
3
3
  export const TIME_PAD_WIDTH = 2;
4
4
  /** ISO 日期字符串长度("YYYY-MM-DD") */
5
5
  export const ISO_DATE_LENGTH = 10;
6
+ /** 格式化本地日期为 YYYY-MM-DD */
7
+ export function localDateStr(d) {
8
+ const y = d.getFullYear().toString();
9
+ const m = (d.getMonth() + 1).toString().padStart(TIME_PAD_WIDTH, "0");
10
+ const day = d.getDate().toString().padStart(TIME_PAD_WIDTH, "0");
11
+ return `${y}-${m}-${day}`;
12
+ }
@@ -1 +1 @@
1
- import{G as e,It as t,J as n,Pt as r,lt as i,ot as a,r as o}from"./button-Cnkbp_6J.js";var s=[`data-size`],c=n({__name:`Card`,props:{class:{type:[Boolean,null,String,Object,Array]},size:{default:`default`}},setup(n){let c=n;return(l,u)=>(a(),e(`div`,{"data-slot":`card`,"data-size":n.size,class:t(r(o)(`ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-sm ring-1 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg group/card flex flex-col`,c.class))},[i(l.$slots,`default`)],10,s))}}),l=n({__name:`CardContent`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(n){let s=n;return(n,c)=>(a(),e(`div`,{"data-slot":`card-content`,class:t(r(o)(`px-4 group-data-[size=sm]/card:px-3`,s.class))},[i(n.$slots,`default`)],2))}});export{c as n,l as t};
1
+ import{G as e,It as t,J as n,Pt as r,lt as i,ot as a,r as o}from"./button-Ul8WlrM5.js";var s=[`data-size`],c=n({__name:`Card`,props:{class:{type:[Boolean,null,String,Object,Array]},size:{default:`default`}},setup(n){let c=n;return(l,u)=>(a(),e(`div`,{"data-slot":`card`,"data-size":n.size,class:t(r(o)(`ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-sm ring-1 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg group/card flex flex-col`,c.class))},[i(l.$slots,`default`)],10,s))}}),l=n({__name:`CardContent`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(n){let s=n;return(n,c)=>(a(),e(`div`,{"data-slot":`card-content`,class:t(r(o)(`px-4 group-data-[size=sm]/card:px-3`,s.class))},[i(n.$slots,`default`)],2))}});export{c as n,l as t};
@@ -1 +1 @@
1
- import{G as e,It as t,J as n,Pt as r,lt as i,ot as a,r as o}from"./button-Cnkbp_6J.js";var s=n({__name:`CardHeader`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(n){let s=n;return(n,c)=>(a(),e(`div`,{"data-slot":`card-header`,class:t(r(o)(`gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]`,s.class))},[i(n.$slots,`default`)],2))}}),c=n({__name:`CardTitle`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(n){let s=n;return(n,c)=>(a(),e(`div`,{"data-slot":`card-title`,class:t(r(o)(`text-base leading-snug font-medium group-data-[size=sm]/card:text-sm cn-font-heading`,s.class))},[i(n.$slots,`default`)],2))}});export{s as n,c as t};
1
+ import{G as e,It as t,J as n,Pt as r,lt as i,ot as a,r as o}from"./button-Ul8WlrM5.js";var s=n({__name:`CardHeader`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(n){let s=n;return(n,c)=>(a(),e(`div`,{"data-slot":`card-header`,class:t(r(o)(`gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]`,s.class))},[i(n.$slots,`default`)],2))}}),c=n({__name:`CardTitle`,props:{class:{type:[Boolean,null,String,Object,Array]}},setup(n){let s=n;return(n,c)=>(a(),e(`div`,{"data-slot":`card-title`,class:t(r(o)(`text-base leading-snug font-medium group-data-[size=sm]/card:text-sm cn-font-heading`,s.class))},[i(n.$slots,`default`)],2))}});export{s as n,c as t};
@@ -1 +1 @@
1
- import{Dt as e,G as t,H as n,It as r,J as i,Pt as a,U as o,V as s,W as c,ct as l,ot as u,q as d,yt as f,z as p,zt as m}from"./button-Cnkbp_6J.js";import{b as h}from"./Teleport-BQgusr9g.js";import{a as g}from"./PopperContent-B7IuAHeq.js";import{n as _,r as v,t as y}from"./PopoverTrigger-Cyqik5SE.js";var b=h(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]),x=[`onMouseenter`],S={class:`truncate max-w-40`},C=[`onMouseenter`],w=[`onClick`],T={class:`truncate`},E={key:0,class:`shrink-0 text-xs text-muted-foreground`},D={key:0,class:`px-2 py-1.5 text-sm text-muted-foreground`},O=i({__name:`CascadingSelect`,props:{groups:{},modelValue:{},placeholder:{default:`请选择...`}},emits:[`update:modelValue`],setup(i,{emit:h}){let O=i,k=h,A=e(!1),j=e(null),M=s(()=>{if(!O.modelValue)return``;let e=O.groups.find(e=>e.key===O.modelValue.groupKey);if(!e)return``;let t=e.options.find(e=>e.value===O.modelValue.value);return t?`${e.label} / ${t.label}`:``});function N(e,t){k(`update:modelValue`,{groupKey:e,value:t}),A.value=!1}function P(e){A.value=e,e||(j.value=null)}return(e,s)=>(u(),o(a(v),{open:A.value,"onUpdate:open":P},{default:f(()=>[d(a(y),{"as-child":``},{default:f(()=>[n(`div`,{class:r([`flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background cursor-pointer hover:bg-accent hover:text-accent-foreground`,{"ring-2 ring-ring ring-offset-2":A.value}])},[n(`span`,{class:r([`truncate`,i.modelValue?`text-foreground`:`text-muted-foreground`])},m(M.value||i.placeholder),3),d(a(g),{class:`h-4 w-4 shrink-0 opacity-50`})],2)]),_:1}),d(a(_),{align:`start`,"side-offset":4,class:`z-[200] w-auto min-w-56 overflow-visible p-1`},{default:f(()=>[(u(!0),t(p,null,l(i.groups,e=>(u(),t(`div`,{key:e.key,class:r([`relative flex cursor-pointer items-center justify-between rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground`,{"bg-accent text-accent-foreground z-10":j.value===e.key}]),onMouseenter:t=>j.value=e.key},[n(`span`,S,m(e.label),1),d(a(b),{class:`ml-1 h-4 w-4 shrink-0 opacity-50`}),j.value===e.key&&e.options.length>0?(u(),t(`div`,{key:0,class:`absolute left-full top-0 ml-0.5 min-w-48 rounded-md border bg-popover p-1 text-popover-foreground shadow-md`,onMouseenter:t=>j.value=e.key},[(u(!0),t(p,null,l(e.options,a=>(u(),t(`div`,{key:a.value,class:r([`flex cursor-pointer items-center justify-between gap-2 rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground`,{"bg-accent text-accent-foreground":i.modelValue?.groupKey===e.key&&i.modelValue?.value===a.value}]),onClick:t=>N(e.key,a.value)},[n(`span`,T,m(a.label),1),a.tag?(u(),t(`span`,E,m(a.tag),1)):c(``,!0)],10,w))),128))],40,C)):c(``,!0)],42,x))),128)),i.groups.length===0?(u(),t(`div`,D,` 暂无选项 `)):c(``,!0)]),_:1})]),_:1},8,[`open`]))}}),k=i({__name:`CascadingModelSelect`,props:{providers:{},modelValue:{},placeholder:{default:`选择供应商 / 模型`}},emits:[`update:modelValue`],setup(e,{emit:t}){let n=e,r=t;function i(e){return e>=1e6?`${e/1e6}M`:`${e/1e3}K`}let a=s(()=>n.providers.map(e=>({key:e.provider.id,label:e.provider.name,options:e.models.map(e=>({value:e.name,label:e.name,tag:i(e.contextWindow)}))}))),c=s(()=>n.modelValue?{groupKey:n.modelValue.provider_id,value:n.modelValue.model}:void 0);function l(e){r(`update:modelValue`,{provider_id:e.groupKey,model:e.value})}return(t,n)=>(u(),o(O,{groups:a.value,"model-value":c.value,placeholder:e.placeholder,"onUpdate:modelValue":l},null,8,[`groups`,`model-value`,`placeholder`]))}});export{k as t};
1
+ import{Dt as e,G as t,H as n,It as r,J as i,Pt as a,U as o,V as s,W as c,ct as l,ot as u,q as d,yt as f,z as p,zt as m}from"./button-Ul8WlrM5.js";import{b as h}from"./Teleport-DizRK5O3.js";import{a as g}from"./PopperContent-gzzf1XHe.js";import{n as _,r as v,t as y}from"./PopoverTrigger-Bj65uUbv.js";var b=h(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]),x=[`onMouseenter`],S={class:`truncate max-w-40`},C=[`onMouseenter`],w=[`onClick`],T={class:`truncate`},E={key:0,class:`shrink-0 text-xs text-muted-foreground`},D={key:0,class:`px-2 py-1.5 text-sm text-muted-foreground`},O=i({__name:`CascadingSelect`,props:{groups:{},modelValue:{},placeholder:{default:`请选择...`}},emits:[`update:modelValue`],setup(i,{emit:h}){let O=i,k=h,A=e(!1),j=e(null),M=s(()=>{if(!O.modelValue)return``;let e=O.groups.find(e=>e.key===O.modelValue.groupKey);if(!e)return``;let t=e.options.find(e=>e.value===O.modelValue.value);return t?`${e.label} / ${t.label}`:``});function N(e,t){k(`update:modelValue`,{groupKey:e,value:t}),A.value=!1}function P(e){A.value=e,e||(j.value=null)}return(e,s)=>(u(),o(a(v),{open:A.value,"onUpdate:open":P},{default:f(()=>[d(a(y),{"as-child":``},{default:f(()=>[n(`div`,{class:r([`flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background cursor-pointer hover:bg-accent hover:text-accent-foreground`,{"ring-2 ring-ring ring-offset-2":A.value}])},[n(`span`,{class:r([`truncate`,i.modelValue?`text-foreground`:`text-muted-foreground`])},m(M.value||i.placeholder),3),d(a(g),{class:`h-4 w-4 shrink-0 opacity-50`})],2)]),_:1}),d(a(_),{align:`start`,"side-offset":4,class:`z-[200] w-auto min-w-56 overflow-visible p-1`},{default:f(()=>[(u(!0),t(p,null,l(i.groups,e=>(u(),t(`div`,{key:e.key,class:r([`relative flex cursor-pointer items-center justify-between rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground`,{"bg-accent text-accent-foreground z-10":j.value===e.key}]),onMouseenter:t=>j.value=e.key},[n(`span`,S,m(e.label),1),d(a(b),{class:`ml-1 h-4 w-4 shrink-0 opacity-50`}),j.value===e.key&&e.options.length>0?(u(),t(`div`,{key:0,class:`absolute left-full top-0 ml-0.5 min-w-48 rounded-md border bg-popover p-1 text-popover-foreground shadow-md`,onMouseenter:t=>j.value=e.key},[(u(!0),t(p,null,l(e.options,a=>(u(),t(`div`,{key:a.value,class:r([`flex cursor-pointer items-center justify-between gap-2 rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground`,{"bg-accent text-accent-foreground":i.modelValue?.groupKey===e.key&&i.modelValue?.value===a.value}]),onClick:t=>N(e.key,a.value)},[n(`span`,T,m(a.label),1),a.tag?(u(),t(`span`,E,m(a.tag),1)):c(``,!0)],10,w))),128))],40,C)):c(``,!0)],42,x))),128)),i.groups.length===0?(u(),t(`div`,D,` 暂无选项 `)):c(``,!0)]),_:1})]),_:1},8,[`open`]))}}),k=i({__name:`CascadingModelSelect`,props:{providers:{},modelValue:{},placeholder:{default:`选择供应商 / 模型`}},emits:[`update:modelValue`],setup(e,{emit:t}){let n=e,r=t;function i(e){return e>=1e6?`${e/1e6}M`:`${e/1e3}K`}let a=s(()=>n.providers.map(e=>({key:e.provider.id,label:e.provider.name,options:e.models.map(e=>({value:e.name,label:e.name,tag:i(e.contextWindow)}))}))),c=s(()=>n.modelValue?{groupKey:n.modelValue.provider_id,value:n.modelValue.model}:void 0);function l(e){r(`update:modelValue`,{provider_id:e.groupKey,model:e.value})}return(t,n)=>(u(),o(O,{groups:a.value,"model-value":c.value,placeholder:e.placeholder,"onUpdate:modelValue":l},null,8,[`groups`,`model-value`,`placeholder`]))}});export{k as t};
@@ -1 +1 @@
1
- import{J as e,L as t,Lt as n,Pt as r,R as i,U as a,V as o,W as s,X as c,dt as l,i as u,lt as d,m as f,o as p,ot as m,q as h,r as g,tt as _,x as v,yt as y}from"./button-Cnkbp_6J.js";import{g as b,o as x,u as S,y as C}from"./Teleport-BQgusr9g.js";import{t as w}from"./check-BuqB5Nyb.js";import{t as T}from"./ohash.D__AXeF1-D5e5Wyzx.js";import{t as E}from"./useFormControl-Da4ViGZF.js";import{t as D}from"./VisuallyHiddenInput-yrDtxucb.js";import{t as O}from"./RovingFocusItem-D291Vjh8.js";function k(e,t){return b(e)?!1:Array.isArray(e)?e.some(e=>T(e,t)):T(e,t)}var[A,j]=C(`CheckboxGroupRoot`);function M(e){return e===`indeterminate`}function N(e){return M(e)?`indeterminate`:e?`checked`:`unchecked`}var[P,F]=C(`CheckboxRoot`),I=e({inheritAttrs:!1,__name:`CheckboxRoot`,props:{defaultValue:{type:null,required:!1},modelValue:{type:null,required:!1,default:void 0},disabled:{type:Boolean,required:!1},value:{type:null,required:!1,default:`on`},id:{type:String,required:!1},trueValue:{type:null,required:!1,default:()=>!0},falseValue:{type:null,required:!1,default:()=>!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:`button`},name:{type:String,required:!1},required:{type:Boolean,required:!1}},emits:[`update:modelValue`],setup(e,{emit:n}){let c=e,h=n,{forwardRef:g,currentElement:v}=p(),x=A(null),S=f(c,`modelValue`,h,{defaultValue:c.defaultValue??c.falseValue,passive:c.modelValue===void 0}),C=o(()=>x?.disabled.value||c.disabled),w=o(()=>T(S.value,c.trueValue)),j=o(()=>b(x?.modelValue.value)?S.value===`indeterminate`?`indeterminate`:w.value:k(x.modelValue.value,c.value));function P(){if(b(x?.modelValue.value))S.value===`indeterminate`?S.value=c.trueValue:S.value=w.value?c.falseValue:c.trueValue;else{let e=[...x.modelValue.value||[]];if(k(e,c.value)){let t=e.findIndex(e=>T(e,c.value));e.splice(t,1)}else e.push(c.value);x.modelValue.value=e}}let I=E(v),L=o(()=>c.id&&v.value?document.querySelector(`[for="${c.id}"]`)?.innerText:void 0);return F({disabled:C,state:j}),(e,n)=>(m(),a(l(r(x)?.rovingFocus.value?r(O):r(u)),_(e.$attrs,{id:e.id,ref:r(g),role:`checkbox`,"as-child":e.asChild,as:e.as,type:e.as===`button`?`button`:void 0,"aria-checked":r(M)(j.value)?`mixed`:j.value,"aria-required":e.required,"aria-label":e.$attrs[`aria-label`]||L.value,"data-state":r(N)(j.value),"data-disabled":C.value?``:void 0,disabled:C.value,focusable:r(x)?.rovingFocus.value?!C.value:void 0,onKeydown:t(i(()=>{},[`prevent`]),[`enter`]),onClick:P}),{default:y(()=>[d(e.$slots,`default`,{modelValue:r(S),state:j.value}),r(I)&&e.name&&!r(x)?(m(),a(r(D),{key:0,type:`checkbox`,checked:!!j.value,name:e.name,value:e.value,disabled:C.value,required:e.required},null,8,[`checked`,`name`,`value`,`disabled`,`required`])):s(`v-if`,!0)]),_:3},16,[`id`,`as-child`,`as`,`type`,`aria-checked`,`aria-required`,`aria-label`,`data-state`,`data-disabled`,`disabled`,`focusable`,`onKeydown`]))}}),L=e({__name:`CheckboxIndicator`,props:{forceMount:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:`span`}},setup(e){let{forwardRef:t}=p(),n=P();return(e,i)=>(m(),a(r(x),{present:e.forceMount||r(M)(r(n).state.value)||r(n).state.value===!0},{default:y(()=>[h(r(u),_({ref:r(t),"data-state":r(N)(r(n).state.value),"data-disabled":r(n).disabled.value?``:void 0,style:{pointerEvents:`none`},"as-child":e.asChild,as:e.as},e.$attrs),{default:y(()=>[d(e.$slots,`default`)]),_:3},16,[`data-state`,`data-disabled`,`as-child`,`as`])]),_:3},8,[`present`]))}}),R=e({__name:`Checkbox`,props:{defaultValue:{},modelValue:{},disabled:{type:Boolean},value:{},id:{},trueValue:{},falseValue:{},asChild:{type:Boolean},as:{},name:{},required:{type:Boolean},class:{type:[Boolean,null,String,Object,Array]}},emits:[`update:modelValue`],setup(e,{emit:t}){let i=e,o=t,s=S(v(i,`class`),o);return(e,t)=>(m(),a(r(I),_({"data-slot":`checkbox`},r(s),{class:r(g)(`border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex size-4 items-center justify-center rounded-md border transition-colors group-has-disabled/field:opacity-50 focus-visible:ring-3 aria-invalid:ring-3 peer relative shrink-0 outline-none after:absolute after:-inset-x-3 after:-inset-y-2 disabled:cursor-not-allowed disabled:opacity-50`,i.class)}),{default:y(t=>[h(r(L),{"data-slot":`checkbox-indicator`,class:`[&>svg]:size-3.5 grid place-content-center text-current transition-none`},{default:y(()=>[d(e.$slots,`default`,n(c(t)),()=>[h(r(w))])]),_:2},1024)]),_:3},16,[`class`]))}});export{R as t};
1
+ import{J as e,L as t,Lt as n,Pt as r,R as i,U as a,V as o,W as s,X as c,dt as l,i as u,lt as d,m as f,o as p,ot as m,q as h,r as g,tt as _,x as v,yt as y}from"./button-Ul8WlrM5.js";import{g as b,o as x,u as S,y as C}from"./Teleport-DizRK5O3.js";import{t as w}from"./check-7ahK--N4.js";import{t as T}from"./ohash.D__AXeF1-D5e5Wyzx.js";import{t as E}from"./useFormControl-DEO19lRe.js";import{t as D}from"./VisuallyHiddenInput-DdiZrV2i.js";import{t as O}from"./RovingFocusItem-CXM_Yfkm.js";function k(e,t){return b(e)?!1:Array.isArray(e)?e.some(e=>T(e,t)):T(e,t)}var[A,j]=C(`CheckboxGroupRoot`);function M(e){return e===`indeterminate`}function N(e){return M(e)?`indeterminate`:e?`checked`:`unchecked`}var[P,F]=C(`CheckboxRoot`),I=e({inheritAttrs:!1,__name:`CheckboxRoot`,props:{defaultValue:{type:null,required:!1},modelValue:{type:null,required:!1,default:void 0},disabled:{type:Boolean,required:!1},value:{type:null,required:!1,default:`on`},id:{type:String,required:!1},trueValue:{type:null,required:!1,default:()=>!0},falseValue:{type:null,required:!1,default:()=>!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:`button`},name:{type:String,required:!1},required:{type:Boolean,required:!1}},emits:[`update:modelValue`],setup(e,{emit:n}){let c=e,h=n,{forwardRef:g,currentElement:v}=p(),x=A(null),S=f(c,`modelValue`,h,{defaultValue:c.defaultValue??c.falseValue,passive:c.modelValue===void 0}),C=o(()=>x?.disabled.value||c.disabled),w=o(()=>T(S.value,c.trueValue)),j=o(()=>b(x?.modelValue.value)?S.value===`indeterminate`?`indeterminate`:w.value:k(x.modelValue.value,c.value));function P(){if(b(x?.modelValue.value))S.value===`indeterminate`?S.value=c.trueValue:S.value=w.value?c.falseValue:c.trueValue;else{let e=[...x.modelValue.value||[]];if(k(e,c.value)){let t=e.findIndex(e=>T(e,c.value));e.splice(t,1)}else e.push(c.value);x.modelValue.value=e}}let I=E(v),L=o(()=>c.id&&v.value?document.querySelector(`[for="${c.id}"]`)?.innerText:void 0);return F({disabled:C,state:j}),(e,n)=>(m(),a(l(r(x)?.rovingFocus.value?r(O):r(u)),_(e.$attrs,{id:e.id,ref:r(g),role:`checkbox`,"as-child":e.asChild,as:e.as,type:e.as===`button`?`button`:void 0,"aria-checked":r(M)(j.value)?`mixed`:j.value,"aria-required":e.required,"aria-label":e.$attrs[`aria-label`]||L.value,"data-state":r(N)(j.value),"data-disabled":C.value?``:void 0,disabled:C.value,focusable:r(x)?.rovingFocus.value?!C.value:void 0,onKeydown:t(i(()=>{},[`prevent`]),[`enter`]),onClick:P}),{default:y(()=>[d(e.$slots,`default`,{modelValue:r(S),state:j.value}),r(I)&&e.name&&!r(x)?(m(),a(r(D),{key:0,type:`checkbox`,checked:!!j.value,name:e.name,value:e.value,disabled:C.value,required:e.required},null,8,[`checked`,`name`,`value`,`disabled`,`required`])):s(`v-if`,!0)]),_:3},16,[`id`,`as-child`,`as`,`type`,`aria-checked`,`aria-required`,`aria-label`,`data-state`,`data-disabled`,`disabled`,`focusable`,`onKeydown`]))}}),L=e({__name:`CheckboxIndicator`,props:{forceMount:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:`span`}},setup(e){let{forwardRef:t}=p(),n=P();return(e,i)=>(m(),a(r(x),{present:e.forceMount||r(M)(r(n).state.value)||r(n).state.value===!0},{default:y(()=>[h(r(u),_({ref:r(t),"data-state":r(N)(r(n).state.value),"data-disabled":r(n).disabled.value?``:void 0,style:{pointerEvents:`none`},"as-child":e.asChild,as:e.as},e.$attrs),{default:y(()=>[d(e.$slots,`default`)]),_:3},16,[`data-state`,`data-disabled`,`as-child`,`as`])]),_:3},8,[`present`]))}}),R=e({__name:`Checkbox`,props:{defaultValue:{},modelValue:{},disabled:{type:Boolean},value:{},id:{},trueValue:{},falseValue:{},asChild:{type:Boolean},as:{},name:{},required:{type:Boolean},class:{type:[Boolean,null,String,Object,Array]}},emits:[`update:modelValue`],setup(e,{emit:t}){let i=e,o=t,s=S(v(i,`class`),o);return(e,t)=>(m(),a(r(I),_({"data-slot":`checkbox`},r(s),{class:r(g)(`border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex size-4 items-center justify-center rounded-md border transition-colors group-has-disabled/field:opacity-50 focus-visible:ring-3 aria-invalid:ring-3 peer relative shrink-0 outline-none after:absolute after:-inset-x-3 after:-inset-y-2 disabled:cursor-not-allowed disabled:opacity-50`,i.class)}),{default:y(t=>[h(r(L),{"data-slot":`checkbox-indicator`,class:`[&>svg]:size-3.5 grid place-content-center text-current transition-none`},{default:y(()=>[d(e.$slots,`default`,n(c(t)),()=>[h(r(w))])]),_:2},1024)]),_:3},16,[`class`]))}});export{R as t};
@@ -1 +1 @@
1
- import{Dt as e,J as t,Lt as n,Mt as r,Pt as i,U as a,V as o,W as s,X as c,d as l,gt as u,i as d,it as f,lt as p,m,nt as h,o as g,ot as _,q as v,tt as y,yt as b}from"./button-Cnkbp_6J.js";import{c as x,o as S,u as C,y as w}from"./Teleport-BQgusr9g.js";var[T,E]=w(`CollapsibleRoot`),D=t({__name:`CollapsibleRoot`,props:{defaultOpen:{type:Boolean,required:!1,default:!1},open:{type:Boolean,required:!1,default:void 0},disabled:{type:Boolean,required:!1},unmountOnHide:{type:Boolean,required:!1,default:!0},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},emits:[`update:open`],setup(e,{expose:t,emit:n}){let o=e,s=m(o,`open`,n,{defaultValue:o.defaultOpen,passive:o.open===void 0}),{disabled:c,unmountOnHide:l}=r(o);return E({contentId:``,disabled:c,open:s,unmountOnHide:l,onOpenToggle:()=>{c.value||(s.value=!s.value)}}),t({open:s}),g(),(e,t)=>(_(),a(i(d),{as:e.as,"as-child":o.asChild,"data-state":i(s)?`open`:`closed`,"data-disabled":i(c)?``:void 0},{default:b(()=>[p(e.$slots,`default`,{open:i(s)})]),_:3},8,[`as`,`as-child`,`data-state`,`data-disabled`]))}}),O=t({inheritAttrs:!1,__name:`CollapsibleContent`,props:{forceMount:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},emits:[`contentFound`],setup(t,{emit:n}){let r=t,c=n,m=T();m.contentId||=x(void 0,`reka-collapsible-content`);let C=e(),{forwardRef:w,currentElement:E}=g(),D=e(0),O=e(0),k=o(()=>m.open.value),A=e(k.value),j=e();u(()=>[k.value,C.value?.present],async()=>{await h();let e=E.value;if(!e)return;j.value=j.value||{transitionDuration:e.style.transitionDuration,animationName:e.style.animationName},e.style.transitionDuration=`0s`,e.style.animationName=`none`;let t=e.getBoundingClientRect();O.value=t.height,D.value=t.width,A.value||(e.style.transitionDuration=j.value.transitionDuration,e.style.animationName=j.value.animationName)},{immediate:!0});let M=o(()=>A.value&&m.open.value);return f(()=>{requestAnimationFrame(()=>{A.value=!1})}),l(E,`beforematch`,e=>{requestAnimationFrame(()=>{m.onOpenToggle(),c(`contentFound`)})}),(e,t)=>(_(),a(i(S),{ref_key:`presentRef`,ref:C,present:e.forceMount||i(m).open.value,"force-mount":!0},{default:b(({present:t})=>[v(i(d),y(e.$attrs,{id:i(m).contentId,ref:i(w),"as-child":r.asChild,as:e.as,hidden:t?void 0:i(m).unmountOnHide.value?``:`until-found`,"data-state":M.value?void 0:i(m).open.value?`open`:`closed`,"data-disabled":i(m).disabled?.value?``:void 0,style:{"--reka-collapsible-content-height":`${O.value}px`,"--reka-collapsible-content-width":`${D.value}px`}}),{default:b(()=>[!i(m).unmountOnHide.value||t?p(e.$slots,`default`,{key:0}):s(`v-if`,!0)]),_:2},1040,[`id`,`as-child`,`as`,`hidden`,`data-state`,`data-disabled`,`style`])]),_:3},8,[`present`]))}}),k=t({__name:`CollapsibleTrigger`,props:{asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:`button`}},setup(e){let t=e;g();let n=T();return(e,r)=>(_(),a(i(d),{type:e.as===`button`?`button`:void 0,as:e.as,"as-child":t.asChild,"aria-controls":i(n).contentId,"aria-expanded":i(n).open.value,"data-state":i(n).open.value?`open`:`closed`,"data-disabled":i(n).disabled?.value?``:void 0,disabled:i(n).disabled?.value,onClick:i(n).onOpenToggle},{default:b(()=>[p(e.$slots,`default`)]),_:3},8,[`type`,`as`,`as-child`,`aria-controls`,`aria-expanded`,`data-state`,`data-disabled`,`disabled`,`onClick`]))}}),A=t({__name:`Collapsible`,props:{defaultOpen:{type:Boolean},open:{type:Boolean},disabled:{type:Boolean},unmountOnHide:{type:Boolean},asChild:{type:Boolean},as:{}},emits:[`update:open`],setup(e,{emit:t}){let r=C(e,t);return(e,t)=>(_(),a(i(D),y({"data-slot":`collapsible`},i(r)),{default:b(t=>[p(e.$slots,`default`,n(c(t)))]),_:3},16))}}),j=t({__name:`CollapsibleContent`,props:{forceMount:{type:Boolean},asChild:{type:Boolean},as:{}},setup(e){let t=e;return(e,n)=>(_(),a(i(O),y({"data-slot":`collapsible-content`},t),{default:b(()=>[p(e.$slots,`default`)]),_:3},16))}}),M=t({__name:`CollapsibleTrigger`,props:{asChild:{type:Boolean},as:{}},setup(e){let t=e;return(e,n)=>(_(),a(i(k),y({"data-slot":`collapsible-trigger`},t),{default:b(()=>[p(e.$slots,`default`)]),_:3},16))}});export{j as n,A as r,M as t};
1
+ import{Dt as e,J as t,Lt as n,Mt as r,Pt as i,U as a,V as o,W as s,X as c,d as l,gt as u,i as d,it as f,lt as p,m,nt as h,o as g,ot as _,q as v,tt as y,yt as b}from"./button-Ul8WlrM5.js";import{c as x,o as S,u as C,y as w}from"./Teleport-DizRK5O3.js";var[T,E]=w(`CollapsibleRoot`),D=t({__name:`CollapsibleRoot`,props:{defaultOpen:{type:Boolean,required:!1,default:!1},open:{type:Boolean,required:!1,default:void 0},disabled:{type:Boolean,required:!1},unmountOnHide:{type:Boolean,required:!1,default:!0},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},emits:[`update:open`],setup(e,{expose:t,emit:n}){let o=e,s=m(o,`open`,n,{defaultValue:o.defaultOpen,passive:o.open===void 0}),{disabled:c,unmountOnHide:l}=r(o);return E({contentId:``,disabled:c,open:s,unmountOnHide:l,onOpenToggle:()=>{c.value||(s.value=!s.value)}}),t({open:s}),g(),(e,t)=>(_(),a(i(d),{as:e.as,"as-child":o.asChild,"data-state":i(s)?`open`:`closed`,"data-disabled":i(c)?``:void 0},{default:b(()=>[p(e.$slots,`default`,{open:i(s)})]),_:3},8,[`as`,`as-child`,`data-state`,`data-disabled`]))}}),O=t({inheritAttrs:!1,__name:`CollapsibleContent`,props:{forceMount:{type:Boolean,required:!1},asChild:{type:Boolean,required:!1},as:{type:null,required:!1}},emits:[`contentFound`],setup(t,{emit:n}){let r=t,c=n,m=T();m.contentId||=x(void 0,`reka-collapsible-content`);let C=e(),{forwardRef:w,currentElement:E}=g(),D=e(0),O=e(0),k=o(()=>m.open.value),A=e(k.value),j=e();u(()=>[k.value,C.value?.present],async()=>{await h();let e=E.value;if(!e)return;j.value=j.value||{transitionDuration:e.style.transitionDuration,animationName:e.style.animationName},e.style.transitionDuration=`0s`,e.style.animationName=`none`;let t=e.getBoundingClientRect();O.value=t.height,D.value=t.width,A.value||(e.style.transitionDuration=j.value.transitionDuration,e.style.animationName=j.value.animationName)},{immediate:!0});let M=o(()=>A.value&&m.open.value);return f(()=>{requestAnimationFrame(()=>{A.value=!1})}),l(E,`beforematch`,e=>{requestAnimationFrame(()=>{m.onOpenToggle(),c(`contentFound`)})}),(e,t)=>(_(),a(i(S),{ref_key:`presentRef`,ref:C,present:e.forceMount||i(m).open.value,"force-mount":!0},{default:b(({present:t})=>[v(i(d),y(e.$attrs,{id:i(m).contentId,ref:i(w),"as-child":r.asChild,as:e.as,hidden:t?void 0:i(m).unmountOnHide.value?``:`until-found`,"data-state":M.value?void 0:i(m).open.value?`open`:`closed`,"data-disabled":i(m).disabled?.value?``:void 0,style:{"--reka-collapsible-content-height":`${O.value}px`,"--reka-collapsible-content-width":`${D.value}px`}}),{default:b(()=>[!i(m).unmountOnHide.value||t?p(e.$slots,`default`,{key:0}):s(`v-if`,!0)]),_:2},1040,[`id`,`as-child`,`as`,`hidden`,`data-state`,`data-disabled`,`style`])]),_:3},8,[`present`]))}}),k=t({__name:`CollapsibleTrigger`,props:{asChild:{type:Boolean,required:!1},as:{type:null,required:!1,default:`button`}},setup(e){let t=e;g();let n=T();return(e,r)=>(_(),a(i(d),{type:e.as===`button`?`button`:void 0,as:e.as,"as-child":t.asChild,"aria-controls":i(n).contentId,"aria-expanded":i(n).open.value,"data-state":i(n).open.value?`open`:`closed`,"data-disabled":i(n).disabled?.value?``:void 0,disabled:i(n).disabled?.value,onClick:i(n).onOpenToggle},{default:b(()=>[p(e.$slots,`default`)]),_:3},8,[`type`,`as`,`as-child`,`aria-controls`,`aria-expanded`,`data-state`,`data-disabled`,`disabled`,`onClick`]))}}),A=t({__name:`Collapsible`,props:{defaultOpen:{type:Boolean},open:{type:Boolean},disabled:{type:Boolean},unmountOnHide:{type:Boolean},asChild:{type:Boolean},as:{}},emits:[`update:open`],setup(e,{emit:t}){let r=C(e,t);return(e,t)=>(_(),a(i(D),y({"data-slot":`collapsible`},i(r)),{default:b(t=>[p(e.$slots,`default`,n(c(t)))]),_:3},16))}}),j=t({__name:`CollapsibleContent`,props:{forceMount:{type:Boolean},asChild:{type:Boolean},as:{}},setup(e){let t=e;return(e,n)=>(_(),a(i(O),y({"data-slot":`collapsible-content`},t),{default:b(()=>[p(e.$slots,`default`)]),_:3},16))}}),M=t({__name:`CollapsibleTrigger`,props:{asChild:{type:Boolean},as:{}},setup(e){let t=e;return(e,n)=>(_(),a(i(k),y({"data-slot":`collapsible-trigger`},t),{default:b(()=>[p(e.$slots,`default`)]),_:3},16))}});export{j as n,A as r,M as t};
@@ -1 +1 @@
1
- import{Dt as e,J as t,Q as n,V as r,Z as i,_t as a,a as o,gt as s,st as c,u as l,wt as u}from"./button-Cnkbp_6J.js";import{h as d}from"./Teleport-BQgusr9g.js";function f(t){let n=d({dir:e(`ltr`)});return r(()=>t?.value||n.dir?.value||`ltr`)}function p(){let t=e();return{primitiveElement:t,currentElement:r(()=>[`#text`,`#comment`].includes(t.value?.$el.nodeName)?t.value?.$el.nextElementSibling:l(t))}}var m=`data-reka-collection-item`;function h(l={}){let{key:d=``,isProvider:f=!1}=l,h=`${d}CollectionProvider`,g;if(f){let t=e(new Map);g={collectionRef:e(),itemMap:t},c(h,g)}else g=n(h);let _=(e=!1)=>{let t=g.collectionRef.value;if(!t)return[];let n=Array.from(t.querySelectorAll(`[${m}]`)),r=Array.from(g.itemMap.value.values()).sort((e,t)=>n.indexOf(e.ref)-n.indexOf(t.ref));return e?r:r.filter(e=>e.ref.dataset.disabled!==``)},v=t({name:`CollectionSlot`,inheritAttrs:!1,setup(e,{slots:t,attrs:n}){let{primitiveElement:r,currentElement:a}=p();return s(a,()=>{g.collectionRef.value=a.value}),()=>i(o,{ref:r,...n},t)}}),y=t({name:`CollectionItem`,inheritAttrs:!1,props:{value:{validator:()=>!0}},setup(e,{slots:t,attrs:n}){let{primitiveElement:r,currentElement:s}=p();return a(t=>{if(s.value){let n=u(s.value);g.itemMap.value.set(n,{ref:s.value,value:e.value}),t(()=>g.itemMap.value.delete(n))}}),()=>i(o,{...n,[m]:``,ref:r},t)}});return{getItems:_,reactiveItems:r(()=>Array.from(g.itemMap.value.values())),itemMapSize:r(()=>g.itemMap.value.size),CollectionSlot:v,CollectionItem:y}}export{p as n,f as r,h as t};
1
+ import{Dt as e,J as t,Q as n,V as r,Z as i,_t as a,a as o,gt as s,st as c,u as l,wt as u}from"./button-Ul8WlrM5.js";import{h as d}from"./Teleport-DizRK5O3.js";function f(t){let n=d({dir:e(`ltr`)});return r(()=>t?.value||n.dir?.value||`ltr`)}function p(){let t=e();return{primitiveElement:t,currentElement:r(()=>[`#text`,`#comment`].includes(t.value?.$el.nodeName)?t.value?.$el.nextElementSibling:l(t))}}var m=`data-reka-collection-item`;function h(l={}){let{key:d=``,isProvider:f=!1}=l,h=`${d}CollectionProvider`,g;if(f){let t=e(new Map);g={collectionRef:e(),itemMap:t},c(h,g)}else g=n(h);let _=(e=!1)=>{let t=g.collectionRef.value;if(!t)return[];let n=Array.from(t.querySelectorAll(`[${m}]`)),r=Array.from(g.itemMap.value.values()).sort((e,t)=>n.indexOf(e.ref)-n.indexOf(t.ref));return e?r:r.filter(e=>e.ref.dataset.disabled!==``)},v=t({name:`CollectionSlot`,inheritAttrs:!1,setup(e,{slots:t,attrs:n}){let{primitiveElement:r,currentElement:a}=p();return s(a,()=>{g.collectionRef.value=a.value}),()=>i(o,{ref:r,...n},t)}}),y=t({name:`CollectionItem`,inheritAttrs:!1,props:{value:{validator:()=>!0}},setup(e,{slots:t,attrs:n}){let{primitiveElement:r,currentElement:s}=p();return a(t=>{if(s.value){let n=u(s.value);g.itemMap.value.set(n,{ref:s.value,value:e.value}),t(()=>g.itemMap.value.delete(n))}}),()=>i(o,{...n,[m]:``,ref:r},t)}});return{getItems:_,reactiveItems:r(()=>Array.from(g.itemMap.value.values())),itemMapSize:r(()=>g.itemMap.value.size),CollectionSlot:v,CollectionItem:y}}export{p as n,f as r,h as t};