@umituz/web-cloudflare 1.4.3 → 1.4.5

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 (44) hide show
  1. package/README.md +24 -29
  2. package/package.json +6 -5
  3. package/src/config/patterns.ts +43 -24
  4. package/src/domain/entities/analytics.entity.ts +18 -35
  5. package/src/domain/entities/d1.entity.ts +27 -0
  6. package/src/domain/entities/image.entity.ts +27 -27
  7. package/src/domain/entities/kv.entity.ts +20 -17
  8. package/src/domain/entities/r2.entity.ts +49 -0
  9. package/src/domain/entities/worker.entity.ts +35 -0
  10. package/src/domains/analytics/entities/index.ts +47 -0
  11. package/src/domains/analytics/index.ts +13 -0
  12. package/src/{infrastructure/services/analytics → domains/analytics/services}/analytics.service.ts +1 -1
  13. package/src/{infrastructure/services/analytics → domains/analytics/services}/index.ts +1 -0
  14. package/src/domains/analytics/types/index.ts +5 -0
  15. package/src/domains/analytics/types/service.interface.ts +12 -0
  16. package/src/domains/images/entities/index.ts +48 -0
  17. package/src/domains/images/index.ts +13 -0
  18. package/src/{infrastructure/services/images → domains/images/services}/images.service.ts +3 -3
  19. package/src/{infrastructure/services/images → domains/images/services}/index.ts +1 -0
  20. package/src/domains/images/types/index.ts +5 -0
  21. package/src/domains/images/types/service.interface.ts +13 -0
  22. package/src/domains/kv/entities/index.ts +34 -0
  23. package/src/domains/kv/index.ts +13 -0
  24. package/src/{infrastructure/services/kv → domains/kv/services}/index.ts +1 -0
  25. package/src/{infrastructure/services/kv → domains/kv/services}/kv.service.ts +2 -2
  26. package/src/domains/kv/types/index.ts +5 -0
  27. package/src/domains/kv/types/service.interface.ts +13 -0
  28. package/src/domains/workers/entities/index.ts +1 -1
  29. package/src/domains/workflows/entities/index.ts +60 -0
  30. package/src/domains/workflows/index.ts +10 -0
  31. package/src/domains/workflows/services/index.ts +6 -0
  32. package/src/{infrastructure/services/workflows/index.ts → domains/workflows/services/workflows.service.ts} +1 -1
  33. package/src/domains/wrangler/entities/index.ts +2 -2
  34. package/src/domains/wrangler/services/wrangler.service.ts +16 -8
  35. package/src/domains/wrangler/types/service.interface.ts +2 -2
  36. package/src/index.ts +4 -4
  37. package/src/infrastructure/middleware/auth.ts +118 -0
  38. package/src/infrastructure/middleware/cache.ts +95 -0
  39. package/src/infrastructure/middleware/cors.ts +95 -0
  40. package/src/infrastructure/middleware/index.ts +20 -3
  41. package/src/infrastructure/middleware/rate-limit.ts +105 -0
  42. package/src/infrastructure/router/index.ts +26 -4
  43. package/src/infrastructure/utils/helpers.ts +25 -11
  44. package/src/infrastructure/utils/utils.util.ts +3 -2
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Analytics Domain
3
+ * Complete Cloudflare Analytics integration
4
+ */
5
+
6
+ // Entities
7
+ export * from './entities';
8
+
9
+ // Types
10
+ export * from './types';
11
+
12
+ // Services
13
+ export * from './services';
@@ -3,7 +3,7 @@
3
3
  * @description Cloudflare Web Analytics operations
4
4
  */
5
5
 
6
- import type { AnalyticsEvent, AnalyticsPageviewEvent, AnalyticsCustomEvent, AnalyticsData } from "../../../domain/entities/analytics.entity";
6
+ import type { AnalyticsEvent, AnalyticsPageviewEvent, AnalyticsCustomEvent, AnalyticsData } from "../entities";
7
7
  import type { IAnalyticsService } from "../../../domain/interfaces/services.interface";
8
8
 
9
9
  export interface AnalyticsClientOptions {
@@ -5,3 +5,4 @@
5
5
 
6
6
  export { AnalyticsService, analyticsService } from "./analytics.service";
7
7
  export type { AnalyticsClientOptions } from "./analytics.service";
8
+ export type { IAnalyticsService } from '../types';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Analytics Domain Types
3
+ */
4
+
5
+ export * from './service.interface';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Analytics Service Interface
3
+ * @description Abstract interface for Analytics operations
4
+ */
5
+
6
+ import type { AnalyticsEvent, AnalyticsData } from '../entities';
7
+
8
+ export interface IAnalyticsService {
9
+ trackEvent(event: AnalyticsEvent): Promise<void>;
10
+ trackPageview(url: string, title: string, referrer?: string): Promise<void>;
11
+ getAnalytics(): Promise<AnalyticsData>;
12
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Image Entity
3
+ * @description Cloudflare Images configuration and types
4
+ */
5
+
6
+ export interface ImageConfig {
7
+ readonly account: string;
8
+ readonly customDomain?: string;
9
+ }
10
+
11
+ export interface ImageVariant {
12
+ readonly variant: string;
13
+ readonly width?: number;
14
+ readonly height?: number;
15
+ readonly fit?: "scale-down" | "contain" | "cover" | "crop" | "pad";
16
+ readonly format?: "jpeg" | "png" | "gif" | "webp" | "avif";
17
+ readonly quality?: number;
18
+ }
19
+
20
+ export interface ImageUploadResult {
21
+ readonly id: string;
22
+ readonly filename: string;
23
+ readonly uploaded: Date;
24
+ readonly variants: readonly string[];
25
+ readonly requireSignedURLs: boolean;
26
+ }
27
+
28
+ export interface ImageUploadOptions {
29
+ readonly metadata?: Record<string, string>;
30
+ readonly requireSignedURLs?: boolean;
31
+ readonly variants?: readonly ImageVariant[];
32
+ }
33
+
34
+ export interface ImageTransformation {
35
+ readonly width?: number;
36
+ readonly height?: number;
37
+ readonly fit?: "scale-down" | "contain" | "cover" | "crop" | "pad";
38
+ readonly format?: "jpeg" | "png" | "gif" | "webp" | "avif";
39
+ readonly quality?: number;
40
+ readonly rotate?: number;
41
+ readonly flip?: boolean;
42
+ readonly flop?: boolean;
43
+ }
44
+
45
+ export interface SignedURL {
46
+ readonly url: string;
47
+ readonly expiresAt: Date;
48
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Images Domain
3
+ * Complete Cloudflare Images integration
4
+ */
5
+
6
+ // Entities
7
+ export * from './entities';
8
+
9
+ // Types
10
+ export * from './types';
11
+
12
+ // Services
13
+ export * from './services';
@@ -3,10 +3,10 @@
3
3
  * @description Cloudflare Images operations
4
4
  */
5
5
 
6
- import type { ImageUploadResult, ImageUploadOptions, ImageTransformation, SignedURL } from "../../../domain/entities/image.entity";
6
+ import type { ImageUploadResult, ImageUploadOptions, ImageTransformation, SignedURL } from "../entities";
7
7
  import type { IImageService } from "../../../domain/interfaces/services.interface";
8
- import { validationUtils, transformUtils } from "../../utils";
9
- import { MAX_IMAGE_SIZE, ALLOWED_IMAGE_TYPES } from "../../constants";
8
+ import { validationUtils, transformUtils } from "../../../infrastructure/utils";
9
+ import { MAX_IMAGE_SIZE, ALLOWED_IMAGE_TYPES } from "../../../infrastructure/constants";
10
10
 
11
11
  export interface ImagesClientOptions {
12
12
  readonly accountId: string;
@@ -5,3 +5,4 @@
5
5
 
6
6
  export { ImagesService, imagesService } from "./images.service";
7
7
  export type { ImagesClientOptions } from "./images.service";
8
+ export type { IImageService } from '../types';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Images Domain Types
3
+ */
4
+
5
+ export * from './service.interface';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Images Service Interface
3
+ * @description Abstract interface for Images operations
4
+ */
5
+
6
+ import type { ImageUploadResult, ImageUploadOptions, SignedURL, ImageTransformation } from '../entities';
7
+
8
+ export interface IImageService {
9
+ upload(file: File | Blob, options?: ImageUploadOptions): Promise<ImageUploadResult>;
10
+ getSignedURL(imageId: string, expiresIn?: number): Promise<SignedURL>;
11
+ getTransformedURL(imageId: string, transform: ImageTransformation): Promise<string>;
12
+ delete(imageId: string): Promise<boolean>;
13
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * KV Entity
3
+ * @description Cloudflare KV configuration and types
4
+ */
5
+
6
+ export interface KVNamespaceConfig {
7
+ readonly namespace: string;
8
+ readonly ttl?: number;
9
+ }
10
+
11
+ export interface KVEntry<T = unknown> {
12
+ readonly key: string;
13
+ readonly value: T;
14
+ readonly metadata?: Record<string, unknown>;
15
+ readonly expiration?: number;
16
+ }
17
+
18
+ export interface KVListOptions {
19
+ readonly limit?: number;
20
+ readonly cursor?: string;
21
+ readonly prefix?: string;
22
+ }
23
+
24
+ export interface KVListResult {
25
+ readonly keys: readonly KVKey[];
26
+ readonly list_complete: boolean;
27
+ readonly cursor?: string;
28
+ }
29
+
30
+ export interface KVKey {
31
+ readonly name: string;
32
+ readonly metadata?: Record<string, unknown>;
33
+ readonly expiration?: number;
34
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * KV Domain
3
+ * Complete Cloudflare KV key-value storage integration
4
+ */
5
+
6
+ // Entities
7
+ export * from './entities';
8
+
9
+ // Types
10
+ export * from './types';
11
+
12
+ // Services
13
+ export * from './services';
@@ -5,3 +5,4 @@
5
5
 
6
6
  export { KVService, kvService } from "./kv.service";
7
7
  export type { KVCacheOptions } from "./kv.service";
8
+ export type { IKVService } from '../types';
@@ -3,9 +3,9 @@
3
3
  * @description Cloudflare KV key-value storage operations
4
4
  */
5
5
 
6
- import type { KVEntry, KVListOptions, KVListResult } from "../../../domain/entities/kv.entity";
6
+ import type { KVEntry, KVListOptions, KVListResult } from "../entities";
7
7
  import type { IKVService } from "../../../domain/interfaces/services.interface";
8
- import { validationUtils, cacheUtils } from "../../utils";
8
+ import { validationUtils, cacheUtils } from "../../../infrastructure/utils";
9
9
 
10
10
  export interface KVCacheOptions {
11
11
  readonly namespace: string;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * KV Domain Types
3
+ */
4
+
5
+ export * from './service.interface';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * KV Service Interface
3
+ * @description Abstract interface for KV storage operations
4
+ */
5
+
6
+ import type { KVListOptions, KVListResult } from '../entities';
7
+
8
+ export interface IKVService {
9
+ get<T>(key: string): Promise<T | null>;
10
+ put<T>(key: string, value: T, options?: { ttl?: number }): Promise<void>;
11
+ delete(key: string): Promise<boolean>;
12
+ list(options?: KVListOptions): Promise<KVListResult>;
13
+ }
@@ -11,7 +11,7 @@ export interface WorkerResponse extends Response {
11
11
  waitUntil?: (promise: Promise<unknown>) => void;
12
12
  }
13
13
 
14
- export interface WorkerConfig {
14
+ export interface CloudflareWorkerConfig {
15
15
  readonly name: string;
16
16
  readonly routes?: string[];
17
17
  readonly schedule?: string;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Workflows Domain Entities
3
+ * @description Workflow orchestration entities for Cloudflare Workers
4
+ */
5
+
6
+ /**
7
+ * Workflow step definition
8
+ */
9
+ export interface WorkflowStep {
10
+ id: string;
11
+ name: string;
12
+ handler: string;
13
+ timeout?: number;
14
+ retryPolicy?: {
15
+ maxAttempts: number;
16
+ backoffMultiplier: number;
17
+ initialDelay: number;
18
+ maxDelay: number;
19
+ };
20
+ dependencies?: string[];
21
+ }
22
+
23
+ /**
24
+ * Workflow definition
25
+ */
26
+ export interface WorkflowDefinition {
27
+ id: string;
28
+ name: string;
29
+ description?: string;
30
+ steps: WorkflowStep[];
31
+ }
32
+
33
+ /**
34
+ * Workflow execution state
35
+ */
36
+ export interface WorkflowExecution {
37
+ id: string;
38
+ workflowId: string;
39
+ status: 'pending' | 'running' | 'completed' | 'failed';
40
+ currentStep?: string;
41
+ startedAt: number;
42
+ completedAt?: number;
43
+ input: unknown;
44
+ output?: unknown;
45
+ error?: string;
46
+ }
47
+
48
+ /**
49
+ * Workflow config
50
+ */
51
+ export interface CloudflareWorkflowConfig {
52
+ enabled: boolean;
53
+ maxExecutionTime: number;
54
+ defaultRetries: number;
55
+ workflows?: Record<string, WorkflowDefinition>;
56
+ storage?: 'kv' | 'd1';
57
+ }
58
+
59
+ // Type alias for compatibility
60
+ export type WorkflowConfig = CloudflareWorkflowConfig;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Workflows Domain
3
+ * Complete workflow orchestration integration
4
+ */
5
+
6
+ // Entities
7
+ export * from './entities';
8
+
9
+ // Services
10
+ export * from './services';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Workflows Service
3
+ * Subpath: @umituz/web-cloudflare/workflows
4
+ */
5
+
6
+ export * from './workflows.service';
@@ -11,7 +11,7 @@ import type {
11
11
  MediaProcessingWorkflow,
12
12
  AIGenerationWorkflow,
13
13
  BatchOperationWorkflow,
14
- } from '../../domain/workflows.entity';
14
+ } from '../entities';
15
15
 
16
16
  export interface WorkflowServiceConfig {
17
17
  KV?: KVNamespace;
@@ -132,9 +132,9 @@ export interface WorkerVersionInfo {
132
132
  }
133
133
 
134
134
  /**
135
- * Analytics data
135
+ * Wrangler analytics data
136
136
  */
137
- export interface AnalyticsData {
137
+ export interface WranglerAnalyticsData {
138
138
  requests?: number;
139
139
  errors?: number;
140
140
  statusCodes?: Record<string, number>;
@@ -118,6 +118,14 @@ export class WranglerService implements IWranglerService {
118
118
  }
119
119
  }
120
120
 
121
+ /**
122
+ * Convert string result to void result
123
+ */
124
+ private asVoidResult(result: WranglerResult<string>): WranglerResult<void> {
125
+ const { data, ...rest } = result;
126
+ return rest;
127
+ }
128
+
121
129
  // ==================== Authentication ====================
122
130
 
123
131
  async login(options?: WranglerCommandOptions): Promise<WranglerResult<AuthInfo>> {
@@ -132,7 +140,7 @@ export class WranglerService implements IWranglerService {
132
140
  }
133
141
 
134
142
  async logout(options?: WranglerCommandOptions): Promise<WranglerResult<void>> {
135
- return this.execute(['logout'], options);
143
+ return this.asVoidResult(await this.execute(['logout'], options));
136
144
  }
137
145
 
138
146
  async whoami(options?: WranglerCommandOptions): Promise<WranglerResult<AuthInfo>> {
@@ -158,7 +166,7 @@ export class WranglerService implements IWranglerService {
158
166
  if (template) {
159
167
  args.push('--template', template);
160
168
  }
161
- return this.execute(args, options);
169
+ return this.asVoidResult(await this.execute(args, options));
162
170
  }
163
171
 
164
172
  async dev(
@@ -237,7 +245,7 @@ export class WranglerService implements IWranglerService {
237
245
  value: string,
238
246
  options?: WranglerCommandOptions
239
247
  ): Promise<WranglerResult<void>> {
240
- return this.execute(['kv:key', 'put', '--namespace-id', namespaceId, key, value], options);
248
+ return this.asVoidResult(await this.execute(['kv:key', 'put', '--namespace-id', namespaceId, key, value], options));
241
249
  }
242
250
 
243
251
  async kvKeyGet(
@@ -253,7 +261,7 @@ export class WranglerService implements IWranglerService {
253
261
  key: string,
254
262
  options?: WranglerCommandOptions
255
263
  ): Promise<WranglerResult<void>> {
256
- return this.execute(['kv:key', 'delete', '--namespace-id', namespaceId, key], options);
264
+ return this.asVoidResult(await this.execute(['kv:key', 'delete', '--namespace-id', namespaceId, key], options));
257
265
  }
258
266
 
259
267
  // ==================== R2 Operations ====================
@@ -289,7 +297,7 @@ export class WranglerService implements IWranglerService {
289
297
  bucketName: string,
290
298
  options?: WranglerCommandOptions
291
299
  ): Promise<WranglerResult<void>> {
292
- return this.execute(['r2', 'bucket', 'delete', bucketName], options);
300
+ return this.asVoidResult(await this.execute(['r2', 'bucket', 'delete', bucketName], options));
293
301
  }
294
302
 
295
303
  async r2ObjectPut(
@@ -298,7 +306,7 @@ export class WranglerService implements IWranglerService {
298
306
  file: string,
299
307
  options?: WranglerCommandOptions
300
308
  ): Promise<WranglerResult<void>> {
301
- return this.execute(['r2', 'object', 'put', bucketName, key, '--file', file], options);
309
+ return this.asVoidResult(await this.execute(['r2', 'object', 'put', bucketName, key, '--file', file], options));
302
310
  }
303
311
 
304
312
  // ==================== D1 Operations ====================
@@ -412,7 +420,7 @@ export class WranglerService implements IWranglerService {
412
420
  secretName: string,
413
421
  options?: WranglerCommandOptions
414
422
  ): Promise<WranglerResult<void>> {
415
- return this.execute(['secret', 'delete', secretName], options);
423
+ return this.asVoidResult(await this.execute(['secret', 'delete', secretName], options));
416
424
  }
417
425
 
418
426
  // ==================== Monitoring ====================
@@ -446,7 +454,7 @@ export class WranglerService implements IWranglerService {
446
454
  versionId: string,
447
455
  options?: WranglerCommandOptions
448
456
  ): Promise<WranglerResult<void>> {
449
- return this.execute(['versions', 'rollback', '--version-id', versionId], options);
457
+ return this.asVoidResult(await this.execute(['versions', 'rollback', '--version-id', versionId], options));
450
458
  }
451
459
 
452
460
  // ==================== Generic Command Execution ====================
@@ -12,8 +12,8 @@ import type {
12
12
  D1DatabaseInfo,
13
13
  SecretInfo,
14
14
  WorkerVersionInfo,
15
- AnalyticsData,
16
- } from '../entities/wrangler.entity';
15
+ WranglerAnalyticsData,
16
+ } from '../entities';
17
17
 
18
18
  export interface IWranglerService {
19
19
  // Authentication
package/src/index.ts CHANGED
@@ -31,10 +31,10 @@ export * from "./domains/workers";
31
31
  export * from "./domains/ai-gateway";
32
32
  export * from "./domains/r2";
33
33
  export * from "./domains/d1";
34
- export * from "./infrastructure/services/kv";
35
- export * from "./infrastructure/services/images";
36
- export * from "./infrastructure/services/analytics";
37
- export * from "./infrastructure/services/workflows";
34
+ export * from "./domains/kv";
35
+ export * from "./domains/images";
36
+ export * from "./domains/analytics";
37
+ export * from "./domains/workflows";
38
38
 
39
39
  // Infrastructure - Router, Middleware, Utils
40
40
  export * from "./infrastructure/router";
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Auth Middleware
3
+ * @description Authentication middleware for Cloudflare Workers
4
+ */
5
+
6
+ export interface AuthConfig {
7
+ enabled: boolean;
8
+ type: 'bearer' | 'apikey' | 'basic';
9
+ token?: string;
10
+ apiKeyHeader?: string;
11
+ apiKeyValue?: string;
12
+ username?: string;
13
+ password?: string;
14
+ }
15
+
16
+ /**
17
+ * Require authentication
18
+ */
19
+ export async function requireAuth(
20
+ request: Request,
21
+ config: AuthConfig
22
+ ): Promise<Response | null> {
23
+ if (!config.enabled) {
24
+ return null;
25
+ }
26
+
27
+ const authHeader = request.headers.get('Authorization');
28
+
29
+ if (!authHeader) {
30
+ return new Response(
31
+ JSON.stringify({ error: 'Missing authorization header' }),
32
+ {
33
+ status: 401,
34
+ headers: { 'Content-Type': 'application/json' },
35
+ }
36
+ );
37
+ }
38
+
39
+ switch (config.type) {
40
+ case 'bearer':
41
+ if (!authHeader.startsWith('Bearer ')) {
42
+ return new Response(
43
+ JSON.stringify({ error: 'Invalid authorization type' }),
44
+ {
45
+ status: 401,
46
+ headers: { 'Content-Type': 'application/json' },
47
+ }
48
+ );
49
+ }
50
+ const token = authHeader.substring(7);
51
+ if (token !== config.token) {
52
+ return new Response(
53
+ JSON.stringify({ error: 'Invalid token' }),
54
+ {
55
+ status: 401,
56
+ headers: { 'Content-Type': 'application/json' },
57
+ }
58
+ );
59
+ }
60
+ break;
61
+
62
+ case 'apikey':
63
+ const apiKey = request.headers.get(config.apiKeyHeader || 'X-API-Key');
64
+ if (apiKey !== config.apiKeyValue) {
65
+ return new Response(
66
+ JSON.stringify({ error: 'Invalid API key' }),
67
+ {
68
+ status: 401,
69
+ headers: { 'Content-Type': 'application/json' },
70
+ }
71
+ );
72
+ }
73
+ break;
74
+
75
+ case 'basic':
76
+ if (!authHeader.startsWith('Basic ')) {
77
+ return new Response(
78
+ JSON.stringify({ error: 'Invalid authorization type' }),
79
+ {
80
+ status: 401,
81
+ headers: { 'Content-Type': 'application/json' },
82
+ }
83
+ );
84
+ }
85
+ const credentials = atob(authHeader.substring(6));
86
+ const [username, password] = credentials.split(':');
87
+ if (username !== config.username || password !== config.password) {
88
+ return new Response(
89
+ JSON.stringify({ error: 'Invalid credentials' }),
90
+ {
91
+ status: 401,
92
+ headers: { 'Content-Type': 'application/json' },
93
+ }
94
+ );
95
+ }
96
+ break;
97
+ }
98
+
99
+ return null;
100
+ }
101
+
102
+ /**
103
+ * Add user context to request
104
+ */
105
+ export function addUserContext(request: Request, user: {
106
+ id: string;
107
+ [key: string]: unknown;
108
+ }): Request {
109
+ const headers = new Headers(request.headers);
110
+ headers.set('X-User-ID', user.id);
111
+ headers.set('X-User-Context', JSON.stringify(user));
112
+
113
+ return new Request(request.url, {
114
+ method: request.method,
115
+ headers,
116
+ body: request.body,
117
+ });
118
+ }