@uniforge/core 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/auth/index.d.cts +165 -0
  2. package/dist/auth/index.d.ts +165 -0
  3. package/dist/auth/index.js +443 -0
  4. package/dist/auth/index.js.map +1 -0
  5. package/dist/auth/index.mjs +406 -0
  6. package/dist/auth/index.mjs.map +1 -0
  7. package/dist/billing/index.d.cts +34 -0
  8. package/dist/billing/index.d.ts +34 -0
  9. package/dist/billing/index.js +254 -0
  10. package/dist/billing/index.js.map +1 -0
  11. package/dist/billing/index.mjs +225 -0
  12. package/dist/billing/index.mjs.map +1 -0
  13. package/dist/config/index.d.cts +12 -0
  14. package/dist/config/index.d.ts +12 -0
  15. package/dist/config/index.js +186 -0
  16. package/dist/config/index.js.map +1 -0
  17. package/dist/config/index.mjs +156 -0
  18. package/dist/config/index.mjs.map +1 -0
  19. package/dist/database/index.d.cts +33 -0
  20. package/dist/database/index.d.ts +33 -0
  21. package/dist/database/index.js +127 -0
  22. package/dist/database/index.js.map +1 -0
  23. package/dist/database/index.mjs +95 -0
  24. package/dist/database/index.mjs.map +1 -0
  25. package/dist/graphql/index.d.cts +36 -0
  26. package/dist/graphql/index.d.ts +36 -0
  27. package/dist/graphql/index.js +209 -0
  28. package/dist/graphql/index.js.map +1 -0
  29. package/dist/graphql/index.mjs +179 -0
  30. package/dist/graphql/index.mjs.map +1 -0
  31. package/dist/index.d.cts +16 -0
  32. package/dist/index.d.ts +16 -0
  33. package/dist/index.js +36 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/index.mjs +10 -0
  36. package/dist/index.mjs.map +1 -0
  37. package/dist/multi-store/index.d.cts +11 -0
  38. package/dist/multi-store/index.d.ts +11 -0
  39. package/dist/multi-store/index.js +473 -0
  40. package/dist/multi-store/index.js.map +1 -0
  41. package/dist/multi-store/index.mjs +447 -0
  42. package/dist/multi-store/index.mjs.map +1 -0
  43. package/dist/multi-tenant/index.d.cts +23 -0
  44. package/dist/multi-tenant/index.d.ts +23 -0
  45. package/dist/multi-tenant/index.js +69 -0
  46. package/dist/multi-tenant/index.js.map +1 -0
  47. package/dist/multi-tenant/index.mjs +41 -0
  48. package/dist/multi-tenant/index.mjs.map +1 -0
  49. package/dist/performance/index.d.cts +34 -0
  50. package/dist/performance/index.d.ts +34 -0
  51. package/dist/performance/index.js +319 -0
  52. package/dist/performance/index.js.map +1 -0
  53. package/dist/performance/index.mjs +290 -0
  54. package/dist/performance/index.mjs.map +1 -0
  55. package/dist/platform/index.d.cts +25 -0
  56. package/dist/platform/index.d.ts +25 -0
  57. package/dist/platform/index.js +91 -0
  58. package/dist/platform/index.js.map +1 -0
  59. package/dist/platform/index.mjs +62 -0
  60. package/dist/platform/index.mjs.map +1 -0
  61. package/dist/rbac/index.d.cts +24 -0
  62. package/dist/rbac/index.d.ts +24 -0
  63. package/dist/rbac/index.js +267 -0
  64. package/dist/rbac/index.js.map +1 -0
  65. package/dist/rbac/index.mjs +236 -0
  66. package/dist/rbac/index.mjs.map +1 -0
  67. package/dist/schema-CM7mHj_H.d.cts +53 -0
  68. package/dist/schema-CM7mHj_H.d.ts +53 -0
  69. package/dist/security/index.d.cts +47 -0
  70. package/dist/security/index.d.ts +47 -0
  71. package/dist/security/index.js +505 -0
  72. package/dist/security/index.js.map +1 -0
  73. package/dist/security/index.mjs +474 -0
  74. package/dist/security/index.mjs.map +1 -0
  75. package/dist/session-storage/index.d.cts +70 -0
  76. package/dist/session-storage/index.d.ts +70 -0
  77. package/dist/session-storage/index.js +271 -0
  78. package/dist/session-storage/index.js.map +1 -0
  79. package/dist/session-storage/index.mjs +242 -0
  80. package/dist/session-storage/index.mjs.map +1 -0
  81. package/dist/webhooks/index.d.cts +89 -0
  82. package/dist/webhooks/index.d.ts +89 -0
  83. package/dist/webhooks/index.js +380 -0
  84. package/dist/webhooks/index.js.map +1 -0
  85. package/dist/webhooks/index.mjs +348 -0
  86. package/dist/webhooks/index.mjs.map +1 -0
  87. package/package.json +119 -0
@@ -0,0 +1,34 @@
1
+ import { CacheManagerConfig, CacheManager, QueryCostConfig, QueryCostTracker, BatchConfig, QueryBatcher } from '@uniforge/platform-core/performance';
2
+
3
+ /**
4
+ * In-memory cache manager implementation.
5
+ *
6
+ * Provides TTL-based caching with strategy-based TTL matching,
7
+ * LRU-style eviction, and performance metrics tracking.
8
+ */
9
+
10
+ /** Create an in-memory CacheManager. */
11
+ declare function createCacheManager(config: CacheManagerConfig): CacheManager;
12
+
13
+ /**
14
+ * Query cost tracker implementation.
15
+ *
16
+ * Tracks GraphQL query costs within a sliding time window
17
+ * and provides budget monitoring to prevent API throttling.
18
+ */
19
+
20
+ /** Create a QueryCostTracker that monitors query costs within a sliding window. */
21
+ declare function createQueryCostTracker(config: QueryCostConfig): QueryCostTracker;
22
+
23
+ /**
24
+ * Query batcher implementation.
25
+ *
26
+ * Collects individual queries into batches and executes them together,
27
+ * reducing the number of API round-trips. Batches are flushed either
28
+ * when they reach the configured size or after a delay timeout.
29
+ */
30
+
31
+ /** Create a QueryBatcher that groups queries and executes them in batches. */
32
+ declare function createQueryBatcher<TQuery, TResult>(config: BatchConfig, executor: (queries: TQuery[]) => Promise<TResult[]>): QueryBatcher<TQuery, TResult>;
33
+
34
+ export { createCacheManager, createQueryBatcher, createQueryCostTracker };
@@ -0,0 +1,34 @@
1
+ import { CacheManagerConfig, CacheManager, QueryCostConfig, QueryCostTracker, BatchConfig, QueryBatcher } from '@uniforge/platform-core/performance';
2
+
3
+ /**
4
+ * In-memory cache manager implementation.
5
+ *
6
+ * Provides TTL-based caching with strategy-based TTL matching,
7
+ * LRU-style eviction, and performance metrics tracking.
8
+ */
9
+
10
+ /** Create an in-memory CacheManager. */
11
+ declare function createCacheManager(config: CacheManagerConfig): CacheManager;
12
+
13
+ /**
14
+ * Query cost tracker implementation.
15
+ *
16
+ * Tracks GraphQL query costs within a sliding time window
17
+ * and provides budget monitoring to prevent API throttling.
18
+ */
19
+
20
+ /** Create a QueryCostTracker that monitors query costs within a sliding window. */
21
+ declare function createQueryCostTracker(config: QueryCostConfig): QueryCostTracker;
22
+
23
+ /**
24
+ * Query batcher implementation.
25
+ *
26
+ * Collects individual queries into batches and executes them together,
27
+ * reducing the number of API round-trips. Batches are flushed either
28
+ * when they reach the configured size or after a delay timeout.
29
+ */
30
+
31
+ /** Create a QueryBatcher that groups queries and executes them in batches. */
32
+ declare function createQueryBatcher<TQuery, TResult>(config: BatchConfig, executor: (queries: TQuery[]) => Promise<TResult[]>): QueryBatcher<TQuery, TResult>;
33
+
34
+ export { createCacheManager, createQueryBatcher, createQueryCostTracker };
@@ -0,0 +1,319 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/performance/index.ts
21
+ var performance_exports = {};
22
+ __export(performance_exports, {
23
+ createCacheManager: () => createCacheManager,
24
+ createQueryBatcher: () => createQueryBatcher,
25
+ createQueryCostTracker: () => createQueryCostTracker
26
+ });
27
+ module.exports = __toCommonJS(performance_exports);
28
+
29
+ // src/performance/cache-manager.ts
30
+ function createCacheManager(config) {
31
+ const store = /* @__PURE__ */ new Map();
32
+ let hits = 0;
33
+ let misses = 0;
34
+ let evictions = 0;
35
+ function resolveTTL(key, ttlOverride) {
36
+ if (ttlOverride !== void 0) return ttlOverride;
37
+ if (config.strategies !== void 0) {
38
+ for (const strategy of config.strategies) {
39
+ if (key.startsWith(strategy.pattern)) {
40
+ return strategy.ttl;
41
+ }
42
+ }
43
+ }
44
+ return config.defaultTTL;
45
+ }
46
+ function prefixKey(key) {
47
+ if (config.keyPrefix !== void 0) {
48
+ return `${config.keyPrefix}:${key}`;
49
+ }
50
+ return key;
51
+ }
52
+ function isExpired(entry) {
53
+ return Date.now() >= entry.expiresAt;
54
+ }
55
+ function evictOldest() {
56
+ let oldestKey;
57
+ let oldestTime = Infinity;
58
+ for (const [k, v] of store) {
59
+ if (v.createdAt < oldestTime) {
60
+ oldestTime = v.createdAt;
61
+ oldestKey = k;
62
+ }
63
+ }
64
+ if (oldestKey !== void 0) {
65
+ store.delete(oldestKey);
66
+ evictions++;
67
+ }
68
+ }
69
+ const manager = {
70
+ config,
71
+ async get(key) {
72
+ const fullKey = prefixKey(key);
73
+ const entry = store.get(fullKey);
74
+ if (!entry) {
75
+ misses++;
76
+ return void 0;
77
+ }
78
+ if (isExpired(entry)) {
79
+ store.delete(fullKey);
80
+ misses++;
81
+ return void 0;
82
+ }
83
+ entry.hits++;
84
+ hits++;
85
+ return {
86
+ key: entry.key,
87
+ value: entry.value,
88
+ createdAt: entry.createdAt,
89
+ expiresAt: entry.expiresAt,
90
+ hits: entry.hits
91
+ };
92
+ },
93
+ async set(key, value, ttl) {
94
+ const fullKey = prefixKey(key);
95
+ const resolvedTTL = resolveTTL(key, ttl);
96
+ const now = Date.now();
97
+ if (!store.has(fullKey) && store.size >= config.maxEntries) {
98
+ evictOldest();
99
+ }
100
+ const entry = {
101
+ key,
102
+ value,
103
+ createdAt: now,
104
+ expiresAt: now + resolvedTTL,
105
+ hits: 0
106
+ };
107
+ store.set(fullKey, entry);
108
+ },
109
+ async delete(key) {
110
+ const fullKey = prefixKey(key);
111
+ return store.delete(fullKey);
112
+ },
113
+ async invalidate(pattern) {
114
+ let count = 0;
115
+ const prefixed = prefixKey(pattern);
116
+ for (const key of [...store.keys()]) {
117
+ if (key.startsWith(prefixed)) {
118
+ store.delete(key);
119
+ count++;
120
+ }
121
+ }
122
+ return count;
123
+ },
124
+ async has(key) {
125
+ const fullKey = prefixKey(key);
126
+ const entry = store.get(fullKey);
127
+ if (!entry) return false;
128
+ if (isExpired(entry)) {
129
+ store.delete(fullKey);
130
+ return false;
131
+ }
132
+ return true;
133
+ },
134
+ async warm(entries) {
135
+ for (const entry of entries) {
136
+ await manager.set(entry.key, entry.value, entry.ttl);
137
+ }
138
+ },
139
+ getMetrics() {
140
+ const total = hits + misses;
141
+ return {
142
+ hits,
143
+ misses,
144
+ hitRate: total === 0 ? 0 : hits / total,
145
+ totalEntries: store.size,
146
+ evictions
147
+ };
148
+ },
149
+ resetMetrics() {
150
+ hits = 0;
151
+ misses = 0;
152
+ evictions = 0;
153
+ },
154
+ async clear() {
155
+ store.clear();
156
+ }
157
+ };
158
+ return manager;
159
+ }
160
+
161
+ // src/performance/query-cost-tracker.ts
162
+ function createQueryCostTracker(config) {
163
+ let entries = [];
164
+ function pruneExpired() {
165
+ const cutoff = Date.now() - config.trackingWindowMs;
166
+ entries = entries.filter((e) => e.timestamp >= cutoff);
167
+ }
168
+ function computeCostPerSecond() {
169
+ if (entries.length === 0) return 0;
170
+ let totalCost = 0;
171
+ for (const entry of entries) {
172
+ totalCost += entry.actualCost;
173
+ }
174
+ const windowSeconds = config.trackingWindowMs / 1e3;
175
+ return totalCost / windowSeconds;
176
+ }
177
+ const tracker = {
178
+ config,
179
+ track(query, actualCost, requestedCost) {
180
+ entries.push({
181
+ query,
182
+ actualCost,
183
+ requestedCost,
184
+ timestamp: Date.now()
185
+ });
186
+ pruneExpired();
187
+ },
188
+ getReport() {
189
+ pruneExpired();
190
+ if (entries.length === 0) {
191
+ return {
192
+ totalCost: 0,
193
+ averageCost: 0,
194
+ maxCost: 0,
195
+ queryCount: 0,
196
+ costPerSecond: 0,
197
+ topQueries: [],
198
+ isOverBudget: false
199
+ };
200
+ }
201
+ let totalCost = 0;
202
+ let maxCost = 0;
203
+ for (const entry of entries) {
204
+ totalCost += entry.actualCost;
205
+ if (entry.actualCost > maxCost) {
206
+ maxCost = entry.actualCost;
207
+ }
208
+ }
209
+ const queryCount = entries.length;
210
+ const averageCost = totalCost / queryCount;
211
+ const costPerSecond = computeCostPerSecond();
212
+ const topQueries = [...entries].sort((a, b) => b.actualCost - a.actualCost).slice(0, 10);
213
+ return {
214
+ totalCost,
215
+ averageCost,
216
+ maxCost,
217
+ queryCount,
218
+ costPerSecond,
219
+ topQueries,
220
+ isOverBudget: costPerSecond > config.maxCostPerSecond
221
+ };
222
+ },
223
+ isWithinBudget() {
224
+ pruneExpired();
225
+ return computeCostPerSecond() <= config.maxCostPerSecond;
226
+ },
227
+ getCostPerSecond() {
228
+ pruneExpired();
229
+ return computeCostPerSecond();
230
+ },
231
+ reset() {
232
+ entries = [];
233
+ }
234
+ };
235
+ return tracker;
236
+ }
237
+
238
+ // src/performance/query-batcher.ts
239
+ function createQueryBatcher(config, executor) {
240
+ let pending = [];
241
+ let timer;
242
+ function scheduleFlush() {
243
+ if (timer !== void 0) return;
244
+ const delay = config.maxDelayMs !== void 0 ? Math.min(config.delayMs, config.maxDelayMs) : config.delayMs;
245
+ timer = setTimeout(() => {
246
+ timer = void 0;
247
+ void batcher.flush();
248
+ }, delay);
249
+ }
250
+ function clearTimer() {
251
+ if (timer !== void 0) {
252
+ clearTimeout(timer);
253
+ timer = void 0;
254
+ }
255
+ }
256
+ const batcher = {
257
+ config,
258
+ add(query) {
259
+ return new Promise((resolve, reject) => {
260
+ pending.push({ query, resolve, reject });
261
+ if (pending.length >= config.maxBatchSize) {
262
+ clearTimer();
263
+ void batcher.flush();
264
+ } else {
265
+ scheduleFlush();
266
+ }
267
+ });
268
+ },
269
+ async flush() {
270
+ clearTimer();
271
+ const batch = pending;
272
+ pending = [];
273
+ if (batch.length === 0) {
274
+ return {
275
+ results: [],
276
+ batchSize: 0,
277
+ executionTimeMs: 0
278
+ };
279
+ }
280
+ const queries = batch.map((p) => p.query);
281
+ const startTime = Date.now();
282
+ try {
283
+ const results = await executor(queries);
284
+ const executionTimeMs = Date.now() - startTime;
285
+ for (let i = 0; i < batch.length; i++) {
286
+ const item = batch[i];
287
+ if (item) {
288
+ item.resolve(results[i]);
289
+ }
290
+ }
291
+ return {
292
+ results,
293
+ batchSize: batch.length,
294
+ executionTimeMs
295
+ };
296
+ } catch (error) {
297
+ for (const item of batch) {
298
+ item.reject(error);
299
+ }
300
+ return {
301
+ results: [],
302
+ batchSize: batch.length,
303
+ executionTimeMs: Date.now() - startTime
304
+ };
305
+ }
306
+ },
307
+ pending() {
308
+ return pending.length;
309
+ }
310
+ };
311
+ return batcher;
312
+ }
313
+ // Annotate the CommonJS export names for ESM import in node:
314
+ 0 && (module.exports = {
315
+ createCacheManager,
316
+ createQueryBatcher,
317
+ createQueryCostTracker
318
+ });
319
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/performance/index.ts","../../src/performance/cache-manager.ts","../../src/performance/query-cost-tracker.ts","../../src/performance/query-batcher.ts"],"sourcesContent":["/**\n * @uniforge/core/performance\n *\n * Core performance utilities: cache management, query cost tracking,\n * and query batching.\n */\n\nexport { createCacheManager } from './cache-manager.js';\nexport { createQueryCostTracker } from './query-cost-tracker.js';\nexport { createQueryBatcher } from './query-batcher.js';\n","/**\n * In-memory cache manager implementation.\n *\n * Provides TTL-based caching with strategy-based TTL matching,\n * LRU-style eviction, and performance metrics tracking.\n */\n\nimport type {\n CacheManagerConfig,\n CacheEntry,\n CacheMetrics,\n} from '@uniforge/platform-core/performance';\nimport type { CacheManager } from '@uniforge/platform-core/performance';\n\ninterface InternalEntry<T = unknown> {\n key: string;\n value: T;\n createdAt: number;\n expiresAt: number;\n hits: number;\n}\n\n/** Create an in-memory CacheManager. */\nexport function createCacheManager(config: CacheManagerConfig): CacheManager {\n const store = new Map<string, InternalEntry>();\n\n let hits = 0;\n let misses = 0;\n let evictions = 0;\n\n function resolveTTL(key: string, ttlOverride?: number): number {\n if (ttlOverride !== undefined) return ttlOverride;\n\n if (config.strategies !== undefined) {\n for (const strategy of config.strategies) {\n if (key.startsWith(strategy.pattern)) {\n return strategy.ttl;\n }\n }\n }\n\n return config.defaultTTL;\n }\n\n function prefixKey(key: string): string {\n if (config.keyPrefix !== undefined) {\n return `${config.keyPrefix}:${key}`;\n }\n return key;\n }\n\n function isExpired(entry: InternalEntry): boolean {\n return Date.now() >= entry.expiresAt;\n }\n\n function evictOldest(): void {\n // Evict the oldest entry by createdAt\n let oldestKey: string | undefined;\n let oldestTime = Infinity;\n\n for (const [k, v] of store) {\n if (v.createdAt < oldestTime) {\n oldestTime = v.createdAt;\n oldestKey = k;\n }\n }\n\n if (oldestKey !== undefined) {\n store.delete(oldestKey);\n evictions++;\n }\n }\n\n const manager: CacheManager = {\n config,\n\n async get<T = unknown>(key: string): Promise<CacheEntry<T> | undefined> {\n const fullKey = prefixKey(key);\n const entry = store.get(fullKey) as InternalEntry<T> | undefined;\n\n if (!entry) {\n misses++;\n return undefined;\n }\n\n if (isExpired(entry)) {\n store.delete(fullKey);\n misses++;\n return undefined;\n }\n\n entry.hits++;\n hits++;\n\n return {\n key: entry.key,\n value: entry.value,\n createdAt: entry.createdAt,\n expiresAt: entry.expiresAt,\n hits: entry.hits,\n };\n },\n\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n const fullKey = prefixKey(key);\n const resolvedTTL = resolveTTL(key, ttl);\n const now = Date.now();\n\n // If the key already exists, update in place (no eviction needed)\n if (!store.has(fullKey) && store.size >= config.maxEntries) {\n evictOldest();\n }\n\n const entry: InternalEntry<T> = {\n key,\n value,\n createdAt: now,\n expiresAt: now + resolvedTTL,\n hits: 0,\n };\n\n store.set(fullKey, entry as InternalEntry);\n },\n\n async delete(key: string): Promise<boolean> {\n const fullKey = prefixKey(key);\n return store.delete(fullKey);\n },\n\n async invalidate(pattern: string): Promise<number> {\n let count = 0;\n const prefixed = prefixKey(pattern);\n\n for (const key of [...store.keys()]) {\n if (key.startsWith(prefixed)) {\n store.delete(key);\n count++;\n }\n }\n\n return count;\n },\n\n async has(key: string): Promise<boolean> {\n const fullKey = prefixKey(key);\n const entry = store.get(fullKey);\n\n if (!entry) return false;\n\n if (isExpired(entry)) {\n store.delete(fullKey);\n return false;\n }\n\n return true;\n },\n\n async warm(entries: Array<{ key: string; value: unknown; ttl?: number }>): Promise<void> {\n for (const entry of entries) {\n await manager.set(entry.key, entry.value, entry.ttl);\n }\n },\n\n getMetrics(): CacheMetrics {\n const total = hits + misses;\n return {\n hits,\n misses,\n hitRate: total === 0 ? 0 : hits / total,\n totalEntries: store.size,\n evictions,\n };\n },\n\n resetMetrics(): void {\n hits = 0;\n misses = 0;\n evictions = 0;\n },\n\n async clear(): Promise<void> {\n store.clear();\n },\n };\n\n return manager;\n}\n","/**\n * Query cost tracker implementation.\n *\n * Tracks GraphQL query costs within a sliding time window\n * and provides budget monitoring to prevent API throttling.\n */\n\nimport type {\n QueryCostConfig,\n QueryCostEntry,\n QueryCostReport,\n} from '@uniforge/platform-core/performance';\nimport type { QueryCostTracker } from '@uniforge/platform-core/performance';\n\n/** Create a QueryCostTracker that monitors query costs within a sliding window. */\nexport function createQueryCostTracker(config: QueryCostConfig): QueryCostTracker {\n let entries: QueryCostEntry[] = [];\n\n function pruneExpired(): void {\n const cutoff = Date.now() - config.trackingWindowMs;\n entries = entries.filter((e) => e.timestamp >= cutoff);\n }\n\n function computeCostPerSecond(): number {\n if (entries.length === 0) return 0;\n\n let totalCost = 0;\n for (const entry of entries) {\n totalCost += entry.actualCost;\n }\n\n const windowSeconds = config.trackingWindowMs / 1000;\n return totalCost / windowSeconds;\n }\n\n const tracker: QueryCostTracker = {\n config,\n\n track(query: string, actualCost: number, requestedCost: number): void {\n entries.push({\n query,\n actualCost,\n requestedCost,\n timestamp: Date.now(),\n });\n\n pruneExpired();\n },\n\n getReport(): QueryCostReport {\n pruneExpired();\n\n if (entries.length === 0) {\n return {\n totalCost: 0,\n averageCost: 0,\n maxCost: 0,\n queryCount: 0,\n costPerSecond: 0,\n topQueries: [],\n isOverBudget: false,\n };\n }\n\n let totalCost = 0;\n let maxCost = 0;\n\n for (const entry of entries) {\n totalCost += entry.actualCost;\n if (entry.actualCost > maxCost) {\n maxCost = entry.actualCost;\n }\n }\n\n const queryCount = entries.length;\n const averageCost = totalCost / queryCount;\n const costPerSecond = computeCostPerSecond();\n\n // Top queries sorted by actualCost descending, take top 10\n const topQueries = [...entries]\n .sort((a, b) => b.actualCost - a.actualCost)\n .slice(0, 10);\n\n return {\n totalCost,\n averageCost,\n maxCost,\n queryCount,\n costPerSecond,\n topQueries,\n isOverBudget: costPerSecond > config.maxCostPerSecond,\n };\n },\n\n isWithinBudget(): boolean {\n pruneExpired();\n return computeCostPerSecond() <= config.maxCostPerSecond;\n },\n\n getCostPerSecond(): number {\n pruneExpired();\n return computeCostPerSecond();\n },\n\n reset(): void {\n entries = [];\n },\n };\n\n return tracker;\n}\n","/**\n * Query batcher implementation.\n *\n * Collects individual queries into batches and executes them together,\n * reducing the number of API round-trips. Batches are flushed either\n * when they reach the configured size or after a delay timeout.\n */\n\nimport type { BatchConfig, BatchResult } from '@uniforge/platform-core/performance';\nimport type { QueryBatcher } from '@uniforge/platform-core/performance';\n\ninterface PendingQuery<TQuery, TResult> {\n query: TQuery;\n resolve: (result: TResult) => void;\n reject: (error: unknown) => void;\n}\n\n/** Create a QueryBatcher that groups queries and executes them in batches. */\nexport function createQueryBatcher<TQuery, TResult>(\n config: BatchConfig,\n executor: (queries: TQuery[]) => Promise<TResult[]>,\n): QueryBatcher<TQuery, TResult> {\n let pending: Array<PendingQuery<TQuery, TResult>> = [];\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n function scheduleFlush(): void {\n if (timer !== undefined) return;\n\n const delay = config.maxDelayMs !== undefined\n ? Math.min(config.delayMs, config.maxDelayMs)\n : config.delayMs;\n\n timer = setTimeout(() => {\n timer = undefined;\n void batcher.flush();\n }, delay);\n }\n\n function clearTimer(): void {\n if (timer !== undefined) {\n clearTimeout(timer);\n timer = undefined;\n }\n }\n\n const batcher: QueryBatcher<TQuery, TResult> = {\n config,\n\n add(query: TQuery): Promise<TResult> {\n return new Promise<TResult>((resolve, reject) => {\n pending.push({ query, resolve, reject });\n\n if (pending.length >= config.maxBatchSize) {\n clearTimer();\n void batcher.flush();\n } else {\n scheduleFlush();\n }\n });\n },\n\n async flush(): Promise<BatchResult<TResult>> {\n clearTimer();\n\n const batch = pending;\n pending = [];\n\n if (batch.length === 0) {\n return {\n results: [],\n batchSize: 0,\n executionTimeMs: 0,\n };\n }\n\n const queries = batch.map((p) => p.query);\n const startTime = Date.now();\n\n try {\n const results = await executor(queries);\n const executionTimeMs = Date.now() - startTime;\n\n for (let i = 0; i < batch.length; i++) {\n const item = batch[i];\n if (item) {\n item.resolve(results[i] as TResult);\n }\n }\n\n return {\n results,\n batchSize: batch.length,\n executionTimeMs,\n };\n } catch (error) {\n for (const item of batch) {\n item.reject(error);\n }\n\n return {\n results: [],\n batchSize: batch.length,\n executionTimeMs: Date.now() - startTime,\n };\n }\n },\n\n pending(): number {\n return pending.length;\n },\n };\n\n return batcher;\n}\n"],"mappings":"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","names":[]}