llm-simple-router 0.6.7 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -0
- package/dist/admin/constants.d.ts +1 -1
- package/dist/admin/constants.js +2 -2
- package/dist/admin/logs.d.ts +2 -0
- package/dist/admin/logs.js +17 -1
- package/dist/admin/providers.d.ts +2 -2
- package/dist/admin/providers.js +29 -16
- package/dist/admin/proxy-enhancement.d.ts +2 -0
- package/dist/admin/proxy-enhancement.js +4 -10
- package/dist/admin/retry-rules.d.ts +2 -2
- package/dist/admin/retry-rules.js +4 -8
- package/dist/admin/routes.d.ts +5 -4
- package/dist/admin/routes.js +7 -7
- package/dist/admin/settings-import-export.d.ts +2 -4
- package/dist/admin/settings-import-export.js +9 -19
- package/dist/admin/settings.d.ts +1 -0
- package/dist/admin/settings.js +29 -1
- package/dist/admin/upgrade.d.ts +1 -0
- package/dist/admin/upgrade.js +37 -4
- package/dist/{constants.d.ts → core/constants.d.ts} +4 -1
- package/dist/{constants.js → core/constants.js} +21 -1
- package/dist/core/container.d.ts +31 -0
- package/dist/core/container.js +41 -0
- package/dist/core/errors.d.ts +26 -0
- package/dist/core/errors.js +42 -0
- package/dist/core/registry.d.ts +43 -0
- package/dist/core/registry.js +3 -0
- package/dist/core/types.d.ts +105 -0
- package/dist/core/types.js +3 -0
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/logs.d.ts +11 -24
- package/dist/db/logs.js +37 -38
- package/dist/db/metrics.js +1 -1
- package/dist/db/migrations/033_add_pipeline_snapshot.sql +1 -0
- package/dist/db/migrations/034_drop_redundant_log_columns.sql +13 -0
- package/dist/db/settings.d.ts +2 -0
- package/dist/db/settings.js +9 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.js +196 -108
- package/dist/metrics/metrics-extractor.d.ts +1 -24
- package/dist/metrics/metrics-extractor.js +1 -1
- package/dist/metrics/sse-metrics-transform.d.ts +1 -1
- package/dist/middleware/admin-auth.js +4 -0
- package/dist/middleware/auth.js +1 -2
- package/dist/monitor/request-tracker.d.ts +3 -4
- package/dist/monitor/request-tracker.js +6 -16
- package/dist/monitor/runtime-collector.js +1 -1
- package/dist/monitor/types.d.ts +8 -0
- package/dist/proxy/adaptive-controller.d.ts +4 -1
- package/dist/proxy/adaptive-controller.js +5 -0
- package/dist/proxy/enhancement/enhancement-handler.d.ts +19 -3
- package/dist/proxy/enhancement/enhancement-handler.js +80 -28
- package/dist/proxy/enhancement/index.d.ts +1 -0
- package/dist/proxy/handler/anthropic.d.ts +7 -0
- package/dist/proxy/{anthropic.js → handler/anthropic.js} +8 -7
- package/dist/proxy/handler/openai.d.ts +7 -0
- package/dist/proxy/{openai.js → handler/openai.js} +10 -9
- package/dist/proxy/handler/proxy-handler-utils.d.ts +9 -0
- package/dist/proxy/handler/proxy-handler-utils.js +63 -0
- package/dist/proxy/handler/proxy-handler.d.ts +13 -0
- package/dist/proxy/{proxy-handler.js → handler/proxy-handler.js} +104 -120
- package/dist/proxy/log-detail-policy.d.ts +12 -0
- package/dist/proxy/log-detail-policy.js +21 -0
- package/dist/proxy/log-helpers.d.ts +8 -0
- package/dist/proxy/log-helpers.js +16 -4
- package/dist/proxy/loop-prevention/tool-loop-guard.d.ts +1 -1
- package/dist/proxy/loop-prevention/tool-loop-guard.js +9 -12
- package/dist/proxy/{orchestrator.d.ts → orchestration/orchestrator.d.ts} +6 -4
- package/dist/proxy/{orchestrator.js → orchestration/orchestrator.js} +2 -1
- package/dist/proxy/{resilience.d.ts → orchestration/resilience.d.ts} +2 -14
- package/dist/proxy/{resilience.js → orchestration/resilience.js} +2 -2
- package/dist/proxy/{retry-rules.d.ts → orchestration/retry-rules.d.ts} +1 -1
- package/dist/proxy/{retry-rules.js → orchestration/retry-rules.js} +1 -1
- package/dist/proxy/{scope.d.ts → orchestration/scope.d.ts} +3 -3
- package/dist/proxy/{semaphore.d.ts → orchestration/semaphore.d.ts} +7 -15
- package/dist/proxy/{semaphore.js → orchestration/semaphore.js} +12 -26
- package/dist/proxy/patch/index.d.ts +8 -2
- package/dist/proxy/patch/index.js +5 -2
- package/dist/proxy/pipeline-snapshot.d.ts +37 -0
- package/dist/proxy/pipeline-snapshot.js +15 -0
- package/dist/proxy/proxy-core.d.ts +1 -1
- package/dist/proxy/proxy-core.js +1 -1
- package/dist/proxy/proxy-logging.d.ts +10 -2
- package/dist/proxy/proxy-logging.js +23 -9
- package/dist/proxy/response-transform.d.ts +7 -0
- package/dist/proxy/response-transform.js +15 -0
- package/dist/proxy/{enhancement-config.js → routing/enhancement-config.js} +1 -1
- package/dist/proxy/{mapping-resolver.d.ts → routing/mapping-resolver.d.ts} +1 -1
- package/dist/proxy/{mapping-resolver.js → routing/mapping-resolver.js} +1 -1
- package/dist/proxy/{model-state.js → routing/model-state.js} +1 -1
- package/dist/proxy/{overflow.d.ts → routing/overflow.d.ts} +1 -1
- package/dist/proxy/{overflow.js → routing/overflow.js} +3 -3
- package/dist/proxy/{usage-window-tracker.js → routing/usage-window-tracker.js} +3 -3
- package/dist/proxy/{transport.d.ts → transport/http.d.ts} +2 -2
- package/dist/proxy/{transport.js → transport/http.js} +3 -3
- package/dist/proxy/{stream-proxy.d.ts → transport/stream.d.ts} +4 -4
- package/dist/proxy/{stream-proxy.js → transport/stream.js} +25 -7
- package/dist/proxy/{transport-fn.d.ts → transport/transport-fn.d.ts} +5 -5
- package/dist/proxy/{transport-fn.js → transport/transport-fn.js} +11 -9
- package/dist/proxy/types.d.ts +3 -64
- package/dist/proxy/types.js +5 -34
- package/dist/storage/log-file-compressor.d.ts +15 -0
- package/dist/storage/log-file-compressor.js +83 -0
- package/dist/storage/log-file-writer.d.ts +21 -0
- package/dist/storage/log-file-writer.js +103 -0
- package/dist/storage/types.d.ts +16 -0
- package/dist/storage/types.js +5 -0
- package/dist/upgrade/deployment.d.ts +13 -0
- package/dist/upgrade/deployment.js +40 -0
- package/frontend-dist/assets/{CardContent-jQcfCC7J.js → CardContent-CxOF1feY.js} +1 -1
- package/frontend-dist/assets/{CardTitle-BrCTvULL.js → CardTitle-BSEFcEOM.js} +1 -1
- package/frontend-dist/assets/{CascadingModelSelect-BFh67j5d.js → CascadingModelSelect-DTwksDPZ.js} +1 -1
- package/frontend-dist/assets/{Checkbox-Bbt7JpdE.js → Checkbox-RfsERG07.js} +1 -1
- package/frontend-dist/assets/{CollapsibleTrigger-DMnEA0qC.js → CollapsibleTrigger-Dsjo7QlC.js} +1 -1
- package/frontend-dist/assets/{Collection-CVk3TPHc.js → Collection-rQ4eIYfa.js} +1 -1
- package/frontend-dist/assets/{Dashboard-Coftbg4B.js → Dashboard-YejfAPiB.js} +1 -1
- package/frontend-dist/assets/{DialogTitle-BbOAZzPQ.js → DialogTitle-DeFTnmgC.js} +1 -1
- package/frontend-dist/assets/{Input-DdHY9q0w.js → Input-CENz_g9t.js} +1 -1
- package/frontend-dist/assets/{Label-DRQv_Dr_.js → Label-BAciBrrd.js} +1 -1
- package/frontend-dist/assets/{Login-SV3ctFnJ.js → Login-DQkYFq7R.js} +1 -1
- package/frontend-dist/assets/{Logs-BG45kX6E.js → Logs-Dol8AX7z.js} +1 -1
- package/frontend-dist/assets/{ModelMappings-DEaBnRU3.js → ModelMappings-VEYW1TrW.js} +1 -1
- package/frontend-dist/assets/{Monitor-ZHOt11n-.js → Monitor-C0r9WefB.js} +1 -1
- package/frontend-dist/assets/{PopoverTrigger-z-Z3EjBk.js → PopoverTrigger-Cyqik5SE.js} +1 -1
- package/frontend-dist/assets/{PopperContent-DPC-6a3n.js → PopperContent-B7IuAHeq.js} +1 -1
- package/frontend-dist/assets/{Providers-DpY6pAcg.js → Providers-D8Z97edN.js} +1 -1
- package/frontend-dist/assets/{ProxyEnhancement-D6KBDXMp.js → ProxyEnhancement-Kn8r2SN6.js} +1 -1
- package/frontend-dist/assets/{RetryRules-DWI7_WLZ.js → RetryRules-F0295m4_.js} +1 -1
- package/frontend-dist/assets/{RouterKeys-CZ1657eX.js → RouterKeys-CFbPtUE_.js} +1 -1
- package/frontend-dist/assets/{RovingFocusItem-BREE2YEV.js → RovingFocusItem-D291Vjh8.js} +1 -1
- package/frontend-dist/assets/{Schedules-BVPsBRPi.js → Schedules-DWhF3uod.js} +1 -1
- package/frontend-dist/assets/{SelectValue-H8hwQwbk.js → SelectValue-BWlgUZa3.js} +1 -1
- package/frontend-dist/assets/Settings-BnIzEF_k.js +6 -0
- package/frontend-dist/assets/{Setup-yOYNKkOG.js → Setup-BglKyQKq.js} +1 -1
- package/frontend-dist/assets/{Switch-CojD3rTH.js → Switch-DyCR-CPu.js} +1 -1
- package/frontend-dist/assets/{TableHeader-awoHTsWN.js → TableHeader-DVUlBL35.js} +1 -1
- package/frontend-dist/assets/{TabsTrigger-DTKSFj85.js → TabsTrigger-BU1DY-C8.js} +1 -1
- package/frontend-dist/assets/{Teleport-DehYAXud.js → Teleport-BQgusr9g.js} +1 -1
- package/frontend-dist/assets/{TooltipTrigger-C2dl_dml.js → TooltipTrigger-Bv_QoBns.js} +1 -1
- package/frontend-dist/assets/{UnifiedRequestDialog-C8A-uSTR.js → UnifiedRequestDialog-f_evI835.js} +2 -2
- package/frontend-dist/assets/{VisuallyHidden-C8oaGi2S.js → VisuallyHidden-Con10z4F.js} +1 -1
- package/frontend-dist/assets/{VisuallyHiddenInput-BMc813t2.js → VisuallyHiddenInput-yrDtxucb.js} +1 -1
- package/frontend-dist/assets/{alert-dialog-C8TZQmU6.js → alert-dialog-2Db6Z7JQ.js} +1 -1
- package/frontend-dist/assets/arrow-down-WyouvE7T.js +1 -0
- package/frontend-dist/assets/{badge-BVh2WpA5.js → badge-DEhZfeI0.js} +1 -1
- package/frontend-dist/assets/button-Cnkbp_6J.js +12 -0
- package/frontend-dist/assets/check-BuqB5Nyb.js +1 -0
- package/frontend-dist/assets/{copy-DTOecxa9.js → copy-CwqZSuIG.js} +1 -1
- package/frontend-dist/assets/{dialog-kA7AUNoc.js → dialog-CVMKSdPr.js} +1 -1
- package/frontend-dist/assets/{file-text-DzZCFO7y.js → file-text-D0K8Hovo.js} +1 -1
- package/frontend-dist/assets/index-Ct718O93.js +1 -0
- package/frontend-dist/assets/{lib-ClDokUbt.js → lib-H3YI7EK4.js} +1 -1
- package/frontend-dist/assets/loader-circle-Be82FnVY.js +1 -0
- package/frontend-dist/assets/{useClipboard-DU1ne-Jw.js → useClipboard-Cd7k-5Yq.js} +1 -1
- package/frontend-dist/assets/{useFocusGuards-Btmdbg_F.js → useFocusGuards-luoLXnwV.js} +1 -1
- package/frontend-dist/assets/useFormControl-Da4ViGZF.js +1 -0
- package/frontend-dist/assets/{useLogRetention--EGNWXig.js → useLogRetention-DB4Iu6o_.js} +1 -1
- package/frontend-dist/assets/useNonce-DvAdQ48J.js +1 -0
- package/frontend-dist/assets/x-DB22csQl.js +1 -0
- package/frontend-dist/index.html +19 -19
- package/package.json +1 -1
- package/dist/proxy/anthropic.d.ts +0 -19
- package/dist/proxy/openai.d.ts +0 -19
- package/dist/proxy/proxy-handler.d.ts +0 -19
- package/dist/proxy/strategy/types.d.ts +0 -21
- package/dist/proxy/strategy/types.js +0 -1
- package/frontend-dist/assets/Settings-DHYaYRgU.js +0 -6
- package/frontend-dist/assets/arrow-down-D-cQXxau.js +0 -1
- package/frontend-dist/assets/button-N59D1BGa.js +0 -12
- package/frontend-dist/assets/check-dDgrw3T3.js +0 -1
- package/frontend-dist/assets/index-DVTeNVaa.js +0 -1
- package/frontend-dist/assets/loader-circle-DVHRL-38.js +0 -1
- package/frontend-dist/assets/useFormControl-C5Kjziuj.js +0 -1
- package/frontend-dist/assets/useNonce-Cp31yRzV.js +0 -1
- package/frontend-dist/assets/x-DMktsI_w.js +0 -1
- /package/dist/{config.d.ts → config/index.d.ts} +0 -0
- /package/dist/{config.js → config/index.js} +0 -0
- /package/dist/proxy/{scope.js → orchestration/scope.js} +0 -0
- /package/dist/proxy/{enhancement-config.d.ts → routing/enhancement-config.d.ts} +0 -0
- /package/dist/proxy/{model-state.d.ts → routing/model-state.d.ts} +0 -0
- /package/dist/proxy/{usage-window-tracker.d.ts → routing/usage-window-tracker.d.ts} +0 -0
package/dist/proxy/types.d.ts
CHANGED
|
@@ -1,64 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export declare function filterHeaders(raw: RawHeaders): Record<string, string>;
|
|
5
|
-
/**
|
|
6
|
-
* 上游调用的传输层结果。
|
|
7
|
-
* discriminated union,按 kind 区分 6 种情况:
|
|
8
|
-
* - success / stream_success:正常完成
|
|
9
|
-
* - stream_error / stream_abort:流式传输中途异常
|
|
10
|
-
* - error:非流式错误响应
|
|
11
|
-
* - throw:未捕获异常
|
|
12
|
-
*/
|
|
13
|
-
export type TransportResult = {
|
|
14
|
-
kind: "success";
|
|
15
|
-
statusCode: number;
|
|
16
|
-
body: string;
|
|
17
|
-
headers: Record<string, string>;
|
|
18
|
-
sentHeaders: Record<string, string>;
|
|
19
|
-
sentBody: string;
|
|
20
|
-
} | {
|
|
21
|
-
kind: "stream_success";
|
|
22
|
-
statusCode: number;
|
|
23
|
-
metrics?: MetricsResult;
|
|
24
|
-
upstreamResponseHeaders?: Record<string, string>;
|
|
25
|
-
sentHeaders: Record<string, string>;
|
|
26
|
-
} | {
|
|
27
|
-
kind: "stream_error";
|
|
28
|
-
statusCode: number;
|
|
29
|
-
body: string;
|
|
30
|
-
headers: Record<string, string>;
|
|
31
|
-
sentHeaders: Record<string, string>;
|
|
32
|
-
/** 响应 headers 是否已发送给客户端。mid-stream 检测到错误时为 true */
|
|
33
|
-
headersSent?: boolean;
|
|
34
|
-
} | {
|
|
35
|
-
kind: "stream_abort";
|
|
36
|
-
statusCode: number;
|
|
37
|
-
metrics?: MetricsResult;
|
|
38
|
-
upstreamResponseHeaders?: Record<string, string>;
|
|
39
|
-
sentHeaders: Record<string, string>;
|
|
40
|
-
} | {
|
|
41
|
-
kind: "error";
|
|
42
|
-
statusCode: number;
|
|
43
|
-
body: string;
|
|
44
|
-
headers: Record<string, string>;
|
|
45
|
-
sentHeaders: Record<string, string>;
|
|
46
|
-
sentBody: string;
|
|
47
|
-
} | {
|
|
48
|
-
kind: "throw";
|
|
49
|
-
error: Error;
|
|
50
|
-
/** 响应 headers 是否已发送给客户端。stream 阶段 throw 时为 true */
|
|
51
|
-
headersSent?: boolean;
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* 跨 provider failover 时由 ResilienceLayer 抛出,
|
|
55
|
-
* orchestrator 捕获后释放当前信号量并获取新 provider 的信号量。
|
|
56
|
-
*/
|
|
57
|
-
export declare class ProviderSwitchNeeded extends Error {
|
|
58
|
-
readonly targetProviderId: string;
|
|
59
|
-
readonly attempts?: import("./resilience.js").ResilienceAttempt[] | undefined;
|
|
60
|
-
readonly lastResult?: TransportResult | undefined;
|
|
61
|
-
constructor(targetProviderId: string, attempts?: import("./resilience.js").ResilienceAttempt[] | undefined, lastResult?: TransportResult | undefined);
|
|
62
|
-
}
|
|
63
|
-
/** 流式传输阶段状态 */
|
|
64
|
-
export type StreamState = "BUFFERING" | "STREAMING" | "COMPLETED" | "EARLY_ERROR" | "ABORTED";
|
|
1
|
+
export { UPSTREAM_SUCCESS, filterHeaders } from "../core/constants.js";
|
|
2
|
+
export type { RawHeaders, TransportResult, StreamState, MetricsResult } from "../core/types.js";
|
|
3
|
+
export { ProviderSwitchNeeded } from "../core/errors.js";
|
package/dist/proxy/types.js
CHANGED
|
@@ -1,34 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"transfer-encoding",
|
|
7
|
-
"connection",
|
|
8
|
-
"keep-alive",
|
|
9
|
-
]);
|
|
10
|
-
export function filterHeaders(raw) {
|
|
11
|
-
const out = {};
|
|
12
|
-
for (const [key, value] of Object.entries(raw)) {
|
|
13
|
-
if (value == null || SKIP_DOWNSTREAM.has(key.toLowerCase()))
|
|
14
|
-
continue;
|
|
15
|
-
out[key] = Array.isArray(value) ? value.join(", ") : value;
|
|
16
|
-
}
|
|
17
|
-
return out;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* 跨 provider failover 时由 ResilienceLayer 抛出,
|
|
21
|
-
* orchestrator 捕获后释放当前信号量并获取新 provider 的信号量。
|
|
22
|
-
*/
|
|
23
|
-
export class ProviderSwitchNeeded extends Error {
|
|
24
|
-
targetProviderId;
|
|
25
|
-
attempts;
|
|
26
|
-
lastResult;
|
|
27
|
-
constructor(targetProviderId, attempts, lastResult) {
|
|
28
|
-
super(`Provider switch needed: ${targetProviderId}`);
|
|
29
|
-
this.targetProviderId = targetProviderId;
|
|
30
|
-
this.attempts = attempts;
|
|
31
|
-
this.lastResult = lastResult;
|
|
32
|
-
this.name = "ProviderSwitchNeeded";
|
|
33
|
-
}
|
|
34
|
-
}
|
|
1
|
+
// src/proxy/types.ts — proxy 内部类型 + core 公共类型 re-export
|
|
2
|
+
// Re-export 公共类型(已被 core 取代)
|
|
3
|
+
export { UPSTREAM_SUCCESS, filterHeaders } from "../core/constants.js";
|
|
4
|
+
// ProviderSwitchNeeded 已移至 core/errors.ts
|
|
5
|
+
export { ProviderSwitchNeeded } from "../core/errors.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** 将已结束窗口的 .jsonl 文件压缩为 .jsonl.gz */
|
|
2
|
+
export declare function compressFinishedFiles(baseDir: string, now: Date): number;
|
|
3
|
+
/** 删除超过保留天数的日期目录 */
|
|
4
|
+
export declare function cleanExpiredDirs(baseDir: string, retentionDays: number, now: Date): number;
|
|
5
|
+
export interface LogFileMaintenanceHandle {
|
|
6
|
+
stop: () => void;
|
|
7
|
+
}
|
|
8
|
+
/** 启动定时维护任务:每 10 分钟执行压缩 + 清理 */
|
|
9
|
+
export declare function scheduleLogFileMaintenance(baseDir: string, options: {
|
|
10
|
+
retentionDays: number;
|
|
11
|
+
log: {
|
|
12
|
+
info: (msg: string) => void;
|
|
13
|
+
};
|
|
14
|
+
intervalMs?: number;
|
|
15
|
+
}): LogFileMaintenanceHandle;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readdirSync, readFileSync, writeFileSync, unlinkSync, rmSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { gzipSync } from "node:zlib";
|
|
4
|
+
import { WINDOW_MINUTES, TIME_PAD_WIDTH, ISO_DATE_LENGTH } from "./types.js";
|
|
5
|
+
const SECONDS_PER_MINUTE = 60;
|
|
6
|
+
const MS_PER_SECOND = 1000;
|
|
7
|
+
const COMPRESSION_INTERVAL_MS = WINDOW_MINUTES * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
8
|
+
/** 将已结束窗口的 .jsonl 文件压缩为 .jsonl.gz */
|
|
9
|
+
export function compressFinishedFiles(baseDir, now) {
|
|
10
|
+
let compressed = 0;
|
|
11
|
+
if (!existsSync(baseDir))
|
|
12
|
+
return 0;
|
|
13
|
+
const dayDirs = readdirSync(baseDir, { withFileTypes: true })
|
|
14
|
+
.filter(d => d.isDirectory() && /^\d{4}-\d{2}-\d{2}$/.test(d.name));
|
|
15
|
+
for (const dayDir of dayDirs) {
|
|
16
|
+
const dirPath = join(baseDir, dayDir.name);
|
|
17
|
+
const files = readdirSync(dirPath);
|
|
18
|
+
for (const file of files) {
|
|
19
|
+
if (!file.endsWith(".jsonl"))
|
|
20
|
+
continue;
|
|
21
|
+
const match = file.match(/^(\d{2})-(\d{2})\.jsonl$/);
|
|
22
|
+
if (!match)
|
|
23
|
+
continue;
|
|
24
|
+
const fileHour = parseInt(match[1], 10);
|
|
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);
|
|
28
|
+
if (now >= windowEnd) {
|
|
29
|
+
const filePath = join(dirPath, file);
|
|
30
|
+
try {
|
|
31
|
+
const content = readFileSync(filePath);
|
|
32
|
+
const gzipped = gzipSync(content);
|
|
33
|
+
writeFileSync(filePath + ".gz", gzipped);
|
|
34
|
+
unlinkSync(filePath);
|
|
35
|
+
compressed++;
|
|
36
|
+
// eslint-disable-next-line taste/no-silent-catch
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// 文件可能正在被写入,跳过
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return compressed;
|
|
45
|
+
}
|
|
46
|
+
/** 删除超过保留天数的日期目录 */
|
|
47
|
+
export function cleanExpiredDirs(baseDir, retentionDays, now) {
|
|
48
|
+
if (!existsSync(baseDir))
|
|
49
|
+
return 0;
|
|
50
|
+
const cutoff = new Date(now);
|
|
51
|
+
cutoff.setUTCDate(cutoff.getUTCDate() - retentionDays);
|
|
52
|
+
const cutoffStr = cutoff.toISOString().slice(0, ISO_DATE_LENGTH);
|
|
53
|
+
let deleted = 0;
|
|
54
|
+
const dayDirs = readdirSync(baseDir, { withFileTypes: true })
|
|
55
|
+
.filter(d => d.isDirectory() && /^\d{4}-\d{2}-\d{2}$/.test(d.name));
|
|
56
|
+
for (const dayDir of dayDirs) {
|
|
57
|
+
if (dayDir.name <= cutoffStr) {
|
|
58
|
+
rmSync(join(baseDir, dayDir.name), { recursive: true, force: true });
|
|
59
|
+
deleted++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return deleted;
|
|
63
|
+
}
|
|
64
|
+
/** 启动定时维护任务:每 10 分钟执行压缩 + 清理 */
|
|
65
|
+
export function scheduleLogFileMaintenance(baseDir, options) {
|
|
66
|
+
const intervalMs = options.intervalMs ?? COMPRESSION_INTERVAL_MS;
|
|
67
|
+
const doMaintenance = () => {
|
|
68
|
+
const now = new Date();
|
|
69
|
+
const compressed = compressFinishedFiles(baseDir, now);
|
|
70
|
+
const deleted = cleanExpiredDirs(baseDir, options.retentionDays, now);
|
|
71
|
+
if (compressed > 0 || deleted > 0) {
|
|
72
|
+
options.log.info(`Log file maintenance: compressed ${compressed} files, deleted ${deleted} dirs`);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const timer = setInterval(doMaintenance, intervalMs);
|
|
76
|
+
const initialTimer = setTimeout(doMaintenance, 0);
|
|
77
|
+
return {
|
|
78
|
+
stop: () => {
|
|
79
|
+
clearInterval(timer);
|
|
80
|
+
clearTimeout(initialTimer);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type LogFileEntry } from "./types.js";
|
|
2
|
+
export interface LogFileWriterOptions {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare class LogFileWriter {
|
|
6
|
+
private readonly baseDir;
|
|
7
|
+
private readonly enabled;
|
|
8
|
+
constructor(baseDir: string, options?: LogFileWriterOptions);
|
|
9
|
+
get isEnabled(): boolean;
|
|
10
|
+
write(entry: LogFileEntry): void;
|
|
11
|
+
/**
|
|
12
|
+
* 根据 id 和 created_at 从 JSONL 文件回读完整记录。
|
|
13
|
+
* 先尝试未压缩的 .jsonl,再尝试 .jsonl.gz。
|
|
14
|
+
* 返回 null 表示找不到。
|
|
15
|
+
*/
|
|
16
|
+
read(id: string, createdAt: string): LogFileEntry | null;
|
|
17
|
+
private findByIdInFile;
|
|
18
|
+
private findByIdInGzFile;
|
|
19
|
+
private parseAndFind;
|
|
20
|
+
stop(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync, existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { gunzipSync } from "node:zlib";
|
|
4
|
+
import { WINDOW_MINUTES, TIME_PAD_WIDTH, ISO_DATE_LENGTH } from "./types.js";
|
|
5
|
+
export class LogFileWriter {
|
|
6
|
+
baseDir;
|
|
7
|
+
enabled;
|
|
8
|
+
constructor(baseDir, options) {
|
|
9
|
+
this.baseDir = baseDir;
|
|
10
|
+
this.enabled = options?.enabled ?? true;
|
|
11
|
+
}
|
|
12
|
+
get isEnabled() {
|
|
13
|
+
return this.enabled;
|
|
14
|
+
}
|
|
15
|
+
write(entry) {
|
|
16
|
+
if (!this.enabled)
|
|
17
|
+
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`;
|
|
24
|
+
const dayDir = join(this.baseDir, dateStr);
|
|
25
|
+
if (!existsSync(dayDir)) {
|
|
26
|
+
mkdirSync(dayDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
const filePath = join(dayDir, fileName);
|
|
29
|
+
const line = JSON.stringify(entry) + "\n";
|
|
30
|
+
try {
|
|
31
|
+
appendFileSync(filePath, line, "utf-8");
|
|
32
|
+
// eslint-disable-next-line taste/no-silent-catch
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// 文件写入是辅助通道,失败不影响主流程
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 根据 id 和 created_at 从 JSONL 文件回读完整记录。
|
|
40
|
+
* 先尝试未压缩的 .jsonl,再尝试 .jsonl.gz。
|
|
41
|
+
* 返回 null 表示找不到。
|
|
42
|
+
*/
|
|
43
|
+
read(id, createdAt) {
|
|
44
|
+
if (!this.enabled)
|
|
45
|
+
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`;
|
|
52
|
+
const dayDir = join(this.baseDir, dateStr);
|
|
53
|
+
// 尝试未压缩文件
|
|
54
|
+
const filePath = join(dayDir, fileName);
|
|
55
|
+
if (existsSync(filePath)) {
|
|
56
|
+
return this.findByIdInFile(filePath, id);
|
|
57
|
+
}
|
|
58
|
+
// 尝试压缩文件
|
|
59
|
+
const gzPath = filePath + ".gz";
|
|
60
|
+
if (existsSync(gzPath)) {
|
|
61
|
+
return this.findByIdInGzFile(gzPath, id);
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
findByIdInFile(filePath, id) {
|
|
66
|
+
try {
|
|
67
|
+
const content = readFileSync(filePath, "utf-8");
|
|
68
|
+
return this.parseAndFind(content, id);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
findByIdInGzFile(gzPath, id) {
|
|
75
|
+
try {
|
|
76
|
+
const compressed = readFileSync(gzPath);
|
|
77
|
+
const content = gunzipSync(compressed).toString("utf-8");
|
|
78
|
+
return this.parseAndFind(content, id);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
parseAndFind(content, id) {
|
|
85
|
+
for (const line of content.split("\n")) {
|
|
86
|
+
if (!line.trim())
|
|
87
|
+
continue;
|
|
88
|
+
try {
|
|
89
|
+
const entry = JSON.parse(line);
|
|
90
|
+
if (entry.id === id)
|
|
91
|
+
return entry;
|
|
92
|
+
// eslint-disable-next-line taste/no-silent-catch
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// 跳过损坏行
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
stop() {
|
|
101
|
+
// 当前实现无需清理
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** JSONL 文件按每 10 分钟一个窗口切分 */
|
|
2
|
+
export declare const WINDOW_MINUTES = 10;
|
|
3
|
+
export declare const TIME_PAD_WIDTH = 2;
|
|
4
|
+
/** ISO 日期字符串长度("YYYY-MM-DD") */
|
|
5
|
+
export declare const ISO_DATE_LENGTH = 10;
|
|
6
|
+
export interface LogFileEntry {
|
|
7
|
+
id: string;
|
|
8
|
+
created_at: string;
|
|
9
|
+
api_type: string;
|
|
10
|
+
status_code: number | null;
|
|
11
|
+
client_request: string | null;
|
|
12
|
+
upstream_request: string | null;
|
|
13
|
+
upstream_response: string | null;
|
|
14
|
+
stream_text_content: string | null;
|
|
15
|
+
pipeline_snapshot: string | null;
|
|
16
|
+
}
|
|
@@ -1,2 +1,15 @@
|
|
|
1
1
|
export type DeploymentType = 'npm' | 'docker' | 'unknown';
|
|
2
|
+
export type RestartMethod = 'process_manager' | 'self_spawn';
|
|
2
3
|
export declare function detectDeployment(): DeploymentType;
|
|
4
|
+
/**
|
|
5
|
+
* 检测是否有外部进程管理器(PM2 / systemd / Docker)。
|
|
6
|
+
* 有管理器时 process.exit(0) 后会自动重启;没有时需要自 spawn。
|
|
7
|
+
*/
|
|
8
|
+
export declare function hasProcessManager(): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* 解析重启时应该使用的可执行文件路径。
|
|
11
|
+
* npx 启动时 process.argv[1] 指向 npm cache 中的旧路径,
|
|
12
|
+
* 升级后全局 bin 已指向新版本,需要重新解析。
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveRestartBinPath(): string;
|
|
15
|
+
export declare function getRestartMethod(): RestartMethod;
|
|
@@ -18,3 +18,43 @@ export function detectDeployment() {
|
|
|
18
18
|
return 'unknown';
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* 检测是否有外部进程管理器(PM2 / systemd / Docker)。
|
|
23
|
+
* 有管理器时 process.exit(0) 后会自动重启;没有时需要自 spawn。
|
|
24
|
+
*/
|
|
25
|
+
export function hasProcessManager() {
|
|
26
|
+
// Docker — restart policy
|
|
27
|
+
if (existsSync('/.dockerenv') || existsSync('/run/.containerenv'))
|
|
28
|
+
return true;
|
|
29
|
+
// PM2 — 注入 pm_id 环境变量
|
|
30
|
+
if (process.env.pm_id !== undefined)
|
|
31
|
+
return true;
|
|
32
|
+
// systemd — 注入 INVOCATION_ID 环境变量
|
|
33
|
+
if (process.env.INVOCATION_ID !== undefined)
|
|
34
|
+
return true;
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 解析重启时应该使用的可执行文件路径。
|
|
39
|
+
* npx 启动时 process.argv[1] 指向 npm cache 中的旧路径,
|
|
40
|
+
* 升级后全局 bin 已指向新版本,需要重新解析。
|
|
41
|
+
*/
|
|
42
|
+
export function resolveRestartBinPath() {
|
|
43
|
+
try {
|
|
44
|
+
const bin = execSync('which llm-simple-router', {
|
|
45
|
+
encoding: 'utf-8',
|
|
46
|
+
timeout: 3000,
|
|
47
|
+
}).trim();
|
|
48
|
+
if (bin)
|
|
49
|
+
return bin;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// which 命令不可用或未安装全局包,fallback 到当前进程入口
|
|
53
|
+
return process.argv[1] ?? 'node';
|
|
54
|
+
}
|
|
55
|
+
// fallback: 当前进程入口(PM2/systemd 场景下通常是正确的)
|
|
56
|
+
return process.argv[1];
|
|
57
|
+
}
|
|
58
|
+
export function getRestartMethod() {
|
|
59
|
+
return hasProcessManager() ? 'process_manager' : 'self_spawn';
|
|
60
|
+
}
|
|
@@ -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-
|
|
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 +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-
|
|
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};
|
package/frontend-dist/assets/{CascadingModelSelect-BFh67j5d.js → CascadingModelSelect-DTwksDPZ.js}
RENAMED
|
@@ -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-
|
|
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 +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-
|
|
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};
|
package/frontend-dist/assets/{CollapsibleTrigger-DMnEA0qC.js → CollapsibleTrigger-Dsjo7QlC.js}
RENAMED
|
@@ -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-
|
|
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 +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-
|
|
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};
|