@dinoconfig/cli 0.0.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.
@@ -0,0 +1,1622 @@
1
+ import { b as T, C as v, a as j, D as A, c as z } from "./constants-Dvwyqn-J.js";
2
+ import * as f from "fs";
3
+ import * as p from "path";
4
+ class R {
5
+ /**
6
+ * Creates a new HttpClient instance.
7
+ *
8
+ * @param {string} baseUrl - The base URL of the DinoConfig API
9
+ * @param {number} [timeout=10000] - Default request timeout in milliseconds
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const client = new HttpClient('https://api.dinoconfig.com', 15000);
14
+ * ```
15
+ */
16
+ constructor(e, t = 1e4) {
17
+ this.baseUrl = e.replace(/\/$/, ""), this.defaultTimeout = t;
18
+ }
19
+ /**
20
+ * Configures authorization by exchanging the API key for an access token.
21
+ *
22
+ * This method:
23
+ * 1. Extracts the API key from the provided headers
24
+ * 2. Exchanges it for a JWT access token
25
+ * 3. Configures the Authorization header for subsequent requests
26
+ *
27
+ * @async
28
+ * @method configureAuthorizationHeader
29
+ * @param {Record<string, string>} headers - Headers containing the X-API-Key
30
+ * @returns {Promise<void>}
31
+ * @throws {Error} If token exchange fails
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * await client.configureAuthorizationHeader({
36
+ * 'X-API-Key': 'dino_your-api-key-here'
37
+ * });
38
+ * // Client is now authenticated
39
+ * ```
40
+ */
41
+ async configureAuthorizationHeader(e) {
42
+ const t = e["X-API-Key"], s = await this.exchangeApiKeyForToken(t);
43
+ this.defaultHeaders = {
44
+ "Content-Type": "application/json",
45
+ Authorization: `Bearer ${s}`,
46
+ ...e
47
+ };
48
+ }
49
+ /**
50
+ * Exchanges an API key for a JWT access token.
51
+ *
52
+ * Makes a POST request to the token exchange endpoint with the API key
53
+ * and returns the access token from the response.
54
+ *
55
+ * @async
56
+ * @private
57
+ * @method exchangeApiKeyForToken
58
+ * @param {string} apiKey - The API key to exchange
59
+ * @returns {Promise<string>} The JWT access token
60
+ * @throws {Error} If the exchange fails or the API key is invalid
61
+ *
62
+ * @remarks
63
+ * The API key is sent via HTTPS, which encrypts it in transit.
64
+ * The server validates the key and returns a short-lived access token.
65
+ */
66
+ async exchangeApiKeyForToken(e) {
67
+ try {
68
+ const t = await fetch(`${this.baseUrl}/api/auth/sdk-token/exchange`, {
69
+ method: "POST",
70
+ headers: {
71
+ "Content-Type": "application/json",
72
+ "x-api-key": e
73
+ },
74
+ credentials: "include"
75
+ });
76
+ if (!t.ok) {
77
+ const n = await t.text();
78
+ throw new Error(`Failed to exchange API key for token: ${t.status} ${n}`);
79
+ }
80
+ return (await t.json()).access_token;
81
+ } catch (t) {
82
+ const s = t instanceof Error ? t.message : "Unknown error";
83
+ throw new Error(`Failed to authenticate with API key: ${s}`);
84
+ }
85
+ }
86
+ /**
87
+ * Makes an HTTP request to the API.
88
+ *
89
+ * Handles:
90
+ * - Request formatting and headers
91
+ * - Timeout via AbortController
92
+ * - Response parsing
93
+ * - Error handling
94
+ * - Retry logic with exponential backoff
95
+ *
96
+ * @async
97
+ * @private
98
+ * @method request
99
+ * @typeParam T - The expected response data type
100
+ * @param {string} method - HTTP method (GET, POST, PUT, PATCH, DELETE)
101
+ * @param {string} endpoint - API endpoint path (e.g., '/api/configs')
102
+ * @param {any} [data] - Request body data (for POST, PUT, PATCH)
103
+ * @param {RequestOptions} [options={}] - Request customization options
104
+ * @returns {Promise<ApiResponse<T>>} The API response
105
+ * @throws {ApiError} If the request fails after all retries
106
+ */
107
+ async request(e, t, s, n = {}) {
108
+ const a = `${this.baseUrl}${t}`, r = n.timeout || this.defaultTimeout, o = n.retries || 0;
109
+ let l = null;
110
+ for (let c = 0; c <= o; c++)
111
+ try {
112
+ const u = new AbortController(), h = setTimeout(() => u.abort(), r), d = {
113
+ method: e,
114
+ headers: this.defaultHeaders,
115
+ signal: u.signal
116
+ };
117
+ s && (e === "POST" || e === "PUT" || e === "PATCH") && (d.body = JSON.stringify(s));
118
+ const m = await fetch(a, d);
119
+ clearTimeout(h);
120
+ const y = await m.json();
121
+ if (!m.ok)
122
+ throw {
123
+ message: y.message || m.statusText,
124
+ status: m.status,
125
+ code: y.code
126
+ };
127
+ return {
128
+ data: y,
129
+ success: !0
130
+ };
131
+ } catch (u) {
132
+ if (l = u, u instanceof Error && "status" in u) {
133
+ const h = u;
134
+ if (h.status >= 400 && h.status < 500)
135
+ throw u;
136
+ }
137
+ if (c === o)
138
+ throw u;
139
+ await new Promise((h) => setTimeout(h, Math.pow(2, c) * 1e3));
140
+ }
141
+ throw l || new Error("Request failed after all retries");
142
+ }
143
+ /**
144
+ * Makes a GET request to the specified endpoint.
145
+ *
146
+ * @async
147
+ * @method get
148
+ * @typeParam T - The expected response data type
149
+ * @param {string} endpoint - The API endpoint path
150
+ * @param {RequestOptions} [options] - Optional request configuration
151
+ * @returns {Promise<ApiResponse<T>>} The API response
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const response = await client.get<Config>('/api/configs/123');
156
+ * console.log(response.data.name);
157
+ * ```
158
+ */
159
+ async get(e, t) {
160
+ return this.request("GET", e, void 0, t);
161
+ }
162
+ /**
163
+ * Makes a POST request to the specified endpoint.
164
+ *
165
+ * @async
166
+ * @method post
167
+ * @typeParam T - The expected response data type
168
+ * @param {string} endpoint - The API endpoint path
169
+ * @param {any} [data] - The request body data
170
+ * @param {RequestOptions} [options] - Optional request configuration
171
+ * @returns {Promise<ApiResponse<T>>} The API response
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * const response = await client.post<Config>('/api/configs', {
176
+ * name: 'NewConfig',
177
+ * formData: { key: 'value' }
178
+ * });
179
+ * ```
180
+ */
181
+ async post(e, t, s) {
182
+ return this.request("POST", e, t, s);
183
+ }
184
+ /**
185
+ * Makes a PUT request to the specified endpoint.
186
+ *
187
+ * @async
188
+ * @method put
189
+ * @typeParam T - The expected response data type
190
+ * @param {string} endpoint - The API endpoint path
191
+ * @param {any} [data] - The request body data
192
+ * @param {RequestOptions} [options] - Optional request configuration
193
+ * @returns {Promise<ApiResponse<T>>} The API response
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * const response = await client.put<Config>('/api/configs/123', {
198
+ * name: 'UpdatedConfig'
199
+ * });
200
+ * ```
201
+ */
202
+ async put(e, t, s) {
203
+ return this.request("PUT", e, t, s);
204
+ }
205
+ /**
206
+ * Makes a PATCH request to the specified endpoint.
207
+ *
208
+ * @async
209
+ * @method patch
210
+ * @typeParam T - The expected response data type
211
+ * @param {string} endpoint - The API endpoint path
212
+ * @param {any} [data] - The request body data (partial update)
213
+ * @param {RequestOptions} [options] - Optional request configuration
214
+ * @returns {Promise<ApiResponse<T>>} The API response
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * const response = await client.patch<Config>('/api/configs/123', {
219
+ * formData: { updatedKey: 'newValue' }
220
+ * });
221
+ * ```
222
+ */
223
+ async patch(e, t, s) {
224
+ return this.request("PATCH", e, t, s);
225
+ }
226
+ /**
227
+ * Makes a DELETE request to the specified endpoint.
228
+ *
229
+ * @async
230
+ * @method delete
231
+ * @typeParam T - The expected response data type
232
+ * @param {string} endpoint - The API endpoint path
233
+ * @param {RequestOptions} [options] - Optional request configuration
234
+ * @returns {Promise<ApiResponse<T>>} The API response
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * const response = await client.delete('/api/configs/123');
239
+ * ```
240
+ */
241
+ async delete(e, t) {
242
+ return this.request("DELETE", e, void 0, t);
243
+ }
244
+ /**
245
+ * Updates the authorization token.
246
+ *
247
+ * Use this method if you need to manually update the token
248
+ * (e.g., after refreshing it externally).
249
+ *
250
+ * @method setToken
251
+ * @param {string} token - The new JWT access token
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * client.setToken('new-jwt-token');
256
+ * ```
257
+ */
258
+ setToken(e) {
259
+ this.defaultHeaders.Authorization = `Bearer ${e}`;
260
+ }
261
+ /**
262
+ * Sets a custom header for all subsequent requests.
263
+ *
264
+ * @method setHeader
265
+ * @param {string} key - The header name
266
+ * @param {string} value - The header value
267
+ *
268
+ * @example
269
+ * ```typescript
270
+ * client.setHeader('X-Custom-Header', 'custom-value');
271
+ * ```
272
+ */
273
+ setHeader(e, t) {
274
+ this.defaultHeaders[e] = t;
275
+ }
276
+ /**
277
+ * Removes a custom header from subsequent requests.
278
+ *
279
+ * @method removeHeader
280
+ * @param {string} key - The header name to remove
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * client.removeHeader('X-Custom-Header');
285
+ * ```
286
+ */
287
+ removeHeader(e) {
288
+ delete this.defaultHeaders[e];
289
+ }
290
+ }
291
+ const I = "/api/sdk/brands";
292
+ class M {
293
+ constructor(e, t) {
294
+ this.httpClient = e, this.cacheManager = t;
295
+ }
296
+ async get(e, t, s) {
297
+ const { brand: n, config: a, requestOptions: r } = this.parseConfigArgs(
298
+ e,
299
+ t,
300
+ s
301
+ ), o = `config:${n}:${a}`, l = this.cacheManager && r?.cache !== !1 && !r?.forceRefresh;
302
+ if (l) {
303
+ const h = await this.cacheManager.get(o);
304
+ if (h !== null)
305
+ return h;
306
+ }
307
+ const c = await this.httpClient.get(
308
+ this.buildConfigUrl(n, a),
309
+ r
310
+ ), u = {
311
+ ...c,
312
+ data: this.transformConfigResponse(c.data)
313
+ };
314
+ return l && c.success && await this.cacheManager.set(o, u, { ttl: r?.ttl }), u;
315
+ }
316
+ async getValue(e, t, s, n) {
317
+ const { brand: a, config: r, key: o, requestOptions: l } = this.parseValueArgs(
318
+ e,
319
+ t,
320
+ s,
321
+ n
322
+ ), c = `config:${a}:${r}:${o}`, u = this.cacheManager && l?.cache !== !1 && !l?.forceRefresh;
323
+ if (u) {
324
+ const d = await this.cacheManager.get(c);
325
+ if (d !== null)
326
+ return d;
327
+ }
328
+ const h = await this.httpClient.get(
329
+ this.buildValueUrl(a, r, o),
330
+ l
331
+ );
332
+ return u && h.success && await this.cacheManager.set(c, h, { ttl: l?.ttl }), h;
333
+ }
334
+ // ─────────────────────────────────────────────────────────────────────────────
335
+ // Private helpers
336
+ // ─────────────────────────────────────────────────────────────────────────────
337
+ /**
338
+ * Parses arguments for the get() method.
339
+ */
340
+ parseConfigArgs(e, t, s) {
341
+ if (typeof t == "string")
342
+ return {
343
+ brand: e,
344
+ config: t,
345
+ requestOptions: s
346
+ };
347
+ const n = this.parsePath(e, 2);
348
+ return {
349
+ brand: n[0],
350
+ config: n[1],
351
+ requestOptions: t
352
+ };
353
+ }
354
+ /**
355
+ * Parses arguments for the getValue() method.
356
+ */
357
+ parseValueArgs(e, t, s, n) {
358
+ if (typeof t == "string")
359
+ return {
360
+ brand: e,
361
+ config: t,
362
+ key: s,
363
+ requestOptions: n
364
+ };
365
+ const a = this.parsePath(e, 3);
366
+ return {
367
+ brand: a[0],
368
+ config: a[1],
369
+ key: a[2],
370
+ requestOptions: t
371
+ };
372
+ }
373
+ /**
374
+ * Parses a dot-notation path into components.
375
+ */
376
+ parsePath(e, t) {
377
+ const s = e.split(".");
378
+ if (s.length !== t) {
379
+ const n = t === 2 ? "brandName.configName" : "brandName.configName.keyName";
380
+ throw new Error(`Invalid path format "${e}". Expected "${n}"`);
381
+ }
382
+ return s;
383
+ }
384
+ /**
385
+ * Builds the URL for fetching an entire config.
386
+ */
387
+ buildConfigUrl(e, t) {
388
+ return `${I}/${this.encode(e)}/configs/${this.encode(t)}`;
389
+ }
390
+ /**
391
+ * Builds the URL for fetching a single value.
392
+ */
393
+ buildValueUrl(e, t, s) {
394
+ return `${I}/${this.encode(e)}/configs/${this.encode(t)}/${this.encode(s)}`;
395
+ }
396
+ /**
397
+ * URL-encodes a path segment.
398
+ */
399
+ encode(e) {
400
+ return encodeURIComponent(e);
401
+ }
402
+ /**
403
+ * Transforms the backend response to the public ConfigData shape.
404
+ */
405
+ transformConfigResponse(e) {
406
+ return {
407
+ name: e.name,
408
+ description: e.description,
409
+ values: e.formData,
410
+ version: e.version,
411
+ keys: e.keys,
412
+ createdAt: e.createdAt,
413
+ updatedAt: e.updatedAt
414
+ };
415
+ }
416
+ }
417
+ const $ = "/api/sdk";
418
+ class N {
419
+ constructor(e) {
420
+ this.httpClient = e;
421
+ }
422
+ /**
423
+ * Lists all brands accessible by the current API key.
424
+ *
425
+ * @example
426
+ * ```typescript
427
+ * const response = await dinoconfig.discovery.listBrands();
428
+ * response.data.forEach(brand => {
429
+ * console.log(`${brand.name}: ${brand.configCount} configs`);
430
+ * });
431
+ * ```
432
+ */
433
+ async listBrands(e) {
434
+ const t = await this.httpClient.get(
435
+ `${$}/brands`,
436
+ e
437
+ );
438
+ return this.extractData(t, t.data.brands);
439
+ }
440
+ /**
441
+ * Lists all configurations for a specific brand.
442
+ *
443
+ * @example
444
+ * ```typescript
445
+ * const response = await dinoconfig.discovery.listConfigs('MyBrand');
446
+ * response.data.forEach(config => {
447
+ * console.log(`${config.name}: ${config.keys.length} keys`);
448
+ * });
449
+ * ```
450
+ */
451
+ async listConfigs(e, t) {
452
+ const s = await this.httpClient.get(
453
+ this.buildBrandUrl(e, "/configs"),
454
+ t
455
+ );
456
+ return this.extractData(s, s.data.configs);
457
+ }
458
+ /**
459
+ * Gets the schema/structure for a specific configuration.
460
+ *
461
+ * @example
462
+ * ```typescript
463
+ * const response = await dinoconfig.discovery.getSchema('MyBrand', 'FeatureFlags');
464
+ * Object.entries(response.data.fields).forEach(([name, field]) => {
465
+ * console.log(`${name}: ${field.type}`);
466
+ * });
467
+ * ```
468
+ */
469
+ async getSchema(e, t, s) {
470
+ return this.httpClient.get(
471
+ this.buildConfigUrl(e, t, "/schema"),
472
+ s
473
+ );
474
+ }
475
+ /**
476
+ * Performs full introspection, returning all brands, configs, and keys.
477
+ *
478
+ * @example
479
+ * ```typescript
480
+ * const response = await dinoconfig.discovery.introspect();
481
+ * response.data.brands.forEach(brand => {
482
+ * console.log(`Brand: ${brand.name}`);
483
+ * brand.configs.forEach(config => {
484
+ * console.log(` Config: ${config.name} (${config.keys.length} keys)`);
485
+ * });
486
+ * });
487
+ * ```
488
+ */
489
+ async introspect(e) {
490
+ return this.httpClient.get(`${$}/introspect`, e);
491
+ }
492
+ // ─────────────────────────────────────────────────────────────────────────────
493
+ // Private helpers
494
+ // ─────────────────────────────────────────────────────────────────────────────
495
+ /**
496
+ * Builds URL path for brand-level endpoints.
497
+ */
498
+ buildBrandUrl(e, t = "") {
499
+ return `${$}/brands/${this.encode(e)}${t}`;
500
+ }
501
+ /**
502
+ * Builds URL path for config-level endpoints.
503
+ */
504
+ buildConfigUrl(e, t, s = "") {
505
+ return `${$}/brands/${this.encode(e)}/configs/${this.encode(t)}${s}`;
506
+ }
507
+ /**
508
+ * URL-encodes a path segment.
509
+ */
510
+ encode(e) {
511
+ return encodeURIComponent(e);
512
+ }
513
+ /**
514
+ * Extracts and transforms response data.
515
+ */
516
+ extractData(e, t) {
517
+ return {
518
+ ...e,
519
+ data: t
520
+ };
521
+ }
522
+ }
523
+ class x {
524
+ constructor(e, t) {
525
+ this.ttl = e, this.maxSize = t, this.cache = /* @__PURE__ */ new Map(), this.hits = 0, this.misses = 0;
526
+ }
527
+ /**
528
+ * Get a value from the cache.
529
+ *
530
+ * @param {string} key - Cache key
531
+ * @returns {T | null} Cached value or null if not found/expired
532
+ */
533
+ get(e) {
534
+ const t = this.cache.get(e);
535
+ return t ? this.isExpired(t) ? (this.cache.delete(e), this.misses++, null) : (this.hits++, t.value) : (this.misses++, null);
536
+ }
537
+ /**
538
+ * Set a value in the cache.
539
+ *
540
+ * @param {string} key - Cache key
541
+ * @param {T} value - Value to cache
542
+ * @param {CacheOptions} options - Optional cache options
543
+ */
544
+ set(e, t, s) {
545
+ const n = s?.ttl ?? this.ttl, a = {
546
+ value: t,
547
+ timestamp: Date.now(),
548
+ expiresAt: Date.now() + n
549
+ };
550
+ this.cache.size >= this.maxSize && !this.cache.has(e) && this.evictOldest(), this.cache.set(e, a);
551
+ }
552
+ /**
553
+ * Delete a value from the cache.
554
+ *
555
+ * @param {string} key - Cache key
556
+ */
557
+ delete(e) {
558
+ this.cache.delete(e);
559
+ }
560
+ /**
561
+ * Clear all entries from the cache.
562
+ */
563
+ clear() {
564
+ this.cache.clear(), this.hits = 0, this.misses = 0;
565
+ }
566
+ /**
567
+ * Invalidate entries matching a pattern.
568
+ *
569
+ * @param {string} pattern - Regex pattern to match keys
570
+ */
571
+ invalidate(e) {
572
+ const t = new RegExp(e);
573
+ for (const s of this.cache.keys())
574
+ t.test(s) && this.cache.delete(s);
575
+ }
576
+ /**
577
+ * Check if an entry exists and is not expired.
578
+ *
579
+ * @param {string} key - Cache key
580
+ * @returns {boolean} True if entry exists and is valid
581
+ */
582
+ has(e) {
583
+ const t = this.cache.get(e);
584
+ return t ? this.isExpired(t) ? (this.cache.delete(e), !1) : !0 : !1;
585
+ }
586
+ /**
587
+ * Get cache statistics.
588
+ *
589
+ * @returns {CacheStats} Cache statistics
590
+ */
591
+ getStats() {
592
+ const e = this.hits + this.misses;
593
+ return {
594
+ hits: this.hits,
595
+ misses: this.misses,
596
+ size: this.cache.size,
597
+ hitRate: e > 0 ? this.hits / e : 0
598
+ };
599
+ }
600
+ /**
601
+ * Check if an entry is expired.
602
+ *
603
+ * @private
604
+ * @param {CacheEntry} entry - Cache entry
605
+ * @returns {boolean} True if expired
606
+ */
607
+ isExpired(e) {
608
+ return Date.now() > e.expiresAt;
609
+ }
610
+ /**
611
+ * Evict the oldest entry from the cache.
612
+ * Uses LRU-like strategy based on expiration time.
613
+ *
614
+ * @private
615
+ */
616
+ evictOldest() {
617
+ let e = null, t = 1 / 0;
618
+ for (const [s, n] of this.cache.entries())
619
+ n.expiresAt < t && (t = n.expiresAt, e = s);
620
+ e && this.cache.delete(e);
621
+ }
622
+ }
623
+ class U {
624
+ constructor() {
625
+ if (typeof window > "u" || !window.localStorage)
626
+ throw new Error("localStorage is not available in this environment");
627
+ this.storage = window.localStorage;
628
+ }
629
+ getItem(e) {
630
+ try {
631
+ return this.storage.getItem(e);
632
+ } catch {
633
+ return null;
634
+ }
635
+ }
636
+ setItem(e, t) {
637
+ try {
638
+ this.storage.setItem(e, t);
639
+ } catch {
640
+ }
641
+ }
642
+ removeItem(e) {
643
+ try {
644
+ this.storage.removeItem(e);
645
+ } catch {
646
+ }
647
+ }
648
+ clear() {
649
+ try {
650
+ const e = Object.keys(this.storage);
651
+ for (const t of e)
652
+ t.startsWith("dinoconfig:") && this.storage.removeItem(t);
653
+ } catch {
654
+ }
655
+ }
656
+ }
657
+ class L {
658
+ constructor(e) {
659
+ if (this.prefix = "dinoconfig:", e === "localStorage")
660
+ this.adapter = new U();
661
+ else
662
+ throw new Error("IndexedDB storage is not yet implemented");
663
+ }
664
+ /**
665
+ * Get a value from storage cache.
666
+ *
667
+ * @param {string} key - Cache key
668
+ * @returns {Promise<T | null>} Cached value or null if not found/expired
669
+ */
670
+ async get(e) {
671
+ try {
672
+ const t = this.adapter.getItem(this.prefix + e);
673
+ if (!t)
674
+ return null;
675
+ const s = JSON.parse(t);
676
+ return this.isExpired(s) ? (this.adapter.removeItem(this.prefix + e), null) : s.value;
677
+ } catch {
678
+ return null;
679
+ }
680
+ }
681
+ /**
682
+ * Set a value in storage cache.
683
+ *
684
+ * @param {string} key - Cache key
685
+ * @param {T} value - Value to cache
686
+ * @param {CacheOptions} options - Optional cache options
687
+ */
688
+ async set(e, t, s) {
689
+ try {
690
+ const n = s?.ttl ?? 3e5, a = {
691
+ value: t,
692
+ timestamp: Date.now(),
693
+ expiresAt: Date.now() + n
694
+ };
695
+ this.adapter.setItem(this.prefix + e, JSON.stringify(a));
696
+ } catch {
697
+ }
698
+ }
699
+ /**
700
+ * Delete a value from storage cache.
701
+ *
702
+ * @param {string} key - Cache key
703
+ */
704
+ async delete(e) {
705
+ try {
706
+ this.adapter.removeItem(this.prefix + e);
707
+ } catch {
708
+ }
709
+ }
710
+ /**
711
+ * Clear all entries from storage cache.
712
+ */
713
+ async clear() {
714
+ try {
715
+ this.adapter.clear();
716
+ } catch {
717
+ }
718
+ }
719
+ /**
720
+ * Invalidate entries matching a pattern.
721
+ *
722
+ * @param {string} pattern - Regex pattern to match keys
723
+ */
724
+ async invalidate(e) {
725
+ try {
726
+ const t = new RegExp(e), n = this.adapter.storage;
727
+ if (!n)
728
+ return;
729
+ const a = [];
730
+ for (let r = 0; r < n.length; r++) {
731
+ const o = n.key(r);
732
+ if (o && o.startsWith(this.prefix)) {
733
+ const l = o.substring(this.prefix.length);
734
+ t.test(l) && a.push(o);
735
+ }
736
+ }
737
+ for (const r of a)
738
+ this.adapter.removeItem(r);
739
+ } catch {
740
+ }
741
+ }
742
+ /**
743
+ * Check if an entry is expired.
744
+ *
745
+ * @private
746
+ * @param {CacheEntry} entry - Cache entry
747
+ * @returns {boolean} True if expired
748
+ */
749
+ isExpired(e) {
750
+ return Date.now() > e.expiresAt;
751
+ }
752
+ }
753
+ class O {
754
+ constructor(e) {
755
+ if (this.config = e, !e.enabled) {
756
+ this.memoryCache = new x(0, 0);
757
+ return;
758
+ }
759
+ if (this.memoryCache = new x(
760
+ e.ttl,
761
+ e.maxSize
762
+ ), e.storage && e.storage !== "memory")
763
+ try {
764
+ this.storageCache = new L(e.storage);
765
+ } catch {
766
+ this.storageCache = void 0;
767
+ }
768
+ }
769
+ /**
770
+ * Get a value from cache.
771
+ * Checks L1 (memory) first, then L2 (storage) if available.
772
+ *
773
+ * @param {string} key - Cache key
774
+ * @returns {Promise<T | null>} Cached value or null if not found
775
+ */
776
+ async get(e) {
777
+ if (!this.config.enabled)
778
+ return null;
779
+ const t = this.memoryCache.get(e);
780
+ if (t !== null)
781
+ return t;
782
+ if (this.storageCache) {
783
+ const s = await this.storageCache.get(e);
784
+ if (s !== null)
785
+ return this.memoryCache.set(e, s), s;
786
+ }
787
+ return null;
788
+ }
789
+ /**
790
+ * Set a value in cache.
791
+ * Writes to both L1 (memory) and L2 (storage) if available.
792
+ *
793
+ * @param {string} key - Cache key
794
+ * @param {T} value - Value to cache
795
+ * @param {CacheOptions} options - Optional cache options
796
+ */
797
+ async set(e, t, s) {
798
+ this.config.enabled && (this.memoryCache.set(e, t, s), this.storageCache && await this.storageCache.set(e, t, s));
799
+ }
800
+ /**
801
+ * Delete a value from cache.
802
+ * Removes from both L1 and L2.
803
+ *
804
+ * @param {string} key - Cache key
805
+ */
806
+ async delete(e) {
807
+ this.memoryCache.delete(e), this.storageCache && await this.storageCache.delete(e);
808
+ }
809
+ /**
810
+ * Clear all cache entries.
811
+ */
812
+ async clear() {
813
+ this.memoryCache.clear(), this.storageCache && await this.storageCache.clear();
814
+ }
815
+ /**
816
+ * Invalidate entries matching a pattern.
817
+ *
818
+ * @param {string} pattern - Regex pattern to match keys
819
+ */
820
+ async invalidate(e) {
821
+ if (!e) {
822
+ await this.clear();
823
+ return;
824
+ }
825
+ this.memoryCache.invalidate(e), this.storageCache && await this.storageCache.invalidate(e);
826
+ }
827
+ /**
828
+ * Check if a key exists in cache.
829
+ *
830
+ * @param {string} key - Cache key
831
+ * @returns {boolean} True if key exists and is not expired
832
+ */
833
+ has(e) {
834
+ return this.config.enabled ? this.memoryCache.has(e) : !1;
835
+ }
836
+ /**
837
+ * Get cache statistics.
838
+ *
839
+ * @returns {CacheStats} Cache statistics
840
+ */
841
+ getStats() {
842
+ return this.memoryCache.getStats();
843
+ }
844
+ /**
845
+ * Prefetch a value into cache.
846
+ * This is a convenience method for warming the cache.
847
+ *
848
+ * @param {string} key - Cache key
849
+ * @param {() => Promise<T>} fetcher - Function to fetch the value if not cached
850
+ */
851
+ async prefetch(e, t) {
852
+ const s = await this.get(e);
853
+ if (s !== null)
854
+ return s;
855
+ const n = await t();
856
+ return await this.set(e, n), n;
857
+ }
858
+ }
859
+ async function S(i) {
860
+ const {
861
+ apiKey: e,
862
+ baseUrl: t = "http://localhost:3000",
863
+ timeout: s = 1e4,
864
+ cache: n
865
+ } = i, a = new R(t, s);
866
+ await a.configureAuthorizationHeader({
867
+ "X-API-Key": e
868
+ });
869
+ const r = new O({
870
+ enabled: n?.enabled ?? !1,
871
+ ttl: n?.ttl ?? 6e4,
872
+ maxSize: n?.maxSize ?? 1e3,
873
+ storage: n?.storage,
874
+ staleWhileRevalidate: n?.staleWhileRevalidate ?? !1
875
+ });
876
+ return {
877
+ configs: new M(a, r),
878
+ discovery: new N(a),
879
+ cache: r
880
+ };
881
+ }
882
+ const _ = /* @__PURE__ */ new Set([
883
+ "break",
884
+ "case",
885
+ "catch",
886
+ "class",
887
+ "const",
888
+ "continue",
889
+ "debugger",
890
+ "default",
891
+ "delete",
892
+ "do",
893
+ "else",
894
+ "enum",
895
+ "export",
896
+ "extends",
897
+ "false",
898
+ "finally",
899
+ "for",
900
+ "function",
901
+ "if",
902
+ "import",
903
+ "in",
904
+ "instanceof",
905
+ "new",
906
+ "null",
907
+ "return",
908
+ "super",
909
+ "switch",
910
+ "this",
911
+ "throw",
912
+ "true",
913
+ "try",
914
+ "typeof",
915
+ "var",
916
+ "void",
917
+ "while",
918
+ "with"
919
+ ]);
920
+ function B(i) {
921
+ return i === "string" || i === "number" || i === "boolean";
922
+ }
923
+ class H {
924
+ constructor(e = T) {
925
+ this.namespace = e;
926
+ }
927
+ /**
928
+ * Generates the complete TypeScript declaration file content.
929
+ */
930
+ generate(e) {
931
+ const t = [
932
+ ...this.generateHeader(e),
933
+ "",
934
+ `export namespace ${this.namespace} {`
935
+ ];
936
+ for (const s of e.brands)
937
+ t.push(this.generateBrandNamespace(s)), t.push("");
938
+ return this.removeTrailingEmpty(t), t.push("}", "", ...this.generateHelperType(), ""), t.join(`
939
+ `);
940
+ }
941
+ // ─────────────────────────────────────────────────────────────────────────────
942
+ // Private: Header & Helper Generation
943
+ // ─────────────────────────────────────────────────────────────────────────────
944
+ generateHeader(e) {
945
+ return [
946
+ "/**",
947
+ " * DinoConfig Generated Types",
948
+ " *",
949
+ ` * Auto-generated by ${v} v${j}`,
950
+ ` * Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
951
+ ` * Company: ${e.company}`,
952
+ " *",
953
+ " * DO NOT EDIT THIS FILE MANUALLY",
954
+ " * Run the codegen command to regenerate:",
955
+ ` * npx ${v} codegen --api-key=<your-key> --output=<this-file>`,
956
+ " */"
957
+ ];
958
+ }
959
+ generateHelperType() {
960
+ return [
961
+ "/**",
962
+ " * Helper type to extract config type from namespace path",
963
+ " * @example",
964
+ ` * type Flags = ${this.namespace}.ConfigType<'MyBrand', 'FeatureFlags'>;`,
965
+ " */",
966
+ "export type ConfigType<",
967
+ ` Brand extends keyof typeof ${this.namespace},`,
968
+ ` Config extends keyof (typeof ${this.namespace})[Brand]`,
969
+ `> = (typeof ${this.namespace})[Brand][Config];`
970
+ ];
971
+ }
972
+ // ─────────────────────────────────────────────────────────────────────────────
973
+ // Private: Namespace & Interface Generation
974
+ // ─────────────────────────────────────────────────────────────────────────────
975
+ generateBrandNamespace(e) {
976
+ const t = this.sanitizeIdentifier(e.name), s = [
977
+ " /**",
978
+ ` * ${e.name} brand configurations`,
979
+ " * @namespace",
980
+ " */",
981
+ ` export namespace ${t} {`
982
+ ];
983
+ for (const n of e.configs)
984
+ s.push(this.generateConfigInterface(n), "");
985
+ return this.removeTrailingEmpty(s), s.push(" }"), s.join(`
986
+ `);
987
+ }
988
+ generateConfigInterface(e) {
989
+ const t = this.sanitizeIdentifier(e.name), s = [
990
+ " /**",
991
+ ` * ${e.name} configuration`
992
+ ];
993
+ e.keys.length > 0 && s.push(` * @property {${e.keys.length}} keys`), s.push(" */", ` export interface ${t} {`);
994
+ for (const n of e.keys)
995
+ s.push(...this.generateProperty(n));
996
+ return s.push(" }"), s.join(`
997
+ `);
998
+ }
999
+ generateProperty(e) {
1000
+ const t = this.sanitizeIdentifier(e.name), s = this.toTypeScriptType(e.type, e.value);
1001
+ return [` /** ${e.type} */`, ` ${t}: ${s};`];
1002
+ }
1003
+ // ─────────────────────────────────────────────────────────────────────────────
1004
+ // Private: Type Conversion & Utilities
1005
+ // ─────────────────────────────────────────────────────────────────────────────
1006
+ toTypeScriptType(e, t) {
1007
+ switch (e) {
1008
+ case "boolean":
1009
+ case "number":
1010
+ case "string":
1011
+ return e;
1012
+ case "array":
1013
+ return this.inferArrayType(t);
1014
+ case "object":
1015
+ return "Record<string, unknown>";
1016
+ default:
1017
+ return "unknown";
1018
+ }
1019
+ }
1020
+ inferArrayType(e) {
1021
+ if (Array.isArray(e) && e.length > 0) {
1022
+ const t = typeof e[0];
1023
+ if (B(t))
1024
+ return `${t}[]`;
1025
+ }
1026
+ return "unknown[]";
1027
+ }
1028
+ sanitizeIdentifier(e) {
1029
+ let t = e.replace(/[^a-zA-Z0-9_$]/g, "_");
1030
+ return /^[0-9]/.test(t) && (t = "_" + t), _.has(t.toLowerCase()) && (t += "_"), t;
1031
+ }
1032
+ removeTrailingEmpty(e) {
1033
+ for (; e.length > 0 && e[e.length - 1] === ""; )
1034
+ e.pop();
1035
+ }
1036
+ }
1037
+ const k = /* @__PURE__ */ new Set([
1038
+ "abstract",
1039
+ "assert",
1040
+ "boolean",
1041
+ "break",
1042
+ "byte",
1043
+ "case",
1044
+ "catch",
1045
+ "char",
1046
+ "class",
1047
+ "const",
1048
+ "continue",
1049
+ "default",
1050
+ "do",
1051
+ "double",
1052
+ "else",
1053
+ "enum",
1054
+ "extends",
1055
+ "final",
1056
+ "finally",
1057
+ "float",
1058
+ "for",
1059
+ "goto",
1060
+ "if",
1061
+ "implements",
1062
+ "import",
1063
+ "instanceof",
1064
+ "int",
1065
+ "interface",
1066
+ "long",
1067
+ "native",
1068
+ "new",
1069
+ "null",
1070
+ "package",
1071
+ "private",
1072
+ "protected",
1073
+ "public",
1074
+ "return",
1075
+ "short",
1076
+ "static",
1077
+ "strictfp",
1078
+ "super",
1079
+ "switch",
1080
+ "synchronized",
1081
+ "this",
1082
+ "throw",
1083
+ "throws",
1084
+ "transient",
1085
+ "try",
1086
+ "void",
1087
+ "volatile",
1088
+ "while"
1089
+ ]);
1090
+ function q(i) {
1091
+ return i === "string" || i === "number" || i === "boolean";
1092
+ }
1093
+ const J = "com.dinoconfig.sdk.generated";
1094
+ function K(i) {
1095
+ const e = i.replace(/\\/g, "/"), t = [
1096
+ "src/main/java/",
1097
+ "src/test/java/",
1098
+ "src/java/",
1099
+ "/java/"
1100
+ ];
1101
+ for (const s of t) {
1102
+ const n = e.indexOf(s);
1103
+ if (n !== -1) {
1104
+ const a = e.substring(n + s.length);
1105
+ if (a) {
1106
+ const r = a.replace(/\/+$/, "").replace(/\//g, ".");
1107
+ if (/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/i.test(r))
1108
+ return r;
1109
+ }
1110
+ }
1111
+ }
1112
+ }
1113
+ class G {
1114
+ /**
1115
+ * Creates a new JavaModelGenerator.
1116
+ *
1117
+ * @param options - Generator options
1118
+ */
1119
+ constructor(e = {}) {
1120
+ this.generatedByComment = `Generated by ${v} v${j}`, this.basePackage = e.basePackage ?? J;
1121
+ }
1122
+ /**
1123
+ * Gets the base package used by this generator.
1124
+ */
1125
+ getBasePackage() {
1126
+ return this.basePackage;
1127
+ }
1128
+ /**
1129
+ * Generates Java source files for each brand and config.
1130
+ * Returns a map of file paths (relative to output directory) to file contents.
1131
+ * The file paths only include brand subdirectories, not the base package path,
1132
+ * since the output directory already represents the base package location.
1133
+ */
1134
+ generate(e) {
1135
+ const t = /* @__PURE__ */ new Map();
1136
+ for (const s of e.brands) {
1137
+ const n = this.sanitizePackageName(s.name), a = `${this.basePackage}.${n}`;
1138
+ for (const r of s.configs) {
1139
+ const o = this.sanitizeClassName(r.name), l = `${n}/${o}.java`, c = this.generateConfigClass(a, o, r, s.name);
1140
+ t.set(l, c);
1141
+ }
1142
+ }
1143
+ return t;
1144
+ }
1145
+ // ─────────────────────────────────────────────────────────────────────────────
1146
+ // Private: Class Generation
1147
+ // ─────────────────────────────────────────────────────────────────────────────
1148
+ generateConfigClass(e, t, s, n) {
1149
+ const a = [
1150
+ this.generateHeader(s, n),
1151
+ "",
1152
+ `package ${e};`,
1153
+ "",
1154
+ "import com.fasterxml.jackson.annotation.JsonProperty;",
1155
+ "",
1156
+ "import java.util.Objects;"
1157
+ ], r = this.collectTypesUsed(s.keys);
1158
+ (r.has("List") || r.has("Map")) && (r.has("List") && a.push("import java.util.List;"), r.has("Map") && a.push("import java.util.Map;"), a.push("import java.util.Collections;")), a.push("", this.generateClassDeclaration(t, s));
1159
+ for (const o of s.keys)
1160
+ a.push(this.generateField(o));
1161
+ a.push("", this.generateDefaultConstructor(t, s.keys)), a.push("", this.generateFullConstructor(t, s.keys));
1162
+ for (const o of s.keys)
1163
+ a.push("", this.generateGetter(o));
1164
+ return a.push("", this.generateEqualsMethod(t, s.keys)), a.push("", this.generateHashCodeMethod(s.keys)), a.push("", this.generateToStringMethod(t, s.keys)), a.push("}"), a.join(`
1165
+ `);
1166
+ }
1167
+ generateHeader(e, t) {
1168
+ const s = (/* @__PURE__ */ new Date()).toISOString();
1169
+ return `/*
1170
+ * DinoConfig Java SDK - Generated Model
1171
+ * ${this.generatedByComment}
1172
+ * Generated at: ${s}
1173
+ *
1174
+ * DO NOT EDIT THIS FILE MANUALLY
1175
+ * This file is auto-generated from DinoConfig schema.
1176
+ *
1177
+ * Brand: ${t}
1178
+ * Config: ${e.name}
1179
+ * Version: ${e.version}
1180
+ */`;
1181
+ }
1182
+ generateClassDeclaration(e, t) {
1183
+ const s = [
1184
+ "/**",
1185
+ ` * Generated model for ${t.name} configuration.`
1186
+ ];
1187
+ return t.description && s.push(" *", ` * ${t.description.replace(/\n/g, " ")}`), s.push(" *", " * <p>This class represents the typed structure of the configuration.", " * All fields are immutable.", " */"), s.push(`public final class ${e} {`), s.join(`
1188
+ `);
1189
+ }
1190
+ generateField(e) {
1191
+ const t = this.sanitizeFieldName(e.name), s = this.toJavaType(e.type, e.value);
1192
+ return [
1193
+ " /**",
1194
+ ` * ${e.type} - ${e.name}`,
1195
+ " */",
1196
+ ` @JsonProperty("${e.name}")`,
1197
+ ` private final ${s} ${t};`
1198
+ ].join(`
1199
+ `);
1200
+ }
1201
+ generateDefaultConstructor(e, t) {
1202
+ const s = [
1203
+ " /**",
1204
+ " * Default constructor for Jackson deserialization.",
1205
+ " */",
1206
+ ` public ${e}() {`
1207
+ ];
1208
+ for (const n of t) {
1209
+ const a = this.sanitizeFieldName(n.name), r = this.toJavaType(n.type, n.value), o = this.getDefaultValue(r);
1210
+ s.push(` this.${a} = ${o};`);
1211
+ }
1212
+ return s.push(" }"), s.join(`
1213
+ `);
1214
+ }
1215
+ generateFullConstructor(e, t) {
1216
+ const s = [];
1217
+ for (const a of t) {
1218
+ const r = this.sanitizeFieldName(a.name), o = this.toJavaType(a.type, a.value);
1219
+ s.push(`${o} ${r}`);
1220
+ }
1221
+ const n = [
1222
+ " /**",
1223
+ ` * Creates a new ${e} instance.`,
1224
+ " *"
1225
+ ];
1226
+ for (const a of t) {
1227
+ const r = this.sanitizeFieldName(a.name);
1228
+ n.push(` * @param ${r} ${a.name} (${a.type})`);
1229
+ }
1230
+ n.push(" */", ` public ${e}(${s.join(", ")}) {`);
1231
+ for (const a of t) {
1232
+ const r = this.sanitizeFieldName(a.name), o = this.toJavaType(a.type, a.value);
1233
+ o.startsWith("List<") ? n.push(` this.${r} = ${r} != null ? Collections.unmodifiableList(${r}) : Collections.emptyList();`) : o.startsWith("Map<") ? n.push(` this.${r} = ${r} != null ? Collections.unmodifiableMap(${r}) : Collections.emptyMap();`) : n.push(` this.${r} = ${r};`);
1234
+ }
1235
+ return n.push(" }"), n.join(`
1236
+ `);
1237
+ }
1238
+ generateGetter(e) {
1239
+ const t = this.sanitizeFieldName(e.name), s = this.toGetterName(t), n = this.toJavaType(e.type, e.value);
1240
+ return [
1241
+ " /**",
1242
+ ` * Returns ${e.name}.`,
1243
+ " *",
1244
+ ` * @return ${e.name} (${e.type})`,
1245
+ " */",
1246
+ ` public ${n} ${s}() {`,
1247
+ ` return ${t};`,
1248
+ " }"
1249
+ ].join(`
1250
+ `);
1251
+ }
1252
+ generateEqualsMethod(e, t) {
1253
+ const s = [
1254
+ " @Override",
1255
+ " public boolean equals(Object o) {",
1256
+ " if (this == o) return true;",
1257
+ " if (o == null || getClass() != o.getClass()) return false;",
1258
+ ` ${e} that = (${e}) o;`,
1259
+ " return "
1260
+ ], n = [];
1261
+ for (const a of t) {
1262
+ const r = this.sanitizeFieldName(a.name);
1263
+ n.push(`Objects.equals(${r}, that.${r})`);
1264
+ }
1265
+ return s.push(" " + n.join(`
1266
+ && `)), s.push(" ;"), s.push(" }"), s.join(`
1267
+ `);
1268
+ }
1269
+ generateHashCodeMethod(e) {
1270
+ return [
1271
+ " @Override",
1272
+ " public int hashCode() {",
1273
+ ` return Objects.hash(${e.map((n) => this.sanitizeFieldName(n.name)).join(", ")});`,
1274
+ " }"
1275
+ ].join(`
1276
+ `);
1277
+ }
1278
+ generateToStringMethod(e, t) {
1279
+ if (t.length === 0)
1280
+ return ` @Override
1281
+ public String toString() {
1282
+ return "${e}{}";
1283
+ }`;
1284
+ const s = [
1285
+ " @Override",
1286
+ " public String toString() {",
1287
+ ` return "${e}{" +`
1288
+ ];
1289
+ for (let n = 0; n < t.length; n++) {
1290
+ const a = t[n], r = this.sanitizeFieldName(a.name);
1291
+ n === 0 ? s.push(` "${r}=" + ${r}`) : s.push(` + ", ${r}=" + ${r}`);
1292
+ }
1293
+ return s.push(" + '}';"), s.push(" }"), s.join(`
1294
+ `);
1295
+ }
1296
+ // ─────────────────────────────────────────────────────────────────────────────
1297
+ // Private: Type Conversion & Utilities
1298
+ // ─────────────────────────────────────────────────────────────────────────────
1299
+ toJavaType(e, t) {
1300
+ switch (e) {
1301
+ case "boolean":
1302
+ return "Boolean";
1303
+ case "number":
1304
+ return "Double";
1305
+ // Use Double for numbers to handle both int and float
1306
+ case "string":
1307
+ return "String";
1308
+ case "array":
1309
+ return this.inferArrayType(t);
1310
+ case "object":
1311
+ return "Map<String, Object>";
1312
+ default:
1313
+ return "Object";
1314
+ }
1315
+ }
1316
+ inferArrayType(e) {
1317
+ if (Array.isArray(e) && e.length > 0) {
1318
+ const t = typeof e[0];
1319
+ if (q(t))
1320
+ switch (t) {
1321
+ case "boolean":
1322
+ return "List<Boolean>";
1323
+ case "number":
1324
+ return "List<Double>";
1325
+ case "string":
1326
+ return "List<String>";
1327
+ }
1328
+ }
1329
+ return "List<Object>";
1330
+ }
1331
+ getDefaultValue(e) {
1332
+ switch (e) {
1333
+ case "Boolean":
1334
+ return "null";
1335
+ case "Double":
1336
+ case "Integer":
1337
+ case "Long":
1338
+ return "null";
1339
+ case "String":
1340
+ return "null";
1341
+ case "List<Boolean>":
1342
+ case "List<Double>":
1343
+ case "List<String>":
1344
+ case "List<Object>":
1345
+ return "Collections.emptyList()";
1346
+ case "Map<String, Object>":
1347
+ return "Collections.emptyMap()";
1348
+ default:
1349
+ return "null";
1350
+ }
1351
+ }
1352
+ sanitizeClassName(e) {
1353
+ let t = e.replace(/[^a-zA-Z0-9]/g, "");
1354
+ return t.length === 0 && (t = "Config"), /^[0-9]/.test(t) && (t = "Config" + t), t = t.charAt(0).toUpperCase() + t.slice(1), k.has(t.toLowerCase()) && (t += "Config"), t;
1355
+ }
1356
+ sanitizePackageName(e) {
1357
+ return e.toLowerCase().replace(/[^a-z0-9]/g, "").replace(/^([0-9])/, "_$1");
1358
+ }
1359
+ sanitizeFieldName(e) {
1360
+ let t = e.replace(/[^a-zA-Z0-9_$]/g, "_");
1361
+ return t.length === 0 && (t = "value"), /^[0-9]/.test(t) && (t = "_" + t), t = t.replace(/_([a-z])/g, (s, n) => n.toUpperCase()), t.charAt(0).toUpperCase() === t.charAt(0) && /^[a-z]/.test(e) && (t = t.charAt(0).toLowerCase() + t.slice(1)), k.has(t.toLowerCase()) && (t += "_"), t;
1362
+ }
1363
+ toGetterName(e) {
1364
+ return "get" + e.charAt(0).toUpperCase() + e.slice(1);
1365
+ }
1366
+ collectTypesUsed(e) {
1367
+ const t = /* @__PURE__ */ new Set();
1368
+ for (const s of e) {
1369
+ const n = this.toJavaType(s.type, s.value);
1370
+ n.startsWith("List<") && t.add("List"), n.startsWith("Map<") && t.add("Map");
1371
+ }
1372
+ return t;
1373
+ }
1374
+ getFilePath(e, t) {
1375
+ return `${e.replace(/\./g, "/")}/${t}.java`;
1376
+ }
1377
+ }
1378
+ const w = [
1379
+ {
1380
+ groupId: "com.fasterxml.jackson.core",
1381
+ artifactId: "jackson-databind",
1382
+ version: "2.16.1",
1383
+ scope: "implementation"
1384
+ },
1385
+ {
1386
+ groupId: "com.fasterxml.jackson.core",
1387
+ artifactId: "jackson-annotations",
1388
+ version: "2.16.1",
1389
+ scope: "implementation"
1390
+ }
1391
+ ];
1392
+ function V(i) {
1393
+ let e = p.resolve(i);
1394
+ const t = 10;
1395
+ let s = 0;
1396
+ for (; s < t; ) {
1397
+ const n = p.join(e, "build.gradle");
1398
+ if (f.existsSync(n))
1399
+ return { projectRoot: e, buildFile: n, projectType: "gradle" };
1400
+ const a = p.join(e, "build.gradle.kts");
1401
+ if (f.existsSync(a))
1402
+ return { projectRoot: e, buildFile: a, projectType: "gradle" };
1403
+ const r = p.join(e, "pom.xml");
1404
+ if (f.existsSync(r))
1405
+ return { projectRoot: e, buildFile: r, projectType: "maven" };
1406
+ const o = p.dirname(e);
1407
+ if (o === e)
1408
+ break;
1409
+ e = o, s++;
1410
+ }
1411
+ return null;
1412
+ }
1413
+ function W(i, e) {
1414
+ return [
1415
+ // Standard format: implementation 'group:artifact:version'
1416
+ new RegExp(`['"]${g(e.groupId)}:${g(e.artifactId)}:[^'"]+['"]`),
1417
+ // Without version (e.g., using BOM or version catalog)
1418
+ new RegExp(`['"]${g(e.groupId)}:${g(e.artifactId)}['"]`),
1419
+ // Gradle Kotlin DSL format
1420
+ new RegExp(`"${g(e.groupId)}:${g(e.artifactId)}:[^"]+"`)
1421
+ ].some((s) => s.test(i));
1422
+ }
1423
+ function Z(i, e) {
1424
+ const t = `<groupId>${g(e.groupId)}</groupId>`, s = `<artifactId>${g(e.artifactId)}</artifactId>`;
1425
+ return i.includes(e.groupId) && i.includes(e.artifactId) && new RegExp(t).test(i) && new RegExp(s).test(i);
1426
+ }
1427
+ function g(i) {
1428
+ return i.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1429
+ }
1430
+ function X(i, e, t) {
1431
+ const s = [], n = [];
1432
+ for (const a of e) {
1433
+ const r = `${a.groupId}:${a.artifactId}`;
1434
+ if (W(i, a)) {
1435
+ n.push(r);
1436
+ continue;
1437
+ }
1438
+ const l = /dependencies\s*\{/.exec(i);
1439
+ if (l) {
1440
+ const c = l.index + l[0].length, u = t ? '"' : "'", h = `
1441
+ ${a.scope}(${u}${a.groupId}:${a.artifactId}:${a.version}${u})`;
1442
+ i = i.slice(0, c) + h + i.slice(c), s.push(r);
1443
+ }
1444
+ }
1445
+ return { content: i, added: s, existing: n };
1446
+ }
1447
+ function Y(i, e) {
1448
+ const t = [], s = [];
1449
+ for (const n of e) {
1450
+ const a = `${n.groupId}:${n.artifactId}`;
1451
+ if (Z(i, n)) {
1452
+ s.push(a);
1453
+ continue;
1454
+ }
1455
+ const o = /<dependencies>/.exec(i);
1456
+ if (o) {
1457
+ const l = o.index + o[0].length, c = `
1458
+ <dependency>
1459
+ <groupId>${n.groupId}</groupId>
1460
+ <artifactId>${n.artifactId}</artifactId>
1461
+ <version>${n.version}</version>
1462
+ </dependency>`;
1463
+ i = i.slice(0, l) + c + i.slice(l), t.push(a);
1464
+ } else {
1465
+ const c = /<\/project>/.exec(i);
1466
+ if (c) {
1467
+ const u = c.index, h = `
1468
+ <dependencies>
1469
+ <dependency>
1470
+ <groupId>${n.groupId}</groupId>
1471
+ <artifactId>${n.artifactId}</artifactId>
1472
+ <version>${n.version}</version>
1473
+ </dependency>
1474
+ </dependencies>
1475
+ `;
1476
+ i = i.slice(0, u) + h + i.slice(u), t.push(a);
1477
+ }
1478
+ }
1479
+ }
1480
+ return { content: i, added: t, existing: s };
1481
+ }
1482
+ function Q(i, e = !1) {
1483
+ const t = [], s = V(i);
1484
+ if (!s)
1485
+ return {
1486
+ success: !1,
1487
+ projectType: "unknown",
1488
+ error: "Could not find build.gradle, build.gradle.kts, or pom.xml in the project hierarchy. Please manually add the Jackson dependency to your project.",
1489
+ warnings: [
1490
+ "For Gradle: implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1'",
1491
+ "For Maven: <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.16.1</version></dependency>"
1492
+ ]
1493
+ };
1494
+ const { projectRoot: n, buildFile: a, projectType: r } = s, o = a.endsWith(".kts");
1495
+ try {
1496
+ const l = f.readFileSync(a, "utf-8");
1497
+ let c;
1498
+ return r === "gradle" ? c = X(l, w, o) : c = Y(l, w), c.added.length > 0 && !e && f.writeFileSync(a, c.content, "utf-8"), c.existing.length > 0 && t.push(`Already present: ${c.existing.join(", ")}`), {
1499
+ success: !0,
1500
+ projectType: r,
1501
+ buildFilePath: a,
1502
+ addedDependencies: c.added,
1503
+ existingDependencies: c.existing,
1504
+ warnings: t.length > 0 ? t : void 0
1505
+ };
1506
+ } catch (l) {
1507
+ return {
1508
+ success: !1,
1509
+ projectType: r,
1510
+ buildFilePath: a,
1511
+ error: l instanceof Error ? l.message : "Failed to update build file"
1512
+ };
1513
+ }
1514
+ }
1515
+ function te() {
1516
+ return [...w];
1517
+ }
1518
+ function se(i, e = w) {
1519
+ return i === "gradle" ? e.map(
1520
+ (t) => `implementation '${t.groupId}:${t.artifactId}:${t.version}'`
1521
+ ) : e.map(
1522
+ (t) => `<dependency>
1523
+ <groupId>${t.groupId}</groupId>
1524
+ <artifactId>${t.artifactId}</artifactId>
1525
+ <version>${t.version}</version>
1526
+ </dependency>`
1527
+ );
1528
+ }
1529
+ function E(i) {
1530
+ const e = p.dirname(i);
1531
+ f.existsSync(e) || f.mkdirSync(e, { recursive: !0 });
1532
+ }
1533
+ function D(i) {
1534
+ let e = 0, t = 0;
1535
+ for (const s of i) {
1536
+ e += s.configs.length;
1537
+ for (const n of s.configs)
1538
+ t += n.keys.length;
1539
+ }
1540
+ return { configs: e, keys: t };
1541
+ }
1542
+ async function ne(i) {
1543
+ const {
1544
+ apiKey: e,
1545
+ baseUrl: t = A,
1546
+ output: s = z,
1547
+ namespace: n = T
1548
+ } = i;
1549
+ try {
1550
+ const r = await (await S({ apiKey: e, baseUrl: t })).discovery.introspect();
1551
+ if (!r.success || !r.data)
1552
+ return {
1553
+ success: !1,
1554
+ error: r.message || "Failed to fetch introspection data"
1555
+ };
1556
+ const { brands: o } = r.data, { configs: l, keys: c } = D(o), h = new H(n).generate(r.data), d = p.resolve(process.cwd(), s);
1557
+ return E(d), f.writeFileSync(d, h, "utf-8"), {
1558
+ success: !0,
1559
+ outputPath: d,
1560
+ content: h,
1561
+ stats: {
1562
+ brands: o.length,
1563
+ configs: l,
1564
+ keys: c
1565
+ }
1566
+ };
1567
+ } catch (a) {
1568
+ return {
1569
+ success: !1,
1570
+ error: a instanceof Error ? a.message : "Unknown error"
1571
+ };
1572
+ }
1573
+ }
1574
+ async function ae(i) {
1575
+ const {
1576
+ apiKey: e,
1577
+ baseUrl: t = A,
1578
+ output: s = "./libs/dinoconfig-java-sdk/lib/src/main/java/com/dinoconfig/sdk/generated",
1579
+ skipDependencyUpdate: n = !1
1580
+ } = i;
1581
+ try {
1582
+ const r = await (await S({ apiKey: e, baseUrl: t })).discovery.introspect();
1583
+ if (!r.success || !r.data)
1584
+ return {
1585
+ success: !1,
1586
+ error: r.message || "Failed to fetch introspection data"
1587
+ };
1588
+ const { brands: o } = r.data, { configs: l, keys: c } = D(o), u = p.resolve(process.cwd(), s), h = i.package ?? K(u), d = new G({ basePackage: h }), m = d.generate(r.data), y = [];
1589
+ for (const [P, F] of m.entries()) {
1590
+ const C = p.join(u, P);
1591
+ E(C), f.writeFileSync(C, F, "utf-8"), y.push(C);
1592
+ }
1593
+ let b;
1594
+ return n || (b = Q(u)), {
1595
+ success: !0,
1596
+ outputDir: u,
1597
+ generatedFiles: y,
1598
+ stats: {
1599
+ brands: o.length,
1600
+ configs: l,
1601
+ keys: c
1602
+ },
1603
+ dependencyUpdate: b,
1604
+ basePackage: d.getBasePackage()
1605
+ };
1606
+ } catch (a) {
1607
+ return {
1608
+ success: !1,
1609
+ error: a instanceof Error ? a.message : "Unknown error"
1610
+ };
1611
+ }
1612
+ }
1613
+ export {
1614
+ G as J,
1615
+ H as T,
1616
+ ne as a,
1617
+ te as b,
1618
+ K as d,
1619
+ se as f,
1620
+ ae as g,
1621
+ Q as u
1622
+ };