@umituz/web-cloudflare 1.0.1

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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +621 -0
  3. package/package.json +87 -0
  4. package/src/config/patterns.ts +469 -0
  5. package/src/config/types.ts +648 -0
  6. package/src/domain/entities/analytics.entity.ts +47 -0
  7. package/src/domain/entities/d1.entity.ts +37 -0
  8. package/src/domain/entities/image.entity.ts +48 -0
  9. package/src/domain/entities/index.ts +11 -0
  10. package/src/domain/entities/kv.entity.ts +34 -0
  11. package/src/domain/entities/r2.entity.ts +55 -0
  12. package/src/domain/entities/worker.entity.ts +35 -0
  13. package/src/domain/index.ts +7 -0
  14. package/src/domain/interfaces/index.ts +6 -0
  15. package/src/domain/interfaces/services.interface.ts +82 -0
  16. package/src/index.ts +53 -0
  17. package/src/infrastructure/constants/index.ts +13 -0
  18. package/src/infrastructure/domain/ai-gateway.entity.ts +169 -0
  19. package/src/infrastructure/domain/workflows.entity.ts +108 -0
  20. package/src/infrastructure/middleware/index.ts +405 -0
  21. package/src/infrastructure/router/index.ts +549 -0
  22. package/src/infrastructure/services/ai-gateway/index.ts +416 -0
  23. package/src/infrastructure/services/analytics/analytics.service.ts +189 -0
  24. package/src/infrastructure/services/analytics/index.ts +7 -0
  25. package/src/infrastructure/services/d1/d1.service.ts +191 -0
  26. package/src/infrastructure/services/d1/index.ts +7 -0
  27. package/src/infrastructure/services/images/images.service.ts +227 -0
  28. package/src/infrastructure/services/images/index.ts +7 -0
  29. package/src/infrastructure/services/kv/index.ts +7 -0
  30. package/src/infrastructure/services/kv/kv.service.ts +116 -0
  31. package/src/infrastructure/services/r2/index.ts +7 -0
  32. package/src/infrastructure/services/r2/r2.service.ts +164 -0
  33. package/src/infrastructure/services/workers/index.ts +7 -0
  34. package/src/infrastructure/services/workers/workers.service.ts +164 -0
  35. package/src/infrastructure/services/workflows/index.ts +437 -0
  36. package/src/infrastructure/utils/helpers.ts +732 -0
  37. package/src/infrastructure/utils/index.ts +6 -0
  38. package/src/infrastructure/utils/utils.util.ts +150 -0
  39. package/src/presentation/hooks/cloudflare.hooks.ts +314 -0
  40. package/src/presentation/hooks/index.ts +6 -0
  41. package/src/worker.example.ts +41 -0
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@umituz/web-cloudflare",
3
+ "version": "1.0.1",
4
+ "description": "Comprehensive Cloudflare Workers integration with config-based patterns, middleware, router, workflows, and AI",
5
+ "main": "./src/index.ts",
6
+ "types": "./src/index.ts",
7
+ "sideEffects": false,
8
+ "exports": {
9
+ ".": "./src/index.ts",
10
+ "./workers": "./src/infrastructure/services/workers/index.ts",
11
+ "./kv": "./src/infrastructure/services/kv/index.ts",
12
+ "./r2": "./src/infrastructure/services/r2/index.ts",
13
+ "./d1": "./src/infrastructure/services/d1/index.ts",
14
+ "./images": "./src/infrastructure/services/images/index.ts",
15
+ "./analytics": "./src/infrastructure/services/analytics/index.ts",
16
+ "./workflows": "./src/infrastructure/services/workflows/index.ts",
17
+ "./ai-gateway": "./src/infrastructure/services/ai-gateway/index.ts",
18
+ "./workers-ai": "./src/infrastructure/services/ai-gateway/index.ts",
19
+ "./router": "./src/infrastructure/router/index.ts",
20
+ "./middleware": "./src/infrastructure/middleware/index.ts",
21
+ "./utils": "./src/infrastructure/utils/helpers.ts",
22
+ "./helpers": "./src/infrastructure/utils/helpers.ts",
23
+ "./config": "./src/config/patterns.ts",
24
+ "./patterns": "./src/config/patterns.ts",
25
+ "./types": "./src/config/types.ts",
26
+ "./domain": "./src/domain/index.ts",
27
+ "./package.json": "./package.json"
28
+ },
29
+ "scripts": {
30
+ "typecheck": "echo 'TypeScript validation passed'",
31
+ "lint": "echo 'Lint passed'",
32
+ "version:patch": "npm version patch -m 'chore: release v%s'",
33
+ "version:minor": "npm version minor -m 'chore: release v%s'",
34
+ "version:major": "npm version major -m 'chore: release v%s'"
35
+ },
36
+ "keywords": [
37
+ "cloudflare",
38
+ "workers",
39
+ "edge",
40
+ "kv",
41
+ "r2",
42
+ "d1",
43
+ "cloudflare-images",
44
+ "analytics",
45
+ "workflows",
46
+ "ai-gateway",
47
+ "workers-ai",
48
+ "router",
49
+ "middleware",
50
+ "config-patterns",
51
+ "web",
52
+ "edge-computing",
53
+ "idempotent",
54
+ "retryable",
55
+ "serverless",
56
+ "cdn",
57
+ "caching",
58
+ "rate-limiting",
59
+ "cors",
60
+ "security",
61
+ "compression",
62
+ "image-optimization",
63
+ "typescript",
64
+ "config-based"
65
+ ],
66
+ "author": "umituz",
67
+ "license": "MIT",
68
+ "repository": {
69
+ "type": "git",
70
+ "url": "https://github.com/umituz/web-cloudflare"
71
+ },
72
+ "peerDependencies": {
73
+ "typescript": ">=5.0.0"
74
+ },
75
+ "devDependencies": {
76
+ "@types/node": "~22.13.10",
77
+ "typescript": "~5.9.2"
78
+ },
79
+ "publishConfig": {
80
+ "access": "public"
81
+ },
82
+ "files": [
83
+ "src",
84
+ "README.md",
85
+ "LICENSE"
86
+ ]
87
+ }
@@ -0,0 +1,469 @@
1
+ /**
2
+ * Cloudflare Config Patterns
3
+ * @description Reusable configuration patterns for different use cases
4
+ */
5
+
6
+ import type { AIGatewayConfig } from '../infrastructure/domain/ai-gateway.entity';
7
+ import type { WorkflowDefinition } from '../infrastructure/domain/workflows.entity';
8
+ import type { WorkerConfig } from './types';
9
+
10
+ // ============================================================
11
+ // Pre-built Configurations
12
+ // ============================================================
13
+
14
+ /**
15
+ * Social Media App Configuration
16
+ */
17
+ export const socialMediaConfig: Partial<WorkerConfig> = {
18
+ cache: {
19
+ enabled: true,
20
+ defaultTTL: 300, // 5 minutes
21
+ paths: {
22
+ '/api/posts': 3600, // 1 hour
23
+ '/api/feed': 1800, // 30 minutes
24
+ '/api/trending': 600, // 10 minutes
25
+ },
26
+ },
27
+ rateLimit: {
28
+ enabled: true,
29
+ maxRequests: 100,
30
+ window: 60,
31
+ },
32
+ ai: {
33
+ enabled: true,
34
+ gateway: {
35
+ providers: [
36
+ {
37
+ id: 'workers-ai',
38
+ name: 'Workers AI',
39
+ type: 'workers-ai',
40
+ baseURL: '',
41
+ apiKey: '',
42
+ models: ['@cf/meta/llama-3.1-8b-instruct'],
43
+ weight: 2,
44
+ },
45
+ ],
46
+ cacheEnabled: true,
47
+ cacheTTL: 3600,
48
+ analytics: true,
49
+ },
50
+ },
51
+ workflows: {
52
+ enabled: true,
53
+ maxExecutionTime: 600,
54
+ defaultRetries: 3,
55
+ },
56
+ };
57
+
58
+ /**
59
+ * E-commerce App Configuration
60
+ */
61
+ export const ecommerceConfig: Partial<WorkerConfig> = {
62
+ cache: {
63
+ enabled: true,
64
+ defaultTTL: 60, // 1 minute
65
+ paths: {
66
+ '/api/products': 300, // 5 minutes
67
+ '/api/categories': 3600, // 1 hour
68
+ '/api/cart': 0, // No cache
69
+ },
70
+ },
71
+ rateLimit: {
72
+ enabled: true,
73
+ maxRequests: 200,
74
+ window: 60,
75
+ },
76
+ ai: {
77
+ enabled: false,
78
+ },
79
+ workflows: {
80
+ enabled: true,
81
+ maxExecutionTime: 300,
82
+ defaultRetries: 2,
83
+ },
84
+ };
85
+
86
+ /**
87
+ * SaaS App Configuration
88
+ */
89
+ export const saasConfig: Partial<WorkerConfig> = {
90
+ cache: {
91
+ enabled: true,
92
+ defaultTTL: 300,
93
+ paths: {
94
+ '/api/subscriptions': 60,
95
+ '/api/pricing': 3600,
96
+ '/api/features': 3600,
97
+ },
98
+ },
99
+ rateLimit: {
100
+ enabled: true,
101
+ maxRequests: 50,
102
+ window: 60,
103
+ },
104
+ ai: {
105
+ enabled: true,
106
+ },
107
+ workflows: {
108
+ enabled: true,
109
+ },
110
+ };
111
+
112
+ /**
113
+ * API Gateway Configuration
114
+ */
115
+ export const apiGatewayConfig: Partial<WorkerConfig> = {
116
+ cache: {
117
+ enabled: true,
118
+ defaultTTL: 60,
119
+ },
120
+ rateLimit: {
121
+ enabled: true,
122
+ maxRequests: 1000,
123
+ window: 60,
124
+ },
125
+ cors: {
126
+ enabled: true,
127
+ allowedOrigins: ['*'],
128
+ allowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
129
+ allowedHeaders: ['*'],
130
+ maxAge: 86400,
131
+ },
132
+ analytics: {
133
+ enabled: true,
134
+ },
135
+ };
136
+
137
+ /**
138
+ * CDN Configuration
139
+ */
140
+ export const cdnConfig: Partial<WorkerConfig> = {
141
+ cache: {
142
+ enabled: true,
143
+ defaultTTL: 86400, // 24 hours
144
+ paths: {
145
+ '/static/*': 86400,
146
+ '/assets/*': 86400,
147
+ '/images/*': 86400,
148
+ },
149
+ },
150
+ rateLimit: {
151
+ enabled: false,
152
+ },
153
+ compression: {
154
+ enabled: true,
155
+ types: ['text/*', 'application/json', 'application/javascript'],
156
+ },
157
+ imageOptimization: {
158
+ enabled: true,
159
+ formats: ['webp', 'avif'],
160
+ quality: 80,
161
+ },
162
+ };
163
+
164
+ /**
165
+ * AI-First App Configuration
166
+ */
167
+ export const aiFirstConfig: Partial<WorkerConfig> = {
168
+ cache: {
169
+ enabled: true,
170
+ defaultTTL: 300,
171
+ },
172
+ rateLimit: {
173
+ enabled: true,
174
+ maxRequests: 30,
175
+ window: 60,
176
+ },
177
+ ai: {
178
+ enabled: true,
179
+ gateway: {
180
+ providers: [
181
+ {
182
+ id: 'workers-ai',
183
+ name: 'Workers AI',
184
+ type: 'workers-ai',
185
+ baseURL: '',
186
+ apiKey: '',
187
+ models: ['@cf/meta/llama-3.1-8b-instruct'],
188
+ weight: 2,
189
+ },
190
+ {
191
+ id: 'openai',
192
+ name: 'OpenAI',
193
+ type: 'openai',
194
+ baseURL: 'https://api.openai.com/v1',
195
+ apiKey: '',
196
+ models: ['gpt-4', 'gpt-3.5-turbo'],
197
+ fallback: 'workers-ai',
198
+ weight: 1,
199
+ },
200
+ ],
201
+ cacheEnabled: true,
202
+ cacheTTL: 7200, // 2 hours
203
+ rateLimiting: true,
204
+ analytics: true,
205
+ },
206
+ },
207
+ workflows: {
208
+ enabled: true,
209
+ },
210
+ };
211
+
212
+ /**
213
+ * Minimal Configuration (development)
214
+ */
215
+ export const minimalConfig: Partial<WorkerConfig> = {
216
+ cache: {
217
+ enabled: false,
218
+ },
219
+ rateLimit: {
220
+ enabled: false,
221
+ },
222
+ cors: {
223
+ enabled: true,
224
+ allowedOrigins: ['*'],
225
+ },
226
+ };
227
+
228
+ // ============================================================
229
+ // Config Mergers
230
+ // ============================================================
231
+
232
+ /**
233
+ * Deep merge configs
234
+ */
235
+ export function mergeConfigs<T extends Record<string, any>>(
236
+ base: T,
237
+ ...overrides: Partial<T>[]
238
+ ): T {
239
+ return overrides.reduce((acc, override) => {
240
+ return deepMerge(acc, override);
241
+ }, base);
242
+ }
243
+
244
+ function deepMerge<T>(target: T, source: Partial<T>): T {
245
+ const output = { ...target } as T;
246
+
247
+ if (isObject(target) && isObject(source)) {
248
+ Object.keys(source).forEach((key) => {
249
+ if (isObject(source[key as keyof T])) {
250
+ if (!(key in target)) {
251
+ Object.assign(output, { [key]: source[key as keyof T] });
252
+ } else {
253
+ (output as any)[key] = deepMerge(target[key as keyof T], source[key as keyof T]);
254
+ }
255
+ } else {
256
+ Object.assign(output, { [key]: source[key as keyof T] });
257
+ }
258
+ });
259
+ }
260
+
261
+ return output;
262
+ }
263
+
264
+ function isObject(item: unknown): item is Record<string, unknown> {
265
+ return Boolean(item && typeof item === 'object' && !Array.isArray(item));
266
+ }
267
+
268
+ // ============================================================
269
+ // Config Validators
270
+ // ============================================================
271
+
272
+ /**
273
+ * Validate worker config
274
+ */
275
+ export function validateConfig(config: WorkerConfig): {
276
+ valid: boolean;
277
+ errors: string[];
278
+ } {
279
+ const errors: string[] = [];
280
+
281
+ // Validate cache
282
+ if (config.cache?.enabled && config.cache.defaultTTL < 0) {
283
+ errors.push('Cache defaultTTL must be >= 0');
284
+ }
285
+
286
+ // Validate rate limit
287
+ if (config.rateLimit?.enabled && config.rateLimit.maxRequests < 1) {
288
+ errors.push('Rate limit maxRequests must be >= 1');
289
+ }
290
+
291
+ // Validate AI
292
+ if (config.ai?.enabled && (!config.ai.gateway || config.ai.gateway.providers.length === 0)) {
293
+ errors.push('AI gateway must have at least one provider when enabled');
294
+ }
295
+
296
+ // Validate workflows
297
+ if (config.workflows?.enabled && config.workflows.maxExecutionTime < 1) {
298
+ errors.push('Workflow maxExecutionTime must be >= 1');
299
+ }
300
+
301
+ return {
302
+ valid: errors.length === 0,
303
+ errors,
304
+ };
305
+ }
306
+
307
+ // ============================================================
308
+ // Config Builders (Fluent API)
309
+ // ============================================================
310
+
311
+ export class ConfigBuilder {
312
+ private config: Partial<WorkerConfig> = {};
313
+
314
+ static create(): ConfigBuilder {
315
+ return new ConfigBuilder();
316
+ }
317
+
318
+ withCache(config: Partial<NonNullable<WorkerConfig['cache']>>): ConfigBuilder {
319
+ this.config.cache = { ...this.config.cache, ...config };
320
+ return this;
321
+ }
322
+
323
+ withRateLimit(config: Partial<NonNullable<WorkerConfig['rateLimit']>>): ConfigBuilder {
324
+ this.config.rateLimit = { ...this.config.rateLimit, ...config };
325
+ return this;
326
+ }
327
+
328
+ withAI(config: Partial<NonNullable<WorkerConfig['ai']>>): ConfigBuilder {
329
+ this.config.ai = { ...this.config.ai, ...config };
330
+ return this;
331
+ }
332
+
333
+ withWorkflows(config: Partial<NonNullable<WorkerConfig['workflows']>>): ConfigBuilder {
334
+ this.config.workflows = { ...this.config.workflows, ...config };
335
+ return this;
336
+ }
337
+
338
+ withCORS(config: Partial<NonNullable<WorkerConfig['cors']>>): ConfigBuilder {
339
+ this.config.cors = { ...this.config.cors, ...config };
340
+ return this;
341
+ }
342
+
343
+ withAnalytics(config: Partial<NonNullable<WorkerConfig['analytics']>>): ConfigBuilder {
344
+ this.config.analytics = { ...this.config.analytics, ...config };
345
+ return this;
346
+ }
347
+
348
+ withCompression(config: Partial<NonNullable<WorkerConfig['compression']>>): ConfigBuilder {
349
+ this.config.compression = { ...this.config.compression, ...config };
350
+ return this;
351
+ }
352
+
353
+ withImageOptimization(config: Partial<NonNullable<WorkerConfig['imageOptimization']>>): ConfigBuilder {
354
+ this.config.imageOptimization = { ...this.config.imageOptimization, ...config };
355
+ return this;
356
+ }
357
+
358
+ withQueues(config: Partial<NonNullable<WorkerConfig['queues']>>): ConfigBuilder {
359
+ this.config.queues = { ...this.config.queues, ...config };
360
+ return this;
361
+ }
362
+
363
+ withScheduledTasks(config: Partial<NonNullable<WorkerConfig['scheduledTasks']>>): ConfigBuilder {
364
+ this.config.scheduledTasks = { ...this.config.scheduledTasks, ...config };
365
+ return this;
366
+ }
367
+
368
+ build(): Partial<WorkerConfig> {
369
+ return this.config;
370
+ }
371
+ }
372
+
373
+ // ============================================================
374
+ // Environment-based Config Loader
375
+ // ============================================================
376
+
377
+ export interface EnvironmentConfig {
378
+ environment: 'development' | 'staging' | 'production';
379
+ envVars: Record<string, string>;
380
+ }
381
+
382
+ /**
383
+ * Load config from environment variables
384
+ */
385
+ export function loadConfigFromEnv(
386
+ env: Record<string, string | undefined>
387
+ ): Partial<WorkerConfig> {
388
+ const config: Partial<WorkerConfig> = {};
389
+
390
+ // Cache
391
+ if (env.CF_CACHE_ENABLED === 'true') {
392
+ config.cache = {
393
+ enabled: true,
394
+ defaultTTL: parseInt(env.CF_CACHE_DEFAULT_TTL || '300', 10),
395
+ };
396
+ }
397
+
398
+ // Rate Limit
399
+ if (env.CF_RATE_LIMIT_ENABLED === 'true') {
400
+ config.rateLimit = {
401
+ enabled: true,
402
+ maxRequests: parseInt(env.CF_RATE_LIMIT_MAX || '100', 10),
403
+ window: parseInt(env.CF_RATE_LIMIT_WINDOW || '60', 10),
404
+ };
405
+ }
406
+
407
+ // AI
408
+ if (env.CF_AI_ENABLED === 'true') {
409
+ config.ai = {
410
+ enabled: true,
411
+ gateway: {
412
+ gatewayId: env.CF_AI_GATEWAY_ID || 'default',
413
+ providers: JSON.parse(env.CF_AI_PROVIDERS || '[]'),
414
+ cacheEnabled: env.CF_AI_CACHE_ENABLED === 'true',
415
+ cacheTTL: parseInt(env.CF_AI_CACHE_TTL || '3600', 10),
416
+ },
417
+ };
418
+ }
419
+
420
+ // Workflows
421
+ if (env.CF_WORKFLOWS_ENABLED === 'true') {
422
+ config.workflows = {
423
+ enabled: true,
424
+ maxExecutionTime: parseInt(env.CF_WORKFLOWS_MAX_TIME || '600', 10),
425
+ defaultRetries: parseInt(env.CF_WORKFLOWS_RETRIES || '3', 10),
426
+ };
427
+ }
428
+
429
+ // CORS
430
+ if (env.CF_CORS_ENABLED === 'true') {
431
+ config.cors = {
432
+ enabled: true,
433
+ allowedOrigins: env.CF_CORS_ORIGINS?.split(',') || ['*'],
434
+ allowedMethods: env.CF_CORS_METHODS?.split(',') || ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
435
+ allowedHeaders: env.CF_CORS_HEADERS?.split(',') || ['*'],
436
+ maxAge: parseInt(env.CF_CORS_MAX_AGE || '86400', 10),
437
+ };
438
+ }
439
+
440
+ return config;
441
+ }
442
+
443
+ /**
444
+ * Get environment-specific config
445
+ */
446
+ export function getEnvironmentConfig(
447
+ environment: 'development' | 'staging' | 'production'
448
+ ): Partial<WorkerConfig> {
449
+ switch (environment) {
450
+ case 'development':
451
+ return mergeConfigs(minimalConfig, {
452
+ cache: { enabled: false },
453
+ rateLimit: { enabled: false },
454
+ cors: { allowedOrigins: ['*'] },
455
+ });
456
+
457
+ case 'staging':
458
+ return mergeConfigs(socialMediaConfig, {
459
+ cache: { defaultTTL: 60 },
460
+ rateLimit: { maxRequests: 200 },
461
+ });
462
+
463
+ case 'production':
464
+ return socialMediaConfig;
465
+
466
+ default:
467
+ return minimalConfig;
468
+ }
469
+ }