@flareone/common 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/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/chunk-4TE4W4RZ.js +231 -0
- package/dist/chunk-4TE4W4RZ.js.map +1 -0
- package/dist/chunk-JAMM5H7G.js +577 -0
- package/dist/chunk-JAMM5H7G.js.map +1 -0
- package/dist/chunk-TLAV6QIM.js +327 -0
- package/dist/chunk-TLAV6QIM.js.map +1 -0
- package/dist/chunk-VDUV5SQH.js +281 -0
- package/dist/chunk-VDUV5SQH.js.map +1 -0
- package/dist/chunk-XUS63JTZ.js +16 -0
- package/dist/chunk-XUS63JTZ.js.map +1 -0
- package/dist/guards/index.d.ts +230 -0
- package/dist/guards/index.js +4 -0
- package/dist/guards/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/interceptors/index.d.ts +151 -0
- package/dist/interceptors/index.js +4 -0
- package/dist/interceptors/index.js.map +1 -0
- package/dist/pipes/index.d.ts +120 -0
- package/dist/pipes/index.js +4 -0
- package/dist/pipes/index.js.map +1 -0
- package/dist/utils/index.d.ts +155 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { __decorateClass } from './chunk-XUS63JTZ.js';
|
|
2
|
+
import { Injectable } from '@flareone/core';
|
|
3
|
+
|
|
4
|
+
var LoggingInterceptor = class {
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
this.options = options;
|
|
7
|
+
}
|
|
8
|
+
async intercept(context, next) {
|
|
9
|
+
const request = context.getRequest();
|
|
10
|
+
const startTime = Date.now();
|
|
11
|
+
const requestId = crypto.randomUUID();
|
|
12
|
+
const logData = {
|
|
13
|
+
requestId,
|
|
14
|
+
method: request.method,
|
|
15
|
+
url: request.url,
|
|
16
|
+
ip: context.getClientIp(),
|
|
17
|
+
userAgent: request.headers.get("user-agent")
|
|
18
|
+
};
|
|
19
|
+
this.log(`Incoming request`, logData);
|
|
20
|
+
try {
|
|
21
|
+
const result = await next.handle();
|
|
22
|
+
const duration = Date.now() - startTime;
|
|
23
|
+
this.log(`Request completed`, {
|
|
24
|
+
...logData,
|
|
25
|
+
duration: `${duration}ms`,
|
|
26
|
+
success: true
|
|
27
|
+
});
|
|
28
|
+
return result;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
const duration = Date.now() - startTime;
|
|
31
|
+
this.log(`Request failed`, {
|
|
32
|
+
...logData,
|
|
33
|
+
duration: `${duration}ms`,
|
|
34
|
+
success: false,
|
|
35
|
+
error: error instanceof Error ? error.message : String(error)
|
|
36
|
+
});
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
log(message, data) {
|
|
41
|
+
if (this.options.logger) {
|
|
42
|
+
this.options.logger(message, data);
|
|
43
|
+
} else {
|
|
44
|
+
console.log(JSON.stringify({ message, ...data }));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
LoggingInterceptor = __decorateClass([
|
|
49
|
+
Injectable()
|
|
50
|
+
], LoggingInterceptor);
|
|
51
|
+
var TimeoutInterceptor = class {
|
|
52
|
+
constructor(options) {
|
|
53
|
+
this.options = options;
|
|
54
|
+
}
|
|
55
|
+
async intercept(_context, next) {
|
|
56
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
reject(new Error(this.options.message ?? "Request timeout"));
|
|
59
|
+
}, this.options.timeout);
|
|
60
|
+
});
|
|
61
|
+
return Promise.race([next.handle(), timeoutPromise]);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
TimeoutInterceptor = __decorateClass([
|
|
65
|
+
Injectable()
|
|
66
|
+
], TimeoutInterceptor);
|
|
67
|
+
var CacheInterceptor = class {
|
|
68
|
+
cache = /* @__PURE__ */ new Map();
|
|
69
|
+
ttl;
|
|
70
|
+
methods;
|
|
71
|
+
constructor(options = {}) {
|
|
72
|
+
this.ttl = (options.ttl ?? 60) * 1e3;
|
|
73
|
+
this.methods = options.methods ?? ["GET"];
|
|
74
|
+
}
|
|
75
|
+
async intercept(context, next) {
|
|
76
|
+
const request = context.getRequest();
|
|
77
|
+
if (!this.methods.includes(request.method)) {
|
|
78
|
+
return next.handle();
|
|
79
|
+
}
|
|
80
|
+
const key = this.generateKey(context);
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
const cached = this.cache.get(key);
|
|
83
|
+
if (cached && cached.expiresAt > now) {
|
|
84
|
+
return cached.data;
|
|
85
|
+
}
|
|
86
|
+
const result = await next.handle();
|
|
87
|
+
this.cache.set(key, {
|
|
88
|
+
data: result,
|
|
89
|
+
expiresAt: now + this.ttl
|
|
90
|
+
});
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
generateKey(context) {
|
|
94
|
+
const request = context.getRequest();
|
|
95
|
+
return `cache:${request.method}:${request.url}`;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Clear the cache
|
|
99
|
+
*/
|
|
100
|
+
clear() {
|
|
101
|
+
this.cache.clear();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Invalidate a specific key
|
|
105
|
+
*/
|
|
106
|
+
invalidate(key) {
|
|
107
|
+
this.cache.delete(key);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
CacheInterceptor = __decorateClass([
|
|
111
|
+
Injectable()
|
|
112
|
+
], CacheInterceptor);
|
|
113
|
+
var TransformInterceptor = class {
|
|
114
|
+
constructor(transformer) {
|
|
115
|
+
this.transformer = transformer;
|
|
116
|
+
}
|
|
117
|
+
async intercept(_context, next) {
|
|
118
|
+
const result = await next.handle();
|
|
119
|
+
return this.transformer(result);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
var ResponseWrapperInterceptor = class {
|
|
123
|
+
constructor(options = {}) {
|
|
124
|
+
this.options = options;
|
|
125
|
+
}
|
|
126
|
+
async intercept(context, next) {
|
|
127
|
+
const result = await next.handle();
|
|
128
|
+
const dataKey = this.options.dataKey ?? "data";
|
|
129
|
+
const wrapped = {
|
|
130
|
+
success: true,
|
|
131
|
+
[dataKey]: result
|
|
132
|
+
};
|
|
133
|
+
if (this.options.includeMetadata) {
|
|
134
|
+
wrapped["metadata"] = {
|
|
135
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
136
|
+
path: context.getUrl().pathname
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return wrapped;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
ResponseWrapperInterceptor = __decorateClass([
|
|
143
|
+
Injectable()
|
|
144
|
+
], ResponseWrapperInterceptor);
|
|
145
|
+
var ExcludeNullInterceptor = class {
|
|
146
|
+
async intercept(_context, next) {
|
|
147
|
+
const result = await next.handle();
|
|
148
|
+
return this.removeNulls(result);
|
|
149
|
+
}
|
|
150
|
+
removeNulls(obj) {
|
|
151
|
+
if (obj === null || obj === void 0) {
|
|
152
|
+
return void 0;
|
|
153
|
+
}
|
|
154
|
+
if (Array.isArray(obj)) {
|
|
155
|
+
return obj.map((item) => this.removeNulls(item)).filter((item) => item !== void 0);
|
|
156
|
+
}
|
|
157
|
+
if (typeof obj === "object") {
|
|
158
|
+
const cleaned = {};
|
|
159
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
160
|
+
const cleanedValue = this.removeNulls(value);
|
|
161
|
+
if (cleanedValue !== void 0) {
|
|
162
|
+
cleaned[key] = cleanedValue;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return cleaned;
|
|
166
|
+
}
|
|
167
|
+
return obj;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
ExcludeNullInterceptor = __decorateClass([
|
|
171
|
+
Injectable()
|
|
172
|
+
], ExcludeNullInterceptor);
|
|
173
|
+
var ClassSerializerInterceptor = class {
|
|
174
|
+
async intercept(_context, next) {
|
|
175
|
+
const result = await next.handle();
|
|
176
|
+
return this.serialize(result);
|
|
177
|
+
}
|
|
178
|
+
serialize(data) {
|
|
179
|
+
if (data === null || data === void 0) {
|
|
180
|
+
return data;
|
|
181
|
+
}
|
|
182
|
+
if (Array.isArray(data)) {
|
|
183
|
+
return data.map((item) => this.serialize(item));
|
|
184
|
+
}
|
|
185
|
+
if (data instanceof Date) {
|
|
186
|
+
return data.toISOString();
|
|
187
|
+
}
|
|
188
|
+
if (typeof data === "object") {
|
|
189
|
+
if ("toJSON" in data && typeof data.toJSON === "function") {
|
|
190
|
+
return data.toJSON();
|
|
191
|
+
}
|
|
192
|
+
const serialized = {};
|
|
193
|
+
for (const [key, value] of Object.entries(data)) {
|
|
194
|
+
if (!key.startsWith("_")) {
|
|
195
|
+
serialized[key] = this.serialize(value);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return serialized;
|
|
199
|
+
}
|
|
200
|
+
return data;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
ClassSerializerInterceptor = __decorateClass([
|
|
204
|
+
Injectable()
|
|
205
|
+
], ClassSerializerInterceptor);
|
|
206
|
+
var KVCacheInterceptor = class {
|
|
207
|
+
constructor(options) {
|
|
208
|
+
this.options = options;
|
|
209
|
+
this.ttl = options.ttl ?? 60;
|
|
210
|
+
this.methods = options.methods ?? ["GET"];
|
|
211
|
+
this.keyPrefix = options.keyPrefix ?? "cache:";
|
|
212
|
+
}
|
|
213
|
+
ttl;
|
|
214
|
+
methods;
|
|
215
|
+
keyPrefix;
|
|
216
|
+
async intercept(context, next) {
|
|
217
|
+
const request = context.getRequest();
|
|
218
|
+
if (!this.methods.includes(request.method)) {
|
|
219
|
+
return next.handle();
|
|
220
|
+
}
|
|
221
|
+
const key = this.options.keyGenerator ? this.options.keyGenerator(context) : this.generateKey(context);
|
|
222
|
+
const fullKey = `${this.keyPrefix}${key}`;
|
|
223
|
+
const cached = await this.options.kv.get(fullKey, "json");
|
|
224
|
+
if (cached !== null) {
|
|
225
|
+
return cached;
|
|
226
|
+
}
|
|
227
|
+
const result = await next.handle();
|
|
228
|
+
await this.options.kv.put(fullKey, JSON.stringify(result), {
|
|
229
|
+
expirationTtl: this.ttl
|
|
230
|
+
});
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
generateKey(context) {
|
|
234
|
+
const request = context.getRequest();
|
|
235
|
+
return `${request.method}:${request.url}`;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Invalidate cache by key
|
|
239
|
+
*/
|
|
240
|
+
async invalidate(key) {
|
|
241
|
+
await this.options.kv.delete(`${this.keyPrefix}${key}`);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Invalidate cache by prefix
|
|
245
|
+
*/
|
|
246
|
+
async invalidateByPrefix(prefix) {
|
|
247
|
+
const fullPrefix = `${this.keyPrefix}${prefix}`;
|
|
248
|
+
const keys = await this.options.kv.list({ prefix: fullPrefix });
|
|
249
|
+
await Promise.all(
|
|
250
|
+
keys.keys.map((k) => this.options.kv.delete(k.name))
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
KVCacheInterceptor = __decorateClass([
|
|
255
|
+
Injectable()
|
|
256
|
+
], KVCacheInterceptor);
|
|
257
|
+
var DOCacheInterceptor = class {
|
|
258
|
+
constructor(options) {
|
|
259
|
+
this.options = options;
|
|
260
|
+
this.ttl = options.ttl ?? 60;
|
|
261
|
+
this.methods = options.methods ?? ["GET"];
|
|
262
|
+
}
|
|
263
|
+
ttl;
|
|
264
|
+
methods;
|
|
265
|
+
async intercept(context, next) {
|
|
266
|
+
const request = context.getRequest();
|
|
267
|
+
if (!this.methods.includes(request.method)) {
|
|
268
|
+
return next.handle();
|
|
269
|
+
}
|
|
270
|
+
const shardKey = this.options.shardKeyGenerator ? this.options.shardKeyGenerator(context) : "cache";
|
|
271
|
+
const id = this.options.namespace.idFromName(shardKey);
|
|
272
|
+
const stub = this.options.namespace.get(id);
|
|
273
|
+
const cacheKey = this.options.keyGenerator ? this.options.keyGenerator(context) : this.generateKey(context);
|
|
274
|
+
const response = await stub.fetch("https://cache/get", {
|
|
275
|
+
method: "POST",
|
|
276
|
+
headers: { "Content-Type": "application/json" },
|
|
277
|
+
body: JSON.stringify({ key: cacheKey })
|
|
278
|
+
});
|
|
279
|
+
if (response.ok) {
|
|
280
|
+
return response.json();
|
|
281
|
+
}
|
|
282
|
+
const result = await next.handle();
|
|
283
|
+
await stub.fetch("https://cache/set", {
|
|
284
|
+
method: "POST",
|
|
285
|
+
headers: { "Content-Type": "application/json" },
|
|
286
|
+
body: JSON.stringify({
|
|
287
|
+
key: cacheKey,
|
|
288
|
+
value: result,
|
|
289
|
+
ttl: this.ttl
|
|
290
|
+
})
|
|
291
|
+
});
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
generateKey(context) {
|
|
295
|
+
const request = context.getRequest();
|
|
296
|
+
return `${request.method}:${request.url}`;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Invalidate cache
|
|
300
|
+
*/
|
|
301
|
+
async invalidate(key, shardKey = "cache") {
|
|
302
|
+
const id = this.options.namespace.idFromName(shardKey);
|
|
303
|
+
const stub = this.options.namespace.get(id);
|
|
304
|
+
await stub.fetch("https://cache/delete", {
|
|
305
|
+
method: "POST",
|
|
306
|
+
headers: { "Content-Type": "application/json" },
|
|
307
|
+
body: JSON.stringify({ key })
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Clear all cache in a shard
|
|
312
|
+
*/
|
|
313
|
+
async clear(shardKey = "cache") {
|
|
314
|
+
const id = this.options.namespace.idFromName(shardKey);
|
|
315
|
+
const stub = this.options.namespace.get(id);
|
|
316
|
+
await stub.fetch("https://cache/clear", {
|
|
317
|
+
method: "POST"
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
DOCacheInterceptor = __decorateClass([
|
|
322
|
+
Injectable()
|
|
323
|
+
], DOCacheInterceptor);
|
|
324
|
+
|
|
325
|
+
export { CacheInterceptor, ClassSerializerInterceptor, DOCacheInterceptor, ExcludeNullInterceptor, KVCacheInterceptor, LoggingInterceptor, ResponseWrapperInterceptor, TimeoutInterceptor, TransformInterceptor };
|
|
326
|
+
//# sourceMappingURL=chunk-TLAV6QIM.js.map
|
|
327
|
+
//# sourceMappingURL=chunk-TLAV6QIM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/interceptors/index.ts"],"names":[],"mappings":"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","file":"chunk-TLAV6QIM.js","sourcesContent":["/**\r\n * Built-in Interceptors\r\n * middleware but cooler.\r\n */\r\n\r\nimport {\r\n type Interceptor,\r\n type CallHandler,\r\n type ExecutionContextWrapper,\r\n Injectable,\r\n} from '@flareone/core';\r\n\r\nexport interface LoggingInterceptorOptions {\r\n level?: 'debug' | 'info' | 'warn' | 'error';\r\n includeBody?: boolean;\r\n includeResponse?: boolean;\r\n logger?: (message: string, data?: Record<string, unknown>) => void;\r\n}\r\n\r\n/**\r\n * Logging interceptor for request/response logging\r\n */\r\n@Injectable()\r\nexport class LoggingInterceptor implements Interceptor {\r\n constructor(private readonly options: LoggingInterceptorOptions = {}) { }\r\n\r\n async intercept(\r\n context: ExecutionContextWrapper,\r\n next: CallHandler\r\n ): Promise<unknown> {\r\n const request = context.getRequest();\r\n const startTime = Date.now();\r\n const requestId = crypto.randomUUID();\r\n\r\n const logData: Record<string, unknown> = {\r\n requestId,\r\n method: request.method,\r\n url: request.url,\r\n ip: context.getClientIp(),\r\n userAgent: request.headers.get('user-agent'),\r\n };\r\n\r\n this.log(`Incoming request`, logData);\r\n\r\n try {\r\n const result = await next.handle();\r\n const duration = Date.now() - startTime;\r\n\r\n this.log(`Request completed`, {\r\n ...logData,\r\n duration: `${duration}ms`,\r\n success: true,\r\n });\r\n\r\n return result;\r\n } catch (error) {\r\n const duration = Date.now() - startTime;\r\n\r\n this.log(`Request failed`, {\r\n ...logData,\r\n duration: `${duration}ms`,\r\n success: false,\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n\r\n throw error;\r\n }\r\n }\r\n\r\n private log(message: string, data?: Record<string, unknown>): void {\r\n if (this.options.logger) {\r\n this.options.logger(message, data);\r\n } else {\r\n console.log(JSON.stringify({ message, ...data }));\r\n }\r\n }\r\n}\r\n\r\nexport interface TimeoutInterceptorOptions {\r\n timeout: number;\r\n message?: string;\r\n}\r\n\r\n/**\r\n * Timeout interceptor\r\n */\r\n@Injectable()\r\nexport class TimeoutInterceptor implements Interceptor {\r\n constructor(private readonly options: TimeoutInterceptorOptions) { }\r\n\r\n async intercept(\r\n _context: ExecutionContextWrapper,\r\n next: CallHandler\r\n ): Promise<unknown> {\r\n const timeoutPromise = new Promise((_, reject) => {\r\n setTimeout(() => {\r\n reject(new Error(this.options.message ?? 'Request timeout'));\r\n }, this.options.timeout);\r\n });\r\n\r\n return Promise.race([next.handle(), timeoutPromise]);\r\n }\r\n}\r\n\r\nexport interface CacheInterceptorOptions {\r\n ttl?: number;\r\n keyGenerator?: (context: ExecutionContextWrapper) => string;\r\n methods?: string[];\r\n}\r\n\r\n/**\r\n * In-memory cache interceptor\r\n * For production, use KV or other distributed cache\r\n */\r\n@Injectable()\r\nexport class CacheInterceptor implements Interceptor {\r\n private readonly cache = new Map<string, { data: unknown; expiresAt: number }>();\r\n private readonly ttl: number;\r\n private readonly methods: string[];\r\n\r\n constructor(options: CacheInterceptorOptions = {}) {\r\n this.ttl = (options.ttl ?? 60) * 1000;\r\n this.methods = options.methods ?? ['GET'];\r\n }\r\n\r\n async intercept(\r\n context: ExecutionContextWrapper,\r\n next: CallHandler\r\n ): Promise<unknown> {\r\n const request = context.getRequest();\r\n\r\n if (!this.methods.includes(request.method)) {\r\n return next.handle();\r\n }\r\n\r\n const key = this.generateKey(context);\r\n const now = Date.now();\r\n\r\n const cached = this.cache.get(key);\r\n if (cached && cached.expiresAt > now) {\r\n return cached.data;\r\n }\r\n const result = await next.handle();\r\n\r\n this.cache.set(key, {\r\n data: result,\r\n expiresAt: now + this.ttl,\r\n });\r\n\r\n return result;\r\n }\r\n\r\n private generateKey(context: ExecutionContextWrapper): string {\r\n const request = context.getRequest();\r\n return `cache:${request.method}:${request.url}`;\r\n }\r\n\r\n /**\r\n * Clear the cache\r\n */\r\n clear(): void {\r\n this.cache.clear();\r\n }\r\n\r\n /**\r\n * Invalidate a specific key\r\n */\r\n invalidate(key: string): void {\r\n this.cache.delete(key);\r\n }\r\n}\r\n\r\nexport interface TransformInterceptorOptions<T, R> {\r\n transform: (data: T) => R | Promise<R>;\r\n}\r\n\r\n/**\r\n * Generic transform interceptor\r\n */\r\nexport class TransformInterceptor<T = unknown, R = unknown> implements Interceptor {\r\n constructor(\r\n private readonly transformer: (data: T) => R | Promise<R>\r\n ) { }\r\n\r\n async intercept(\r\n _context: ExecutionContextWrapper,\r\n next: CallHandler<T>\r\n ): Promise<R> {\r\n const result = await next.handle();\r\n return this.transformer(result);\r\n }\r\n}\r\n\r\nexport interface ResponseWrapperOptions {\r\n dataKey?: string;\r\n includeMetadata?: boolean;\r\n}\r\n\r\n/**\r\n * Wrap response in standard format\r\n */\r\n@Injectable()\r\nexport class ResponseWrapperInterceptor implements Interceptor {\r\n constructor(private readonly options: ResponseWrapperOptions = {}) { }\r\n\r\n async intercept(\r\n context: ExecutionContextWrapper,\r\n next: CallHandler\r\n ): Promise<unknown> {\r\n const result = await next.handle();\r\n const dataKey = this.options.dataKey ?? 'data';\r\n\r\n const wrapped: Record<string, unknown> = {\r\n success: true,\r\n [dataKey]: result,\r\n };\r\n\r\n if (this.options.includeMetadata) {\r\n wrapped['metadata'] = {\r\n timestamp: new Date().toISOString(),\r\n path: context.getUrl().pathname,\r\n };\r\n }\r\n\r\n return wrapped;\r\n }\r\n}\r\n\r\n/**\r\n * Remove null and undefined values from response\r\n */\r\n@Injectable()\r\nexport class ExcludeNullInterceptor implements Interceptor {\r\n async intercept(\r\n _context: ExecutionContextWrapper,\r\n next: CallHandler\r\n ): Promise<unknown> {\r\n const result = await next.handle();\r\n return this.removeNulls(result);\r\n }\r\n\r\n private removeNulls(obj: unknown): unknown {\r\n if (obj === null || obj === undefined) {\r\n return undefined;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map((item) => this.removeNulls(item)).filter((item) => item !== undefined);\r\n }\r\n\r\n if (typeof obj === 'object') {\r\n const cleaned: Record<string, unknown> = {};\r\n for (const [key, value] of Object.entries(obj)) {\r\n const cleanedValue = this.removeNulls(value);\r\n if (cleanedValue !== undefined) {\r\n cleaned[key] = cleanedValue;\r\n }\r\n }\r\n return cleaned;\r\n }\r\n\r\n return obj;\r\n }\r\n}\r\n\r\n/**\r\n * Serialize class instances to plain objects\r\n */\r\n@Injectable()\r\nexport class ClassSerializerInterceptor implements Interceptor {\r\n async intercept(\r\n _context: ExecutionContextWrapper,\r\n next: CallHandler\r\n ): Promise<unknown> {\r\n const result = await next.handle();\r\n return this.serialize(result);\r\n }\r\n\r\n private serialize(data: unknown): unknown {\r\n if (data === null || data === undefined) {\r\n return data;\r\n }\r\n\r\n if (Array.isArray(data)) {\r\n return data.map((item) => this.serialize(item));\r\n }\r\n\r\n if (data instanceof Date) {\r\n return data.toISOString();\r\n }\r\n\r\n if (typeof data === 'object') {\r\n if ('toJSON' in data && typeof (data as { toJSON: () => unknown }).toJSON === 'function') {\r\n return (data as { toJSON: () => unknown }).toJSON();\r\n }\r\n\r\n const serialized: Record<string, unknown> = {};\r\n for (const [key, value] of Object.entries(data)) {\r\n if (!key.startsWith('_')) {\r\n serialized[key] = this.serialize(value);\r\n }\r\n }\r\n return serialized;\r\n }\r\n\r\n return data;\r\n }\r\n}\r\n\r\n/**\r\n * KV-based cache interceptor for distributed caching\r\n */\r\nexport interface KVCacheOptions {\r\n kv: KVNamespace;\r\n ttl?: number;\r\n keyGenerator?: (context: ExecutionContextWrapper) => string;\r\n methods?: string[];\r\n keyPrefix?: string;\r\n}\r\n\r\n@Injectable()\r\nexport class KVCacheInterceptor implements Interceptor {\r\n private readonly ttl: number;\r\n private readonly methods: string[];\r\n private readonly keyPrefix: string;\r\n\r\n constructor(private readonly options: KVCacheOptions) {\r\n this.ttl = options.ttl ?? 60;\r\n this.methods = options.methods ?? ['GET'];\r\n this.keyPrefix = options.keyPrefix ?? 'cache:';\r\n }\r\n\r\n async intercept(\r\n context: ExecutionContextWrapper,\r\n next: CallHandler\r\n ): Promise<unknown> {\r\n const request = context.getRequest();\r\n\r\n if (!this.methods.includes(request.method)) {\r\n return next.handle();\r\n }\r\n\r\n const key = this.options.keyGenerator\r\n ? this.options.keyGenerator(context)\r\n : this.generateKey(context);\r\n\r\n const fullKey = `${this.keyPrefix}${key}`;\r\n\r\n const cached = await this.options.kv.get(fullKey, 'json');\r\n if (cached !== null) {\r\n return cached;\r\n }\r\n\r\n const result = await next.handle();\r\n\r\n await this.options.kv.put(fullKey, JSON.stringify(result), {\r\n expirationTtl: this.ttl,\r\n });\r\n\r\n return result;\r\n }\r\n\r\n private generateKey(context: ExecutionContextWrapper): string {\r\n const request = context.getRequest();\r\n return `${request.method}:${request.url}`;\r\n }\r\n\r\n /**\r\n * Invalidate cache by key\r\n */\r\n async invalidate(key: string): Promise<void> {\r\n await this.options.kv.delete(`${this.keyPrefix}${key}`);\r\n }\r\n\r\n /**\r\n * Invalidate cache by prefix\r\n */\r\n async invalidateByPrefix(prefix: string): Promise<void> {\r\n const fullPrefix = `${this.keyPrefix}${prefix}`;\r\n const keys = await this.options.kv.list({ prefix: fullPrefix });\r\n\r\n await Promise.all(\r\n keys.keys.map(k => this.options.kv.delete(k.name))\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Durable Object-based cache interceptor for advanced caching\r\n */\r\nexport interface DOCacheOptions {\r\n namespace: DurableObjectNamespace;\r\n ttl?: number;\r\n keyGenerator?: (context: ExecutionContextWrapper) => string;\r\n methods?: string[];\r\n shardKeyGenerator?: (context: ExecutionContextWrapper) => string;\r\n}\r\n\r\n@Injectable()\r\nexport class DOCacheInterceptor implements Interceptor {\r\n private readonly ttl: number;\r\n private readonly methods: string[];\r\n\r\n constructor(private readonly options: DOCacheOptions) {\r\n this.ttl = options.ttl ?? 60;\r\n this.methods = options.methods ?? ['GET'];\r\n }\r\n\r\n async intercept(\r\n context: ExecutionContextWrapper,\r\n next: CallHandler\r\n ): Promise<unknown> {\r\n const request = context.getRequest();\r\n\r\n if (!this.methods.includes(request.method)) {\r\n return next.handle();\r\n }\r\n\r\n const shardKey = this.options.shardKeyGenerator\r\n ? this.options.shardKeyGenerator(context)\r\n : 'cache';\r\n\r\n const id = this.options.namespace.idFromName(shardKey);\r\n const stub = this.options.namespace.get(id);\r\n\r\n const cacheKey = this.options.keyGenerator\r\n ? this.options.keyGenerator(context)\r\n : this.generateKey(context);\r\n\r\n const response = await stub.fetch('https://cache/get', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ key: cacheKey }),\r\n });\r\n\r\n if (response.ok) {\r\n return response.json();\r\n }\r\n\r\n const result = await next.handle();\r\n\r\n await stub.fetch('https://cache/set', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n key: cacheKey,\r\n value: result,\r\n ttl: this.ttl,\r\n }),\r\n });\r\n\r\n return result;\r\n }\r\n\r\n private generateKey(context: ExecutionContextWrapper): string {\r\n const request = context.getRequest();\r\n return `${request.method}:${request.url}`;\r\n }\r\n\r\n /**\r\n * Invalidate cache\r\n */\r\n async invalidate(key: string, shardKey: string = 'cache'): Promise<void> {\r\n const id = this.options.namespace.idFromName(shardKey);\r\n const stub = this.options.namespace.get(id);\r\n\r\n await stub.fetch('https://cache/delete', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ key }),\r\n });\r\n }\r\n\r\n /**\r\n * Clear all cache in a shard\r\n */\r\n async clear(shardKey: string = 'cache'): Promise<void> {\r\n const id = this.options.namespace.idFromName(shardKey);\r\n const stub = this.options.namespace.get(id);\r\n\r\n await stub.fetch('https://cache/clear', {\r\n method: 'POST',\r\n });\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// src/utils/index.ts
|
|
2
|
+
function uuid() {
|
|
3
|
+
return crypto.randomUUID();
|
|
4
|
+
}
|
|
5
|
+
function randomString(length, charset = "alphanumeric") {
|
|
6
|
+
const charsets = {
|
|
7
|
+
alphanumeric: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
8
|
+
alpha: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
9
|
+
numeric: "0123456789",
|
|
10
|
+
hex: "0123456789abcdef"
|
|
11
|
+
};
|
|
12
|
+
const chars = charsets[charset] ?? charset;
|
|
13
|
+
const array = new Uint8Array(length);
|
|
14
|
+
crypto.getRandomValues(array);
|
|
15
|
+
return Array.from(array).map((byte) => chars[byte % chars.length]).join("");
|
|
16
|
+
}
|
|
17
|
+
async function sha256(data) {
|
|
18
|
+
const encoder = new TextEncoder();
|
|
19
|
+
const buffer = await crypto.subtle.digest("SHA-256", encoder.encode(data));
|
|
20
|
+
return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
21
|
+
}
|
|
22
|
+
async function sha512(data) {
|
|
23
|
+
const encoder = new TextEncoder();
|
|
24
|
+
const buffer = await crypto.subtle.digest("SHA-512", encoder.encode(data));
|
|
25
|
+
return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
26
|
+
}
|
|
27
|
+
async function hmac(data, secret, algorithm = "SHA-256") {
|
|
28
|
+
const encoder = new TextEncoder();
|
|
29
|
+
const key = await crypto.subtle.importKey(
|
|
30
|
+
"raw",
|
|
31
|
+
encoder.encode(secret),
|
|
32
|
+
{ name: "HMAC", hash: algorithm },
|
|
33
|
+
false,
|
|
34
|
+
["sign"]
|
|
35
|
+
);
|
|
36
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(data));
|
|
37
|
+
return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
38
|
+
}
|
|
39
|
+
function constantTimeEqual(a, b) {
|
|
40
|
+
if (a.length !== b.length) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
let result = 0;
|
|
44
|
+
for (let i = 0; i < a.length; i++) {
|
|
45
|
+
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
46
|
+
}
|
|
47
|
+
return result === 0;
|
|
48
|
+
}
|
|
49
|
+
function base64Encode(data) {
|
|
50
|
+
if (typeof data === "string") {
|
|
51
|
+
return btoa(data);
|
|
52
|
+
}
|
|
53
|
+
return btoa(String.fromCharCode(...new Uint8Array(data)));
|
|
54
|
+
}
|
|
55
|
+
function base64Decode(data) {
|
|
56
|
+
return atob(data);
|
|
57
|
+
}
|
|
58
|
+
function base64UrlEncode(data) {
|
|
59
|
+
return base64Encode(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
60
|
+
}
|
|
61
|
+
function base64UrlDecode(data) {
|
|
62
|
+
const padded = data + "=".repeat((4 - data.length % 4) % 4);
|
|
63
|
+
return base64Decode(padded.replace(/-/g, "+").replace(/_/g, "/"));
|
|
64
|
+
}
|
|
65
|
+
function hexEncode(data) {
|
|
66
|
+
const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
67
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
68
|
+
}
|
|
69
|
+
function hexDecode(hex) {
|
|
70
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
71
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
72
|
+
bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
|
|
73
|
+
}
|
|
74
|
+
return bytes;
|
|
75
|
+
}
|
|
76
|
+
function camelCase(str) {
|
|
77
|
+
return str.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : "").replace(/^(.)/, (c) => c.toLowerCase());
|
|
78
|
+
}
|
|
79
|
+
function pascalCase(str) {
|
|
80
|
+
return str.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : "").replace(/^(.)/, (c) => c.toUpperCase());
|
|
81
|
+
}
|
|
82
|
+
function snakeCase(str) {
|
|
83
|
+
return str.replace(/([A-Z])/g, "_$1").replace(/[-\s]+/g, "_").replace(/^_/, "").toLowerCase();
|
|
84
|
+
}
|
|
85
|
+
function kebabCase(str) {
|
|
86
|
+
return str.replace(/([A-Z])/g, "-$1").replace(/[_\s]+/g, "-").replace(/^-/, "").toLowerCase();
|
|
87
|
+
}
|
|
88
|
+
function slugify(str) {
|
|
89
|
+
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
90
|
+
}
|
|
91
|
+
function truncate(str, length, suffix = "...") {
|
|
92
|
+
if (str.length <= length) return str;
|
|
93
|
+
return str.slice(0, length - suffix.length) + suffix;
|
|
94
|
+
}
|
|
95
|
+
function deepClone(obj) {
|
|
96
|
+
if (obj === null || typeof obj !== "object") {
|
|
97
|
+
return obj;
|
|
98
|
+
}
|
|
99
|
+
if (obj instanceof Date) {
|
|
100
|
+
return new Date(obj.getTime());
|
|
101
|
+
}
|
|
102
|
+
if (Array.isArray(obj)) {
|
|
103
|
+
return obj.map((item) => deepClone(item));
|
|
104
|
+
}
|
|
105
|
+
const cloned = {};
|
|
106
|
+
for (const key in obj) {
|
|
107
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
108
|
+
cloned[key] = deepClone(obj[key]);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return cloned;
|
|
112
|
+
}
|
|
113
|
+
function deepMerge(target, ...sources) {
|
|
114
|
+
const result = deepClone(target);
|
|
115
|
+
for (const source of sources) {
|
|
116
|
+
for (const key in source) {
|
|
117
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
118
|
+
const sourceValue = source[key];
|
|
119
|
+
const targetValue = result[key];
|
|
120
|
+
if (typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
|
|
121
|
+
result[key] = deepMerge(
|
|
122
|
+
targetValue,
|
|
123
|
+
sourceValue
|
|
124
|
+
);
|
|
125
|
+
} else {
|
|
126
|
+
result[key] = deepClone(sourceValue);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
function pick(obj, keys) {
|
|
134
|
+
const result = {};
|
|
135
|
+
for (const key of keys) {
|
|
136
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
137
|
+
result[key] = obj[key];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
function omit(obj, keys) {
|
|
143
|
+
const result = { ...obj };
|
|
144
|
+
for (const key of keys) {
|
|
145
|
+
delete result[key];
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
function get(obj, path, defaultValue) {
|
|
150
|
+
const keys = path.split(".");
|
|
151
|
+
let result = obj;
|
|
152
|
+
for (const key of keys) {
|
|
153
|
+
if (result === null || result === void 0) {
|
|
154
|
+
return defaultValue;
|
|
155
|
+
}
|
|
156
|
+
result = result[key];
|
|
157
|
+
}
|
|
158
|
+
return result ?? defaultValue;
|
|
159
|
+
}
|
|
160
|
+
function set(obj, path, value) {
|
|
161
|
+
const keys = path.split(".");
|
|
162
|
+
const result = deepClone(obj);
|
|
163
|
+
let current = result;
|
|
164
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
165
|
+
const key = keys[i];
|
|
166
|
+
if (!(key in current) || typeof current[key] !== "object") {
|
|
167
|
+
current[key] = {};
|
|
168
|
+
}
|
|
169
|
+
current = current[key];
|
|
170
|
+
}
|
|
171
|
+
current[keys[keys.length - 1]] = value;
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
function chunk(arr, size) {
|
|
175
|
+
const chunks = [];
|
|
176
|
+
for (let i = 0; i < arr.length; i += size) {
|
|
177
|
+
chunks.push(arr.slice(i, i + size));
|
|
178
|
+
}
|
|
179
|
+
return chunks;
|
|
180
|
+
}
|
|
181
|
+
function unique(arr) {
|
|
182
|
+
return [...new Set(arr)];
|
|
183
|
+
}
|
|
184
|
+
function groupBy(arr, keyFn) {
|
|
185
|
+
return arr.reduce(
|
|
186
|
+
(acc, item) => {
|
|
187
|
+
const key = keyFn(item);
|
|
188
|
+
if (!acc[key]) {
|
|
189
|
+
acc[key] = [];
|
|
190
|
+
}
|
|
191
|
+
acc[key].push(item);
|
|
192
|
+
return acc;
|
|
193
|
+
},
|
|
194
|
+
{}
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
function shuffle(arr) {
|
|
198
|
+
const result = [...arr];
|
|
199
|
+
for (let i = result.length - 1; i > 0; i--) {
|
|
200
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
201
|
+
[result[i], result[j]] = [result[j], result[i]];
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
function sleep(ms) {
|
|
206
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
207
|
+
}
|
|
208
|
+
async function retry(fn, options = {}) {
|
|
209
|
+
const {
|
|
210
|
+
maxAttempts = 3,
|
|
211
|
+
initialDelay = 100,
|
|
212
|
+
maxDelay = 1e4,
|
|
213
|
+
factor = 2
|
|
214
|
+
} = options;
|
|
215
|
+
let lastError;
|
|
216
|
+
let delay = initialDelay;
|
|
217
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
218
|
+
try {
|
|
219
|
+
return await fn();
|
|
220
|
+
} catch (error) {
|
|
221
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
222
|
+
if (attempt === maxAttempts) {
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
await sleep(delay);
|
|
226
|
+
delay = Math.min(delay * factor, maxDelay);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
throw lastError;
|
|
230
|
+
}
|
|
231
|
+
async function parallel(tasks, concurrency) {
|
|
232
|
+
const results = [];
|
|
233
|
+
const running = [];
|
|
234
|
+
let index = 0;
|
|
235
|
+
const runNext = async () => {
|
|
236
|
+
const i = index++;
|
|
237
|
+
if (i >= tasks.length) return;
|
|
238
|
+
results[i] = await tasks[i]();
|
|
239
|
+
await runNext();
|
|
240
|
+
};
|
|
241
|
+
while (running.length < concurrency && index < tasks.length) {
|
|
242
|
+
running.push(runNext());
|
|
243
|
+
}
|
|
244
|
+
await Promise.all(running);
|
|
245
|
+
return results;
|
|
246
|
+
}
|
|
247
|
+
function isEmail(value) {
|
|
248
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
249
|
+
return emailRegex.test(value);
|
|
250
|
+
}
|
|
251
|
+
function isUrl(value) {
|
|
252
|
+
try {
|
|
253
|
+
new URL(value);
|
|
254
|
+
return true;
|
|
255
|
+
} catch {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function isUuid(value) {
|
|
260
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
261
|
+
return uuidRegex.test(value);
|
|
262
|
+
}
|
|
263
|
+
function isIpv4(value) {
|
|
264
|
+
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
265
|
+
if (!ipv4Regex.test(value)) return false;
|
|
266
|
+
return value.split(".").every((octet) => {
|
|
267
|
+
const num = parseInt(octet, 10);
|
|
268
|
+
return num >= 0 && num <= 255;
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
function isEmpty(value) {
|
|
272
|
+
if (value === null || value === void 0) return true;
|
|
273
|
+
if (typeof value === "string") return value.trim() === "";
|
|
274
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
275
|
+
if (typeof value === "object") return Object.keys(value).length === 0;
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export { base64Decode, base64Encode, base64UrlDecode, base64UrlEncode, camelCase, chunk, constantTimeEqual, deepClone, deepMerge, get, groupBy, hexDecode, hexEncode, hmac, isEmail, isEmpty, isIpv4, isUrl, isUuid, kebabCase, omit, parallel, pascalCase, pick, randomString, retry, set, sha256, sha512, shuffle, sleep, slugify, snakeCase, truncate, unique, uuid };
|
|
280
|
+
//# sourceMappingURL=chunk-VDUV5SQH.js.map
|
|
281
|
+
//# sourceMappingURL=chunk-VDUV5SQH.js.map
|