ccusage 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +68 -0
  2. package/dist/arktype-C-GObzDh-Dj1DVoqC.js +5 -0
  3. package/dist/{calculate-cost-DMC4FhU4.js → calculate-cost-2IwHSzmi.js} +1 -1
  4. package/dist/calculate-cost.d.ts +5 -2
  5. package/dist/calculate-cost.js +1 -1
  6. package/dist/core-BgFXUe_h.js +693 -0
  7. package/dist/data-loader-LMCrJ-lW.d.ts +56 -0
  8. package/dist/{data-loader-BBdPk24U.js → data-loader-r5ZcMQy7.js} +122 -1608
  9. package/dist/data-loader.d.ts +4 -1
  10. package/dist/data-loader.js +4 -1
  11. package/dist/debug-BVxGf4UL.js +142 -0
  12. package/dist/debug.d.ts +39 -0
  13. package/dist/debug.js +7 -0
  14. package/dist/dist-C_i5I27w.js +469 -0
  15. package/dist/dist-FwNhpFrW.js +491 -0
  16. package/dist/effect-WSjEuzC9-BsxP11fz.js +10 -0
  17. package/dist/esm-vjyZjnpZ.js +1090 -0
  18. package/dist/{data-loader-D1LHcGfa.d.ts → index-BurjgCfW.d.ts} +323 -76
  19. package/dist/index-CISmcbXk-BotItq1T.js +23 -0
  20. package/dist/index.js +72 -265
  21. package/dist/logger-Cu4Ir1a5.js +977 -0
  22. package/dist/logger.d.ts +10 -0
  23. package/dist/logger.js +3 -0
  24. package/dist/mcp-DAzj5Pua.js +37580 -0
  25. package/dist/mcp.d.ts +15 -0
  26. package/dist/mcp.js +10 -0
  27. package/dist/pricing-fetcher-B5yPtoTB.js +60 -0
  28. package/dist/pricing-fetcher-DygIroMj.d.ts +21 -0
  29. package/dist/pricing-fetcher.d.ts +3 -0
  30. package/dist/pricing-fetcher.js +5 -0
  31. package/dist/shared-args-DN3jRldX.js +61 -0
  32. package/dist/shared-args.d.ts +94 -0
  33. package/dist/shared-args.js +8 -0
  34. package/dist/sury-DmrZ3_Oj-DhGOjCNc.js +10 -0
  35. package/dist/types-B3ib19os.d.ts +79 -0
  36. package/dist/types-CFnCBr2I.js +3586 -0
  37. package/dist/types-DFrbJmnT.js +41 -0
  38. package/dist/types.d.ts +3 -0
  39. package/dist/types.js +4 -0
  40. package/dist/utils-C7kg8MXN.js +10 -0
  41. package/dist/utils.d.ts +5 -0
  42. package/dist/utils.js +3 -0
  43. package/dist/valibot-CQk-M5rL-Cq5E7F3g.js +10 -0
  44. package/dist/zod-Db63SLXj-BWdcigdx.js +30 -0
  45. package/package.json +8 -1
  46. /package/dist/{prompt-_w55ddDU.js → prompt-IToGuko2.js} +0 -0
@@ -1,2 +1,5 @@
1
- import { DailyUsage, DailyUsageSchema$1 as DailyUsageSchema, DateFilter, LoadOptions, SessionUsage, SessionUsageSchema$1 as SessionUsageSchema, UsageData, UsageDataSchema$1 as UsageDataSchema, calculateCostForEntry$1 as calculateCostForEntry, formatDate$1 as formatDate, getDefaultClaudePath$1 as getDefaultClaudePath, loadSessionData$1 as loadSessionData, loadUsageData$1 as loadUsageData } from "./data-loader-D1LHcGfa.js";
1
+ import "./index-BurjgCfW.js";
2
+ import "./pricing-fetcher-DygIroMj.js";
3
+ import "./types-B3ib19os.js";
4
+ import { DailyUsage, DailyUsageSchema$1 as DailyUsageSchema, DateFilter, LoadOptions, SessionUsage, SessionUsageSchema$1 as SessionUsageSchema, UsageData, UsageDataSchema$1 as UsageDataSchema, calculateCostForEntry$1 as calculateCostForEntry, formatDate$1 as formatDate, getDefaultClaudePath$1 as getDefaultClaudePath, loadSessionData$1 as loadSessionData, loadUsageData$1 as loadUsageData } from "./data-loader-LMCrJ-lW.js";
2
5
  export { DailyUsage, DailyUsageSchema, DateFilter, LoadOptions, SessionUsage, SessionUsageSchema, UsageData, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadSessionData, loadUsageData };
@@ -1,3 +1,6 @@
1
- import { DailyUsageSchema, SessionUsageSchema, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadSessionData, loadUsageData } from "./data-loader-BBdPk24U.js";
1
+ import { DailyUsageSchema, SessionUsageSchema, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadSessionData, loadUsageData } from "./data-loader-r5ZcMQy7.js";
2
+ import "./dist-FwNhpFrW.js";
3
+ import "./logger-Cu4Ir1a5.js";
4
+ import "./pricing-fetcher-B5yPtoTB.js";
2
5
 
3
6
  export { DailyUsageSchema, SessionUsageSchema, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadSessionData, loadUsageData };
@@ -0,0 +1,142 @@
1
+ import { UsageDataSchema, glob } from "./data-loader-r5ZcMQy7.js";
2
+ import { safeParse } from "./dist-FwNhpFrW.js";
3
+ import { logger } from "./logger-Cu4Ir1a5.js";
4
+ import { calculateCostFromTokens, fetchModelPricing, getModelPricing } from "./pricing-fetcher-B5yPtoTB.js";
5
+ import { readFile } from "node:fs/promises";
6
+ import { homedir } from "node:os";
7
+ import path from "node:path";
8
+
9
+ //#region src/debug.ts
10
+ const MATCH_THRESHOLD_PERCENT = .1;
11
+ async function detectMismatches(claudePath) {
12
+ const claudeDir = claudePath || path.join(homedir(), ".claude", "projects");
13
+ const files = await glob(["**/*.jsonl"], {
14
+ cwd: claudeDir,
15
+ absolute: true
16
+ });
17
+ const modelPricing = await fetchModelPricing();
18
+ const stats = {
19
+ totalEntries: 0,
20
+ entriesWithBoth: 0,
21
+ matches: 0,
22
+ mismatches: 0,
23
+ discrepancies: [],
24
+ modelStats: new Map(),
25
+ versionStats: new Map()
26
+ };
27
+ for (const file of files) {
28
+ const content = await readFile(file, "utf-8");
29
+ const lines = content.trim().split("\n").filter((line) => line.length > 0);
30
+ for (const line of lines) try {
31
+ const parsed = JSON.parse(line);
32
+ const result = safeParse(UsageDataSchema, parsed);
33
+ if (!result.success) continue;
34
+ const data = result.output;
35
+ stats.totalEntries++;
36
+ if (data.costUSD !== void 0 && data.message.model && data.message.model !== "<synthetic>") {
37
+ stats.entriesWithBoth++;
38
+ const model = data.message.model;
39
+ const pricing = getModelPricing(model, modelPricing);
40
+ if (pricing) {
41
+ const calculatedCost = calculateCostFromTokens(data.message.usage, pricing);
42
+ const difference = Math.abs(data.costUSD - calculatedCost);
43
+ const percentDiff = data.costUSD > 0 ? difference / data.costUSD * 100 : 0;
44
+ const modelStat = stats.modelStats.get(model) || {
45
+ total: 0,
46
+ matches: 0,
47
+ mismatches: 0,
48
+ avgPercentDiff: 0
49
+ };
50
+ modelStat.total++;
51
+ if (data.version) {
52
+ const versionStat = stats.versionStats.get(data.version) || {
53
+ total: 0,
54
+ matches: 0,
55
+ mismatches: 0,
56
+ avgPercentDiff: 0
57
+ };
58
+ versionStat.total++;
59
+ if (percentDiff < MATCH_THRESHOLD_PERCENT) versionStat.matches++;
60
+ else versionStat.mismatches++;
61
+ versionStat.avgPercentDiff = (versionStat.avgPercentDiff * (versionStat.total - 1) + percentDiff) / versionStat.total;
62
+ stats.versionStats.set(data.version, versionStat);
63
+ }
64
+ if (percentDiff < .1) {
65
+ stats.matches++;
66
+ modelStat.matches++;
67
+ } else {
68
+ stats.mismatches++;
69
+ modelStat.mismatches++;
70
+ stats.discrepancies.push({
71
+ file: path.basename(file),
72
+ timestamp: data.timestamp,
73
+ model,
74
+ originalCost: data.costUSD,
75
+ calculatedCost,
76
+ difference,
77
+ percentDiff,
78
+ usage: data.message.usage
79
+ });
80
+ }
81
+ modelStat.avgPercentDiff = (modelStat.avgPercentDiff * (modelStat.total - 1) + percentDiff) / modelStat.total;
82
+ stats.modelStats.set(model, modelStat);
83
+ }
84
+ }
85
+ } catch (e) {}
86
+ }
87
+ return stats;
88
+ }
89
+ function printMismatchReport(stats, sampleCount = 5) {
90
+ if (stats.entriesWithBoth === 0) {
91
+ logger.info("No pricing data found to analyze.");
92
+ return;
93
+ }
94
+ const matchRate = stats.matches / stats.entriesWithBoth * 100;
95
+ logger.info("\n=== Pricing Mismatch Debug Report ===");
96
+ logger.info(`Total entries processed: ${stats.totalEntries.toLocaleString()}`);
97
+ logger.info(`Entries with both costUSD and model: ${stats.entriesWithBoth.toLocaleString()}`);
98
+ logger.info(`Matches (within 0.1%): ${stats.matches.toLocaleString()}`);
99
+ logger.info(`Mismatches: ${stats.mismatches.toLocaleString()}`);
100
+ logger.info(`Match rate: ${matchRate.toFixed(2)}%`);
101
+ if (stats.mismatches > 0 && stats.modelStats.size > 0) {
102
+ logger.info("\n=== Model Statistics ===");
103
+ const sortedModels = Array.from(stats.modelStats.entries()).sort((a, b) => b[1].mismatches - a[1].mismatches);
104
+ for (const [model, modelStat] of sortedModels) if (modelStat.mismatches > 0) {
105
+ const modelMatchRate = modelStat.matches / modelStat.total * 100;
106
+ logger.info(`${model}:`);
107
+ logger.info(` Total entries: ${modelStat.total.toLocaleString()}`);
108
+ logger.info(` Matches: ${modelStat.matches.toLocaleString()} (${modelMatchRate.toFixed(1)}%)`);
109
+ logger.info(` Mismatches: ${modelStat.mismatches.toLocaleString()}`);
110
+ logger.info(` Avg % difference: ${modelStat.avgPercentDiff.toFixed(1)}%`);
111
+ }
112
+ }
113
+ if (stats.mismatches > 0 && stats.versionStats.size > 0) {
114
+ logger.info("\n=== Version Statistics ===");
115
+ const sortedVersions = Array.from(stats.versionStats.entries()).filter(([_, versionStat]) => versionStat.mismatches > 0).sort((a, b) => b[1].mismatches - a[1].mismatches);
116
+ for (const [version, versionStat] of sortedVersions) {
117
+ const versionMatchRate = versionStat.matches / versionStat.total * 100;
118
+ logger.info(`${version}:`);
119
+ logger.info(` Total entries: ${versionStat.total.toLocaleString()}`);
120
+ logger.info(` Matches: ${versionStat.matches.toLocaleString()} (${versionMatchRate.toFixed(1)}%)`);
121
+ logger.info(` Mismatches: ${versionStat.mismatches.toLocaleString()}`);
122
+ logger.info(` Avg % difference: ${versionStat.avgPercentDiff.toFixed(1)}%`);
123
+ }
124
+ }
125
+ if (stats.discrepancies.length > 0 && sampleCount > 0) {
126
+ logger.info(`\n=== Sample Discrepancies (first ${sampleCount}) ===`);
127
+ const samples = stats.discrepancies.slice(0, sampleCount);
128
+ for (const disc of samples) {
129
+ logger.info(`File: ${disc.file}`);
130
+ logger.info(`Timestamp: ${disc.timestamp}`);
131
+ logger.info(`Model: ${disc.model}`);
132
+ logger.info(`Original cost: $${disc.originalCost.toFixed(6)}`);
133
+ logger.info(`Calculated cost: $${disc.calculatedCost.toFixed(6)}`);
134
+ logger.info(`Difference: $${disc.difference.toFixed(6)} (${disc.percentDiff.toFixed(2)}%)`);
135
+ logger.info(`Tokens: ${JSON.stringify(disc.usage)}`);
136
+ logger.info("---");
137
+ }
138
+ }
139
+ }
140
+
141
+ //#endregion
142
+ export { detectMismatches, printMismatchReport };
@@ -0,0 +1,39 @@
1
+ //#region src/debug.d.ts
2
+ interface Discrepancy {
3
+ file: string;
4
+ timestamp: string;
5
+ model: string;
6
+ originalCost: number;
7
+ calculatedCost: number;
8
+ difference: number;
9
+ percentDiff: number;
10
+ usage: {
11
+ input_tokens: number;
12
+ output_tokens: number;
13
+ cache_creation_input_tokens?: number;
14
+ cache_read_input_tokens?: number;
15
+ };
16
+ }
17
+ interface MismatchStats {
18
+ totalEntries: number;
19
+ entriesWithBoth: number;
20
+ matches: number;
21
+ mismatches: number;
22
+ discrepancies: Discrepancy[];
23
+ modelStats: Map<string, {
24
+ total: number;
25
+ matches: number;
26
+ mismatches: number;
27
+ avgPercentDiff: number;
28
+ }>;
29
+ versionStats: Map<string, {
30
+ total: number;
31
+ matches: number;
32
+ mismatches: number;
33
+ avgPercentDiff: number;
34
+ }>;
35
+ }
36
+ declare function detectMismatches(claudePath?: string): Promise<MismatchStats>;
37
+ declare function printMismatchReport(stats: MismatchStats, sampleCount?: number): void;
38
+ //#endregion
39
+ export { detectMismatches, printMismatchReport };
package/dist/debug.js ADDED
@@ -0,0 +1,7 @@
1
+ import "./data-loader-r5ZcMQy7.js";
2
+ import "./dist-FwNhpFrW.js";
3
+ import "./logger-Cu4Ir1a5.js";
4
+ import "./pricing-fetcher-B5yPtoTB.js";
5
+ import { detectMismatches, printMismatchReport } from "./debug-BVxGf4UL.js";
6
+
7
+ export { detectMismatches, printMismatchReport };
@@ -0,0 +1,469 @@
1
+ import { getDefault } from "./dist-FwNhpFrW.js";
2
+
3
+ //#region node_modules/@valibot/to-json-schema/dist/index.js
4
+ /**
5
+ * Adds an error message to the errors array.
6
+ *
7
+ * @param errors The array of error messages.
8
+ * @param message The error message to add.
9
+ *
10
+ * @returns The new errors.
11
+ */
12
+ function addError(errors, message) {
13
+ if (errors) {
14
+ errors.push(message);
15
+ return errors;
16
+ }
17
+ return [message];
18
+ }
19
+ /**
20
+ * Throws an error or logs a warning based on the configuration.
21
+ *
22
+ * @param message The message to throw or log.
23
+ * @param config The conversion configuration.
24
+ */
25
+ function handleError(message, config) {
26
+ switch (config?.errorMode) {
27
+ case "ignore": break;
28
+ case "warn": {
29
+ console.warn(message);
30
+ break;
31
+ }
32
+ default: throw new Error(message);
33
+ }
34
+ }
35
+ /**
36
+ * Converts any supported Valibot action to the JSON Schema format.
37
+ *
38
+ * @param jsonSchema The JSON Schema object.
39
+ * @param valibotAction The Valibot action object.
40
+ * @param config The conversion configuration.
41
+ *
42
+ * @returns The converted JSON Schema.
43
+ */
44
+ function convertAction(jsonSchema, valibotAction, config) {
45
+ if (config?.ignoreActions?.includes(valibotAction.type)) return jsonSchema;
46
+ let errors;
47
+ switch (valibotAction.type) {
48
+ case "base64": {
49
+ jsonSchema.contentEncoding = "base64";
50
+ break;
51
+ }
52
+ case "bic":
53
+ case "cuid2":
54
+ case "decimal":
55
+ case "digits":
56
+ case "emoji":
57
+ case "hexadecimal":
58
+ case "hex_color":
59
+ case "nanoid":
60
+ case "octal":
61
+ case "ulid": {
62
+ jsonSchema.pattern = valibotAction.requirement.source;
63
+ break;
64
+ }
65
+ case "description": {
66
+ jsonSchema.description = valibotAction.description;
67
+ break;
68
+ }
69
+ case "email": {
70
+ jsonSchema.format = "email";
71
+ break;
72
+ }
73
+ case "empty": {
74
+ if (jsonSchema.type === "array") jsonSchema.maxItems = 0;
75
+ else {
76
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
77
+ jsonSchema.maxLength = 0;
78
+ }
79
+ break;
80
+ }
81
+ case "entries": {
82
+ jsonSchema.minProperties = valibotAction.requirement;
83
+ jsonSchema.maxProperties = valibotAction.requirement;
84
+ break;
85
+ }
86
+ case "integer": {
87
+ jsonSchema.type = "integer";
88
+ break;
89
+ }
90
+ case "ipv4": {
91
+ jsonSchema.format = "ipv4";
92
+ break;
93
+ }
94
+ case "ipv6": {
95
+ jsonSchema.format = "ipv6";
96
+ break;
97
+ }
98
+ case "iso_date": {
99
+ jsonSchema.format = "date";
100
+ break;
101
+ }
102
+ case "iso_date_time":
103
+ case "iso_timestamp": {
104
+ jsonSchema.format = "date-time";
105
+ break;
106
+ }
107
+ case "iso_time": {
108
+ jsonSchema.format = "time";
109
+ break;
110
+ }
111
+ case "length": {
112
+ if (jsonSchema.type === "array") {
113
+ jsonSchema.minItems = valibotAction.requirement;
114
+ jsonSchema.maxItems = valibotAction.requirement;
115
+ } else {
116
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
117
+ jsonSchema.minLength = valibotAction.requirement;
118
+ jsonSchema.maxLength = valibotAction.requirement;
119
+ }
120
+ break;
121
+ }
122
+ case "max_entries": {
123
+ jsonSchema.maxProperties = valibotAction.requirement;
124
+ break;
125
+ }
126
+ case "max_length": {
127
+ if (jsonSchema.type === "array") jsonSchema.maxItems = valibotAction.requirement;
128
+ else {
129
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
130
+ jsonSchema.maxLength = valibotAction.requirement;
131
+ }
132
+ break;
133
+ }
134
+ case "max_value": {
135
+ if (jsonSchema.type !== "number") errors = addError(errors, `The "max_value" action is not supported on type "${jsonSchema.type}".`);
136
+ jsonSchema.maximum = valibotAction.requirement;
137
+ break;
138
+ }
139
+ case "metadata": {
140
+ if (typeof valibotAction.metadata.title === "string") jsonSchema.title = valibotAction.metadata.title;
141
+ if (typeof valibotAction.metadata.description === "string") jsonSchema.description = valibotAction.metadata.description;
142
+ if (Array.isArray(valibotAction.metadata.examples)) jsonSchema.examples = valibotAction.metadata.examples;
143
+ break;
144
+ }
145
+ case "min_entries": {
146
+ jsonSchema.minProperties = valibotAction.requirement;
147
+ break;
148
+ }
149
+ case "min_length": {
150
+ if (jsonSchema.type === "array") jsonSchema.minItems = valibotAction.requirement;
151
+ else {
152
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
153
+ jsonSchema.minLength = valibotAction.requirement;
154
+ }
155
+ break;
156
+ }
157
+ case "min_value": {
158
+ if (jsonSchema.type !== "number") errors = addError(errors, `The "min_value" action is not supported on type "${jsonSchema.type}".`);
159
+ jsonSchema.minimum = valibotAction.requirement;
160
+ break;
161
+ }
162
+ case "multiple_of": {
163
+ jsonSchema.multipleOf = valibotAction.requirement;
164
+ break;
165
+ }
166
+ case "non_empty": {
167
+ if (jsonSchema.type === "array") jsonSchema.minItems = 1;
168
+ else {
169
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
170
+ jsonSchema.minLength = 1;
171
+ }
172
+ break;
173
+ }
174
+ case "regex": {
175
+ if (valibotAction.requirement.flags) errors = addError(errors, "RegExp flags are not supported by JSON Schema.");
176
+ jsonSchema.pattern = valibotAction.requirement.source;
177
+ break;
178
+ }
179
+ case "title": {
180
+ jsonSchema.title = valibotAction.title;
181
+ break;
182
+ }
183
+ case "url": {
184
+ jsonSchema.format = "uri";
185
+ break;
186
+ }
187
+ case "uuid": {
188
+ jsonSchema.format = "uuid";
189
+ break;
190
+ }
191
+ case "value": {
192
+ jsonSchema.const = valibotAction.requirement;
193
+ break;
194
+ }
195
+ default: errors = addError(errors, `The "${valibotAction.type}" action cannot be converted to JSON Schema.`);
196
+ }
197
+ if (config?.overrideAction) {
198
+ const actionOverride = config.overrideAction({
199
+ valibotAction,
200
+ jsonSchema,
201
+ errors
202
+ });
203
+ if (actionOverride) return { ...actionOverride };
204
+ }
205
+ if (errors) for (const message of errors) handleError(message, config);
206
+ return jsonSchema;
207
+ }
208
+ /**
209
+ * Flattens a Valibot pipe by recursively expanding nested pipes.
210
+ *
211
+ * @param pipe The pipeline to flatten.
212
+ *
213
+ * @returns A flat pipeline.
214
+ */
215
+ function flattenPipe(pipe) {
216
+ return pipe.flatMap((item) => "pipe" in item ? flattenPipe(item.pipe) : item);
217
+ }
218
+ let refCount = 0;
219
+ /**
220
+ * Converts any supported Valibot schema to the JSON Schema format.
221
+ *
222
+ * @param jsonSchema The JSON Schema object.
223
+ * @param valibotSchema The Valibot schema object.
224
+ * @param config The conversion configuration.
225
+ * @param context The conversion context.
226
+ * @param skipRef Whether to skip using a reference.
227
+ *
228
+ * @returns The converted JSON Schema.
229
+ */
230
+ function convertSchema(jsonSchema, valibotSchema, config, context, skipRef = false) {
231
+ if (!skipRef) {
232
+ const referenceId = context.referenceMap.get(valibotSchema);
233
+ if (referenceId) {
234
+ jsonSchema.$ref = `#/$defs/${referenceId}`;
235
+ if (config?.overrideRef) {
236
+ const refOverride = config.overrideRef({
237
+ ...context,
238
+ referenceId,
239
+ valibotSchema,
240
+ jsonSchema
241
+ });
242
+ if (refOverride) jsonSchema.$ref = refOverride;
243
+ }
244
+ return jsonSchema;
245
+ }
246
+ }
247
+ if ("pipe" in valibotSchema) {
248
+ const flatPipe = flattenPipe(valibotSchema.pipe);
249
+ let startIndex = 0;
250
+ let stopIndex = flatPipe.length - 1;
251
+ if (config?.typeMode === "input") {
252
+ const inputStopIndex = flatPipe.slice(1).findIndex((item) => item.kind === "schema" || item.kind === "transformation" && (item.type === "find_item" || item.type === "parse_json" || item.type === "raw_transform" || item.type === "reduce_items" || item.type === "stringify_json" || item.type === "transform"));
253
+ if (inputStopIndex !== -1) stopIndex = inputStopIndex;
254
+ } else if (config?.typeMode === "output") {
255
+ const outputStartIndex = flatPipe.findLastIndex((item) => item.kind === "schema");
256
+ if (outputStartIndex !== -1) startIndex = outputStartIndex;
257
+ }
258
+ for (let index = startIndex; index <= stopIndex; index++) {
259
+ const valibotPipeItem = flatPipe[index];
260
+ if (valibotPipeItem.kind === "schema") {
261
+ if (index > startIndex) handleError("Set the \"typeMode\" config to \"input\" or \"output\" to convert pipelines with multiple schemas.", config);
262
+ jsonSchema = convertSchema(jsonSchema, valibotPipeItem, config, context, true);
263
+ } else jsonSchema = convertAction(jsonSchema, valibotPipeItem, config);
264
+ }
265
+ return jsonSchema;
266
+ }
267
+ let errors;
268
+ switch (valibotSchema.type) {
269
+ case "boolean": {
270
+ jsonSchema.type = "boolean";
271
+ break;
272
+ }
273
+ case "null": {
274
+ jsonSchema.type = "null";
275
+ break;
276
+ }
277
+ case "number": {
278
+ jsonSchema.type = "number";
279
+ break;
280
+ }
281
+ case "string": {
282
+ jsonSchema.type = "string";
283
+ break;
284
+ }
285
+ case "array": {
286
+ jsonSchema.type = "array";
287
+ jsonSchema.items = convertSchema({}, valibotSchema.item, config, context);
288
+ break;
289
+ }
290
+ case "tuple":
291
+ case "tuple_with_rest":
292
+ case "loose_tuple":
293
+ case "strict_tuple": {
294
+ jsonSchema.type = "array";
295
+ jsonSchema.items = [];
296
+ jsonSchema.minItems = valibotSchema.items.length;
297
+ for (const item of valibotSchema.items) jsonSchema.items.push(convertSchema({}, item, config, context));
298
+ if (valibotSchema.type === "tuple_with_rest") jsonSchema.additionalItems = convertSchema({}, valibotSchema.rest, config, context);
299
+ else if (valibotSchema.type === "strict_tuple") jsonSchema.additionalItems = false;
300
+ break;
301
+ }
302
+ case "object":
303
+ case "object_with_rest":
304
+ case "loose_object":
305
+ case "strict_object": {
306
+ jsonSchema.type = "object";
307
+ jsonSchema.properties = {};
308
+ jsonSchema.required = [];
309
+ for (const key in valibotSchema.entries) {
310
+ const entry = valibotSchema.entries[key];
311
+ jsonSchema.properties[key] = convertSchema({}, entry, config, context);
312
+ if (entry.type !== "nullish" && entry.type !== "optional") jsonSchema.required.push(key);
313
+ }
314
+ if (valibotSchema.type === "object_with_rest") jsonSchema.additionalProperties = convertSchema({}, valibotSchema.rest, config, context);
315
+ else if (valibotSchema.type === "strict_object") jsonSchema.additionalProperties = false;
316
+ break;
317
+ }
318
+ case "record": {
319
+ if ("pipe" in valibotSchema.key) errors = addError(errors, "The \"record\" schema with a schema for the key that contains a \"pipe\" cannot be converted to JSON Schema.");
320
+ if (valibotSchema.key.type !== "string") errors = addError(errors, `The "record" schema with the "${valibotSchema.key.type}" schema for the key cannot be converted to JSON Schema.`);
321
+ jsonSchema.type = "object";
322
+ jsonSchema.additionalProperties = convertSchema({}, valibotSchema.value, config, context);
323
+ break;
324
+ }
325
+ case "any":
326
+ case "unknown": break;
327
+ case "nullable":
328
+ case "nullish": {
329
+ jsonSchema.anyOf = [convertSchema({}, valibotSchema.wrapped, config, context), { type: "null" }];
330
+ if (valibotSchema.default !== void 0) jsonSchema.default = getDefault(valibotSchema);
331
+ break;
332
+ }
333
+ case "exact_optional":
334
+ case "optional":
335
+ case "undefinedable": {
336
+ jsonSchema = convertSchema(jsonSchema, valibotSchema.wrapped, config, context);
337
+ if (valibotSchema.default !== void 0) jsonSchema.default = getDefault(valibotSchema);
338
+ break;
339
+ }
340
+ case "literal": {
341
+ if (typeof valibotSchema.literal !== "boolean" && typeof valibotSchema.literal !== "number" && typeof valibotSchema.literal !== "string") errors = addError(errors, "The value of the \"literal\" schema is not JSON compatible.");
342
+ jsonSchema.const = valibotSchema.literal;
343
+ break;
344
+ }
345
+ case "enum": {
346
+ jsonSchema.enum = valibotSchema.options;
347
+ break;
348
+ }
349
+ case "picklist": {
350
+ if (valibotSchema.options.some((option) => typeof option !== "number" && typeof option !== "string")) errors = addError(errors, "An option of the \"picklist\" schema is not JSON compatible.");
351
+ jsonSchema.enum = valibotSchema.options;
352
+ break;
353
+ }
354
+ case "union":
355
+ case "variant": {
356
+ jsonSchema.anyOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
357
+ break;
358
+ }
359
+ case "intersect": {
360
+ jsonSchema.allOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
361
+ break;
362
+ }
363
+ case "lazy": {
364
+ let wrappedValibotSchema = context.getterMap.get(valibotSchema.getter);
365
+ if (!wrappedValibotSchema) {
366
+ wrappedValibotSchema = valibotSchema.getter(void 0);
367
+ context.getterMap.set(valibotSchema.getter, wrappedValibotSchema);
368
+ }
369
+ let referenceId = context.referenceMap.get(wrappedValibotSchema);
370
+ if (!referenceId) {
371
+ referenceId = `${refCount++}`;
372
+ context.referenceMap.set(wrappedValibotSchema, referenceId);
373
+ context.definitions[referenceId] = convertSchema({}, wrappedValibotSchema, config, context, true);
374
+ }
375
+ jsonSchema.$ref = `#/$defs/${referenceId}`;
376
+ if (config?.overrideRef) {
377
+ const refOverride = config.overrideRef({
378
+ ...context,
379
+ referenceId,
380
+ valibotSchema: wrappedValibotSchema,
381
+ jsonSchema
382
+ });
383
+ if (refOverride) jsonSchema.$ref = refOverride;
384
+ }
385
+ break;
386
+ }
387
+ default: errors = addError(errors, `The "${valibotSchema.type}" schema cannot be converted to JSON Schema.`);
388
+ }
389
+ if (config?.overrideSchema) {
390
+ const schemaOverride = config.overrideSchema({
391
+ ...context,
392
+ referenceId: context.referenceMap.get(valibotSchema),
393
+ valibotSchema,
394
+ jsonSchema,
395
+ errors
396
+ });
397
+ if (schemaOverride) return { ...schemaOverride };
398
+ }
399
+ if (errors) for (const message of errors) handleError(message, config);
400
+ return jsonSchema;
401
+ }
402
+ let store;
403
+ /**
404
+ * Adds new definitions to the global schema definitions.
405
+ *
406
+ * @param definitions The schema definitions.
407
+ *
408
+ * @beta
409
+ */
410
+ function addGlobalDefs(definitions) {
411
+ store = {
412
+ ...store ?? {},
413
+ ...definitions
414
+ };
415
+ }
416
+ /**
417
+ * Returns the current global schema definitions.
418
+ *
419
+ * @returns The schema definitions.
420
+ *
421
+ * @beta
422
+ */
423
+ function getGlobalDefs() {
424
+ return store;
425
+ }
426
+ /**
427
+ * Converts a Valibot schema to the JSON Schema format.
428
+ *
429
+ * @param schema The Valibot schema object.
430
+ * @param config The JSON Schema configuration.
431
+ *
432
+ * @returns The converted JSON Schema.
433
+ */
434
+ function toJsonSchema(schema, config) {
435
+ const context = {
436
+ definitions: {},
437
+ referenceMap: new Map(),
438
+ getterMap: new Map()
439
+ };
440
+ const definitions = config?.definitions ?? getGlobalDefs();
441
+ if (definitions) {
442
+ for (const key in definitions) context.referenceMap.set(definitions[key], key);
443
+ for (const key in definitions) context.definitions[key] = convertSchema({}, definitions[key], config, context, true);
444
+ }
445
+ const jsonSchema = convertSchema({ $schema: "http://json-schema.org/draft-07/schema#" }, schema, config, context);
446
+ if (context.referenceMap.size) jsonSchema.$defs = context.definitions;
447
+ return jsonSchema;
448
+ }
449
+ /**
450
+ * Converts Valibot schema definitions to JSON Schema definitions.
451
+ *
452
+ * @param definitions The Valibot schema definitions.
453
+ * @param config The JSON Schema configuration.
454
+ *
455
+ * @returns The converted JSON Schema definitions.
456
+ */
457
+ function toJsonSchemaDefs(definitions, config) {
458
+ const context = {
459
+ definitions: {},
460
+ referenceMap: new Map(),
461
+ getterMap: new Map()
462
+ };
463
+ for (const key in definitions) context.referenceMap.set(definitions[key], key);
464
+ for (const key in definitions) context.definitions[key] = convertSchema({}, definitions[key], config, context, true);
465
+ return context.definitions;
466
+ }
467
+
468
+ //#endregion
469
+ export { addGlobalDefs, getGlobalDefs, toJsonSchema, toJsonSchemaDefs };