@with-logic/intent 0.1.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.
package/dist/intent.js ADDED
@@ -0,0 +1,540 @@
1
+ import { batchProcess } from "./batches";
2
+ import { CONFIG } from "./config";
3
+ import { DEFAULT_KEY_EXTRACTOR, DEFAULT_SUMMARY_EXTRACTOR } from "./extractors";
4
+ import { clamp } from "./lib/number";
5
+ import { selectLlmClient } from "./llm_client";
6
+ import { buildChoiceMessages, buildFilterMessages, buildMessages } from "./messages";
7
+ import { buildChoiceSchema, buildFilterSchema, buildRelevancySchema } from "./schema";
8
+ /**
9
+ * LLM-based reranker for arbitrary items.
10
+ *
11
+ * Uses a listwise LLM approach to score candidates within a configurable range based on relevance to a query,
12
+ * then filters by threshold and returns results sorted by score with stable ordering.
13
+ *
14
+ * @template T - The type of items to rerank (defaults to any)
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * // Simplest: uses defaults and GROQ_API_KEY from environment
19
+ * const intent = new Intent();
20
+ * const ranked = await intent.rank("find expense reports", items);
21
+ *
22
+ * // With custom extractors
23
+ * type Document = { id: string; title: string; content: string };
24
+ * const intent = new Intent<Document>({
25
+ * key: doc => doc.title,
26
+ * summary: doc => doc.content.slice(0, 200),
27
+ * relevancyThreshold: 5,
28
+ * batchSize: 20
29
+ * });
30
+ *
31
+ * // With custom LLM client
32
+ * const intent = new Intent<Document>({
33
+ * llm: myClient,
34
+ * userId: "user-123",
35
+ * key: doc => doc.title,
36
+ * summary: doc => doc.content.slice(0, 200)
37
+ * });
38
+ * ```
39
+ */
40
+ export class Intent {
41
+ /**
42
+ * Resolve the model name to use for this Intent instance.
43
+ *
44
+ * Intent is provider-driven. Today only GROQ is supported; when using GROQ
45
+ * we always take the model from GROQ's config defaults.
46
+ *
47
+ * @returns Provider-specific model name
48
+ * @private
49
+ */
50
+ resolveModel() {
51
+ return this.env.GROQ.DEFAULT_MODEL;
52
+ }
53
+ /**
54
+ * Builds the context object from options.
55
+ *
56
+ * Constructs an IntentContext with only defined properties to satisfy
57
+ * TypeScript's exactOptionalPropertyTypes requirement.
58
+ *
59
+ * @param options - The options object containing llm, logger, and userId
60
+ * @returns IntentContext with only defined properties
61
+ * @private
62
+ */
63
+ buildContext(options) {
64
+ return {
65
+ ...(options.llm !== undefined && { llm: options.llm }),
66
+ ...(options.logger !== undefined && { logger: options.logger }),
67
+ ...(options.userId !== undefined && { userId: options.userId }),
68
+ };
69
+ }
70
+ /**
71
+ * Builds the extractors object from options.
72
+ *
73
+ * Uses provided extractors or falls back to generic defaults that work
74
+ * for any type T via JSON stringification and hashing.
75
+ *
76
+ * @param options - The options object containing key and summary extractors
77
+ * @returns Required extractors with defaults applied
78
+ * @private
79
+ */
80
+ buildExtractors(options) {
81
+ return {
82
+ key: options.key ?? (DEFAULT_KEY_EXTRACTOR),
83
+ summary: options.summary ?? (DEFAULT_SUMMARY_EXTRACTOR),
84
+ };
85
+ }
86
+ /**
87
+ * Builds the configuration object from options.
88
+ *
89
+ * Merges user-provided options with environment-based CONFIG defaults.
90
+ *
91
+ * @param options - The options object containing config overrides
92
+ * @returns Required config with all values populated
93
+ * @private
94
+ */
95
+ buildConfig(options) {
96
+ return {
97
+ provider: options.provider ?? this.env.INTENT.PROVIDER,
98
+ timeoutMs: options.timeoutMs ?? this.env.INTENT.TIMEOUT_MS,
99
+ relevancyThreshold: options.relevancyThreshold ?? this.env.INTENT.RELEVANCY_THRESHOLD,
100
+ batchSize: options.batchSize ?? this.env.INTENT.BATCH_SIZE,
101
+ tinyBatchFraction: options.tinyBatchFraction ?? this.env.INTENT.TINY_BATCH_FRACTION,
102
+ minScore: options.minScore ?? this.env.INTENT.MIN_SCORE,
103
+ maxScore: options.maxScore ?? this.env.INTENT.MAX_SCORE,
104
+ };
105
+ }
106
+ /**
107
+ * Validates the configuration values.
108
+ *
109
+ * Ensures the configured score range is valid and the relevancyThreshold is in range.
110
+ *
111
+ * @throws {Error} If maxScore is below minScore
112
+ * @throws {Error} If relevancyThreshold is not within [minScore, maxScore]
113
+ * @private
114
+ */
115
+ validateConfig() {
116
+ if (this.cfg.maxScore < this.cfg.minScore) {
117
+ throw new Error(`intent: maxScore must be >= minScore, got minScore=${this.cfg.minScore} maxScore=${this.cfg.maxScore}`);
118
+ }
119
+ if (this.cfg.relevancyThreshold < this.cfg.minScore ||
120
+ this.cfg.relevancyThreshold > this.cfg.maxScore) {
121
+ throw new Error(`intent: relevancyThreshold must be between ${this.cfg.minScore} and ${this.cfg.maxScore}, got ${this.cfg.relevancyThreshold}`);
122
+ }
123
+ }
124
+ /**
125
+ * Selects and validates the LLM client.
126
+ *
127
+ * Uses the provided client from context or attempts to create a default
128
+ * Groq client if GROQ_API_KEY is available.
129
+ *
130
+ * @returns The selected LLM client
131
+ * @throws {Error} If no LLM client is provided and GROQ_API_KEY is not set
132
+ * @private
133
+ */
134
+ selectAndValidateLlmClient() {
135
+ const selectedClient = selectLlmClient(this.ctx, this.env);
136
+ if (!selectedClient) {
137
+ throw new Error("intent: No LLM client provided and GROQ_API_KEY not set. Provide options.llm or set GROQ_API_KEY.");
138
+ }
139
+ return selectedClient;
140
+ }
141
+ /**
142
+ * Creates a new Intent instance.
143
+ *
144
+ * All options are optional with sensible defaults:
145
+ * - llm: Auto-detected from GROQ_API_KEY environment variable if available
146
+ * - key: Hash-based string from JSON representation of items
147
+ * - summary: Pretty-printed JSON of items (2-space indentation for LLM readability)
148
+ * - Config values: From INTENT_* environment variables or built-in defaults
149
+ *
150
+ * @param options - Optional configuration object
151
+ * @param options.llm - Optional LLM client. If omitted, uses Groq client when GROQ_API_KEY is set
152
+ * @param options.logger - Optional logger for warnings and errors
153
+ * @param options.userId - Optional user identifier for LLM provider abuse monitoring
154
+ * @param options.key - Optional function extracting a short human-readable key from items
155
+ * @param options.summary - Optional function extracting a short description for LLM reasoning
156
+ * @param options.provider - Optional provider override (default: INTENT_PROVIDER or "GROQ")
157
+ * @param options.timeoutMs - Optional timeout in milliseconds (default: INTENT_TIMEOUT_MS or 3000)
158
+ * @param options.relevancyThreshold - Optional minimum score to include results (default: INTENT_RELEVANCY_THRESHOLD)
159
+ * @param options.minScore - Optional minimum score value (default: INTENT_MIN_SCORE or 0)
160
+ * @param options.maxScore - Optional maximum score value (default: INTENT_MAX_SCORE or 10)
161
+ * @param options.batchSize - Optional number of candidates per LLM call (default: INTENT_BATCH_SIZE or 20)
162
+ * @param options.tinyBatchFraction - Optional threshold for merging small batches (default: INTENT_TINY_BATCH_FRACTION or 0.2)
163
+ * @throws {Error} If no LLM client is provided and GROQ_API_KEY is not set
164
+ * @throws {Error} If maxScore is below minScore
165
+ * @throws {Error} If relevancyThreshold is not within [minScore, maxScore]
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * // Minimal - uses all defaults
170
+ * const intent = new Intent();
171
+ *
172
+ * // With extractors
173
+ * const intent = new Intent<Doc>({
174
+ * key: doc => doc.title,
175
+ * summary: doc => doc.content
176
+ * });
177
+ *
178
+ * // Full configuration
179
+ * const intent = new Intent<Doc>({
180
+ * llm: myClient,
181
+ * userId: "org-123",
182
+ * key: doc => doc.title,
183
+ * summary: doc => doc.content,
184
+ * relevancyThreshold: 5,
185
+ * batchSize: 20
186
+ * });
187
+ * ```
188
+ */
189
+ constructor(options = {}) {
190
+ this.env = options.config ?? CONFIG;
191
+ this.ctx = this.buildContext(options);
192
+ this.extractors = this.buildExtractors(options);
193
+ this.cfg = this.buildConfig(options);
194
+ this.validateConfig();
195
+ this.llm = this.selectAndValidateLlmClient();
196
+ }
197
+ async rank(query, candidates, options) {
198
+ try {
199
+ if (candidates.length === 0) {
200
+ return [];
201
+ }
202
+ if (candidates.length === 1) {
203
+ if (options?.explain) {
204
+ const [firstCandidate] = candidates;
205
+ return [{ item: firstCandidate, explanation: "" }];
206
+ }
207
+ return candidates;
208
+ }
209
+ const prepared = this.prepareCandidates(candidates);
210
+ const rankedWithExplanations = await batchProcess(prepared, this.cfg.batchSize, this.cfg.tinyBatchFraction, async (batch) => (await this.processBatch(query, batch, options?.userId !== undefined ? { userId: options.userId } : undefined)), this.ctx.logger, (batch) => batch.map(({ item }) => ({ item, explanation: "" })));
211
+ if (options?.explain) {
212
+ return rankedWithExplanations;
213
+ }
214
+ return rankedWithExplanations.map(({ item }) => item);
215
+ }
216
+ catch (error) {
217
+ this.ctx.logger?.warn?.("intent reranker failed, using fallback", {
218
+ error: error?.message,
219
+ });
220
+ if (options?.explain) {
221
+ return candidates.map((item) => ({ item, explanation: "" }));
222
+ }
223
+ return candidates;
224
+ }
225
+ }
226
+ async filter(query, candidates, options) {
227
+ if (candidates.length === 0) {
228
+ return [];
229
+ }
230
+ if (candidates.length === 1) {
231
+ if (options?.explain) {
232
+ const [firstCandidate] = candidates;
233
+ return [{ item: firstCandidate, explanation: "" }];
234
+ }
235
+ return candidates;
236
+ }
237
+ const prepared = this.prepareCandidates(candidates);
238
+ const filteredWithExplanations = await batchProcess(prepared, this.cfg.batchSize, this.cfg.tinyBatchFraction, async (batch) => (await this.processFilterBatch(query, batch, options?.userId !== undefined ? { userId: options.userId } : undefined)), this.ctx.logger, (batch) => batch.map(({ item }) => ({ item, explanation: "" })));
239
+ if (options?.explain) {
240
+ return filteredWithExplanations;
241
+ }
242
+ return filteredWithExplanations.map(({ item }) => item);
243
+ }
244
+ async choice(query, candidates, options) {
245
+ if (candidates.length === 0) {
246
+ throw new Error("intent: choice requires at least one candidate");
247
+ }
248
+ if (candidates.length === 1) {
249
+ const [firstCandidate] = candidates;
250
+ if (options?.explain) {
251
+ return { item: firstCandidate, explanation: "" };
252
+ }
253
+ return firstCandidate;
254
+ }
255
+ const prepared = this.prepareCandidates(candidates);
256
+ const keyed = this.ensureUniqueKeys(prepared);
257
+ const winners = await batchProcess(keyed, this.cfg.batchSize, this.cfg.tinyBatchFraction, async (batch) => [await this.processChoiceBatch(query, batch, options?.userId)], this.ctx.logger, (batch) => [{ item: batch[0].item, explanation: "" }]);
258
+ // batchProcess guarantees at least one winner via its per-batch fallback.
259
+ if (winners.length === 1) {
260
+ const [onlyWinner] = winners;
261
+ if (options?.explain) {
262
+ return onlyWinner;
263
+ }
264
+ return onlyWinner.item;
265
+ }
266
+ const preparedFinalists = this.prepareCandidates(winners.map((w) => w.item));
267
+ const keyedFinalists = this.ensureUniqueKeys(preparedFinalists);
268
+ const final = await this.processChoiceBatch(query, keyedFinalists, options?.userId);
269
+ if (options?.explain) {
270
+ return final;
271
+ }
272
+ return final.item;
273
+ }
274
+ /**
275
+ * Normalize incoming items into a consistent shape for downstream processing.
276
+ *
277
+ * Extracts the key and summary from each item using the configured extractors,
278
+ * and attaches the original input index for stable sorting later.
279
+ *
280
+ * @param candidates - Raw items to prepare
281
+ * @returns Array of prepared candidates with extracted metadata and original index
282
+ * @private
283
+ */
284
+ prepareCandidates(candidates) {
285
+ return candidates.map((item, idx) => ({
286
+ item,
287
+ idx,
288
+ baseKey: this.extractors.key(item),
289
+ summary: this.extractors.summary(item),
290
+ }));
291
+ }
292
+ /**
293
+ * Ensure keys are unique by suffixing duplicates with their input index.
294
+ *
295
+ * When multiple items share the same key, subsequent occurrences are renamed
296
+ * to "Key (idx)" where idx is the original input index. This prevents JSON
297
+ * schema validation errors and ensures the LLM can score each item independently.
298
+ *
299
+ * @param itemsBase - Prepared candidates with potentially duplicate keys
300
+ * @returns Candidates with guaranteed unique keys
301
+ * @private
302
+ */
303
+ ensureUniqueKeys(itemsBase) {
304
+ const counts = new Map();
305
+ return itemsBase.map(({ item, baseKey, summary, idx }) => {
306
+ const n = (counts.get(baseKey) ?? 0) + 1;
307
+ counts.set(baseKey, n);
308
+ const key = n === 1 ? baseKey : `${baseKey} (${idx})`;
309
+ return { item, idx, key, summary };
310
+ });
311
+ }
312
+ /**
313
+ * Build the JSON schema and chat messages payload for the LLM.
314
+ *
315
+ * Creates a strict JSON schema requiring one integer property (minScore-maxScore) per candidate key,
316
+ * and constructs system + user messages instructing the LLM to score relevance.
317
+ *
318
+ * @param query - The search query to evaluate candidates against
319
+ * @param items - Candidates with unique keys and summaries
320
+ * @returns Object containing JSON schema and chat messages array
321
+ * @private
322
+ */
323
+ buildRequest(query, items) {
324
+ const keys = items.map((x) => x.key);
325
+ const schema = buildRelevancySchema(keys, this.cfg.minScore, this.cfg.maxScore);
326
+ const messages = buildMessages(query, items, {
327
+ minScore: this.cfg.minScore,
328
+ maxScore: this.cfg.maxScore,
329
+ });
330
+ return { schema, messages };
331
+ }
332
+ /**
333
+ * Build the JSON schema and chat messages payload for the LLM filter call.
334
+ *
335
+ * @param query - The search query to evaluate candidates against
336
+ * @param items - Candidates with unique keys and summaries
337
+ * @returns Object containing JSON schema and chat messages array
338
+ * @private
339
+ */
340
+ buildFilterRequest(query, items) {
341
+ const keys = items.map((x) => x.key);
342
+ const schema = buildFilterSchema(keys);
343
+ const messages = buildFilterMessages(query, items);
344
+ return { schema, messages };
345
+ }
346
+ /**
347
+ * Build the JSON schema and chat messages payload for the LLM choice call.
348
+ *
349
+ * @param query - The search query to choose against
350
+ * @param items - Candidates with unique keys and summaries
351
+ * @returns Object containing JSON schema and chat messages array
352
+ * @private
353
+ */
354
+ buildChoiceRequest(query, items) {
355
+ const keys = items.map((x) => x.key);
356
+ const schema = buildChoiceSchema(keys);
357
+ const messages = buildChoiceMessages(query, items);
358
+ return { schema, messages };
359
+ }
360
+ /**
361
+ * Invoke the LLM and return the parsed map of candidate scores.
362
+ *
363
+ * Calls the configured LLM client with the messages, JSON schema, model config,
364
+ * and user ID. Returns null if the response is invalid or missing.
365
+ *
366
+ * @param messages - Chat messages (system + user) to send to LLM
367
+ * @param schema - Strict JSON schema defining expected response structure
368
+ * @param userId - Optional user identifier for provider abuse monitoring
369
+ * @returns Map of candidate keys to numeric scores, or null if response invalid
370
+ * @private
371
+ */
372
+ async fetchEvaluations(messages, schema, userId) {
373
+ const config = {
374
+ model: this.resolveModel(),
375
+ reasoningEffort: "medium",
376
+ timeoutMs: this.cfg.timeoutMs,
377
+ };
378
+ const { data } = await this.llm.call(messages, schema, config, userId ?? this.ctx.userId);
379
+ if (data == null || typeof data !== "object")
380
+ return null;
381
+ return data;
382
+ }
383
+ /**
384
+ * Invoke the LLM and return boolean relevancy decisions.
385
+ *
386
+ * @param messages - Chat messages to send
387
+ * @param schema - Strict JSON schema defining expected response structure
388
+ * @param userId - Optional user id
389
+ * @returns Map of candidate keys to filter decisions, or null if invalid
390
+ * @private
391
+ */
392
+ async fetchFilterDecisions(messages, schema, userId) {
393
+ const config = {
394
+ model: this.resolveModel(),
395
+ reasoningEffort: "medium",
396
+ timeoutMs: this.cfg.timeoutMs,
397
+ };
398
+ const { data } = await this.llm.call(messages, schema, config, userId ?? this.ctx.userId);
399
+ if (data == null || typeof data !== "object")
400
+ return null;
401
+ return data;
402
+ }
403
+ /**
404
+ * Invoke the LLM and return a single selected key.
405
+ *
406
+ * @param messages - Chat messages to send
407
+ * @param schema - Strict JSON schema defining expected response structure
408
+ * @param userId - Optional user id
409
+ * @returns Choice result, or null if invalid
410
+ * @private
411
+ */
412
+ async fetchChoice(messages, schema, userId) {
413
+ const config = {
414
+ model: this.resolveModel(),
415
+ reasoningEffort: "medium",
416
+ timeoutMs: this.cfg.timeoutMs,
417
+ };
418
+ const { data } = await this.llm.call(messages, schema, config, userId ?? this.ctx.userId);
419
+ if (data == null || typeof data !== "object")
420
+ return null;
421
+ const record = data;
422
+ const explanation = typeof record.explanation === "string" ? record.explanation : "";
423
+ const selectedKey = typeof record.selectedKey === "string" ? record.selectedKey : "";
424
+ if (selectedKey === "")
425
+ return null;
426
+ return { explanation, selectedKey };
427
+ }
428
+ /**
429
+ * Apply boolean filter decisions while preserving input order.
430
+ *
431
+ * @param items - Candidates with unique keys
432
+ * @param decisions - Map of candidate keys to decisions
433
+ * @returns Filtered items with explanations
434
+ * @private
435
+ */
436
+ applyFilter(items, decisions) {
437
+ const kept = [];
438
+ for (const it of items) {
439
+ const decision = decisions[it.key];
440
+ if (decision?.isRelevant === true) {
441
+ kept.push({
442
+ item: it.item,
443
+ explanation: typeof decision.explanation === "string" ? decision.explanation : "",
444
+ });
445
+ }
446
+ }
447
+ return kept;
448
+ }
449
+ /**
450
+ * Process a single batch of candidates through the LLM filter.
451
+ *
452
+ * @param query - Query to filter against
453
+ * @param batch - Prepared candidates
454
+ * @param options - Optional userId override
455
+ * @returns Filtered items (stable order), with explanations
456
+ * @private
457
+ */
458
+ async processFilterBatch(query, batch, options) {
459
+ const keyed = this.ensureUniqueKeys(batch);
460
+ const { schema, messages } = this.buildFilterRequest(query, keyed);
461
+ const decisions = await this.fetchFilterDecisions(messages, schema, options?.userId);
462
+ if (decisions == null) {
463
+ return keyed.map(({ item }) => ({ item, explanation: "" }));
464
+ }
465
+ return this.applyFilter(keyed, decisions);
466
+ }
467
+ /**
468
+ * Process a batch of candidates and choose a single winner.
469
+ *
470
+ * @param query - Query to choose against
471
+ * @param batch - Candidates with unique keys
472
+ * @param userId - Optional userId override
473
+ * @returns Winner item with explanation
474
+ * @private
475
+ */
476
+ async processChoiceBatch(query, batch, userId) {
477
+ const { schema, messages } = this.buildChoiceRequest(query, batch);
478
+ const choice = await this.fetchChoice(messages, schema, userId);
479
+ if (choice == null) {
480
+ return { item: batch[0].item, explanation: "" };
481
+ }
482
+ const winner = batch.find((x) => x.key === choice.selectedKey);
483
+ if (!winner) {
484
+ return { item: batch[0].item, explanation: choice.explanation };
485
+ }
486
+ return { item: winner.item, explanation: choice.explanation };
487
+ }
488
+ /**
489
+ * Apply relevancy threshold filtering and stable sorting.
490
+ *
491
+ * Scores are clamped to the configured score range, then filtered to keep only items with
492
+ * score > threshold. Results are sorted by score descending, with ties
493
+ * preserving original input order for deterministic results.
494
+ *
495
+ * @param items - Candidates with unique keys
496
+ * @param scores - Map of candidate keys to LLM-assigned scores
497
+ * @returns Filtered and sorted array of original items
498
+ * @private
499
+ */
500
+ rankAndFilter(items, evaluations) {
501
+ const threshold = this.cfg.relevancyThreshold;
502
+ const scored = items.map(({ item, idx, key }) => ({
503
+ item,
504
+ idx,
505
+ explanation: typeof evaluations[key]?.explanation === "string" ? evaluations[key].explanation : "",
506
+ score: clamp(evaluations[key]?.score ?? this.cfg.minScore, this.cfg.minScore, this.cfg.maxScore),
507
+ }));
508
+ const filtered = scored.filter(({ score }) => score > threshold);
509
+ const sorted = filtered.sort((a, b) => {
510
+ if (b.score !== a.score)
511
+ return b.score - a.score;
512
+ return a.idx - b.idx;
513
+ });
514
+ return sorted;
515
+ }
516
+ /**
517
+ * Process a single batch of candidates through the LLM.
518
+ *
519
+ * Ensures unique keys, builds the request payload, fetches scores from the LLM,
520
+ * and returns filtered and sorted results. On any error or null response from
521
+ * the LLM, returns items in their original order as a fallback.
522
+ *
523
+ * @param query - The search query to evaluate candidates against
524
+ * @param batch - Batch of prepared candidates to process
525
+ * @param userId - Optional user identifier for provider abuse monitoring
526
+ * @returns Ranked and filtered items, or original order on error
527
+ * @private
528
+ */
529
+ async processBatch(query, batch, options) {
530
+ const keyed = this.ensureUniqueKeys(batch);
531
+ const { schema, messages } = this.buildRequest(query, keyed);
532
+ const evaluations = await this.fetchEvaluations(messages, schema, options?.userId);
533
+ if (evaluations == null) {
534
+ return keyed.map(({ item }) => ({ item, explanation: "" }));
535
+ }
536
+ const ranked = this.rankAndFilter(keyed, evaluations);
537
+ return ranked.map(({ item, explanation }) => ({ item, explanation }));
538
+ }
539
+ }
540
+ //# sourceMappingURL=intent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent.js","sourceRoot":"","sources":["../src/intent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Lightweight env var readers matching the API service pattern.
3
+ * - If the env var is set (non-empty), parse and return it.
4
+ * - Otherwise, if a default is provided, return the default.
5
+ * - Otherwise, throw a helpful error.
6
+ *
7
+ * This version exposes four self-contained readers with an options object
8
+ * supporting { default, min, max } where min/max apply to int/number only.
9
+ */
10
+ export type BaseOptions<T> = {
11
+ default?: T;
12
+ };
13
+ export type RangeOptions = BaseOptions<number> & {
14
+ min?: number;
15
+ max?: number;
16
+ };
17
+ export type EnumOptions<T extends readonly string[]> = BaseOptions<T[number]> & {
18
+ values: T;
19
+ };
20
+ export declare function string(name: string, opts?: BaseOptions<string>): string;
21
+ /**
22
+ * Read an env var as a constrained enum string.
23
+ *
24
+ * When set, validates the value is included in opts.values.
25
+ * When unset, returns opts.default if provided, otherwise throws.
26
+ */
27
+ export declare function enumeration<const T extends readonly string[]>(name: string, opts: EnumOptions<T>): T[number];
28
+ export declare function boolean(name: string, opts?: BaseOptions<boolean>): boolean;
29
+ export declare function int(name: string, opts?: RangeOptions): number;
30
+ export declare function number(name: string, opts?: RangeOptions): number;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Lightweight env var readers matching the API service pattern.
3
+ * - If the env var is set (non-empty), parse and return it.
4
+ * - Otherwise, if a default is provided, return the default.
5
+ * - Otherwise, throw a helpful error.
6
+ *
7
+ * This version exposes four self-contained readers with an options object
8
+ * supporting { default, min, max } where min/max apply to int/number only.
9
+ */
10
+ function throwRequiredEnvVar(name) {
11
+ throw new Error(`${name} is required.`);
12
+ }
13
+ import { clamp } from "./number";
14
+ export function string(name, opts) {
15
+ const value = process.env[name];
16
+ const exists = value != null && value.length > 0;
17
+ if (exists) {
18
+ return value;
19
+ }
20
+ if (opts?.default !== undefined) {
21
+ return opts.default;
22
+ }
23
+ return throwRequiredEnvVar(name);
24
+ }
25
+ /**
26
+ * Read an env var as a constrained enum string.
27
+ *
28
+ * When set, validates the value is included in opts.values.
29
+ * When unset, returns opts.default if provided, otherwise throws.
30
+ */
31
+ export function enumeration(name, opts) {
32
+ const value = opts.default !== undefined ? string(name, { default: opts.default }) : string(name);
33
+ if (opts.values.includes(value)) {
34
+ return value;
35
+ }
36
+ throw new Error(`${name} must be one of: ${opts.values.join(", ")}`);
37
+ }
38
+ export function boolean(name, opts) {
39
+ const value = process.env[name];
40
+ const exists = value != null && value.length > 0;
41
+ if (exists) {
42
+ const v = value;
43
+ return ["0", "false"].includes(v) === false;
44
+ }
45
+ if (opts?.default !== undefined) {
46
+ return opts.default;
47
+ }
48
+ return throwRequiredEnvVar(name);
49
+ }
50
+ export function int(name, opts) {
51
+ const value = process.env[name];
52
+ const exists = value != null && value.length > 0;
53
+ if (exists) {
54
+ const parsed = Number.parseInt(value, 10);
55
+ if (Number.isNaN(parsed)) {
56
+ throw new Error(`${name} must be a valid integer`);
57
+ }
58
+ return clamp(parsed, opts?.min, opts?.max);
59
+ }
60
+ if (opts?.default !== undefined) {
61
+ const def = Math.trunc(opts.default);
62
+ return clamp(def, opts?.min, opts?.max);
63
+ }
64
+ return throwRequiredEnvVar(name);
65
+ }
66
+ export function number(name, opts) {
67
+ const value = process.env[name];
68
+ const exists = value != null && value.length > 0;
69
+ if (exists) {
70
+ const parsed = Number.parseFloat(value);
71
+ if (Number.isNaN(parsed)) {
72
+ throw new Error(`${name} must be a valid number`);
73
+ }
74
+ return clamp(parsed, opts?.min, opts?.max);
75
+ }
76
+ if (opts?.default !== undefined) {
77
+ return clamp(opts.default, opts?.min, opts?.max);
78
+ }
79
+ return throwRequiredEnvVar(name);
80
+ }
81
+ //# sourceMappingURL=config.js.map