@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
@@ -0,0 +1,549 @@
1
+ /**
2
+ * Cloudflare Worker Router
3
+ * @description Express-like router for Cloudflare Workers
4
+ */
5
+
6
+ import { json, notFound, badRequest } from '../utils/helpers';
7
+
8
+ // ============================================================
9
+ // Route Handler Types
10
+ // ============================================================
11
+
12
+ export type RouteHandler = (
13
+ request: Request,
14
+ params?: Record<string, string>,
15
+ env?: Env,
16
+ ctx?: ExecutionContext
17
+ ) => Promise<Response> | Response;
18
+
19
+ export type Middleware = (
20
+ request: Request,
21
+ env?: Env,
22
+ ctx?: ExecutionContext
23
+ ) => Promise<Response | null> | Response | null;
24
+
25
+ export interface Route {
26
+ method: string;
27
+ pattern: URLPattern;
28
+ handler: RouteHandler;
29
+ middlewares?: Middleware[];
30
+ }
31
+
32
+ // ============================================================
33
+ // Router Class
34
+ // ============================================================
35
+
36
+ export class Router {
37
+ private routes: Route[] = [];
38
+ private globalMiddlewares: Middleware[] = [];
39
+
40
+ /**
41
+ * Add global middleware
42
+ */
43
+ use(middleware: Middleware): Router {
44
+ this.globalMiddlewares.push(middleware);
45
+ return this;
46
+ }
47
+
48
+ /**
49
+ * Add GET route
50
+ */
51
+ get(path: string, handler: RouteHandler, middlewares?: Middleware[]): Router {
52
+ return this.addRoute('GET', path, handler, middlewares);
53
+ }
54
+
55
+ /**
56
+ * Add POST route
57
+ */
58
+ post(path: string, handler: RouteHandler, middlewares?: Middleware[]): Router {
59
+ return this.addRoute('POST', path, handler, middlewares);
60
+ }
61
+
62
+ /**
63
+ * Add PUT route
64
+ */
65
+ put(path: string, handler: RouteHandler, middlewares?: Middleware[]): Router {
66
+ return this.addRoute('PUT', path, handler, middlewares);
67
+ }
68
+
69
+ /**
70
+ * Add PATCH route
71
+ */
72
+ patch(path: string, handler: RouteHandler, middlewares?: Middleware[]): Router {
73
+ return this.addRoute('PATCH', path, handler, middlewares);
74
+ }
75
+
76
+ /**
77
+ * Add DELETE route
78
+ */
79
+ delete(path: string, handler: RouteHandler, middlewares?: Middleware[]): Router {
80
+ return this.addRoute('DELETE', path, handler, middlewares);
81
+ }
82
+
83
+ /**
84
+ * Add HEAD route
85
+ */
86
+ head(path: string, handler: RouteHandler, middlewares?: Middleware[]): Router {
87
+ return this.addRoute('HEAD', path, handler, middlewares);
88
+ }
89
+
90
+ /**
91
+ * Add OPTIONS route
92
+ */
93
+ options(path: string, handler: RouteHandler, middlewares?: Middleware[]): Router {
94
+ return this.addRoute('OPTIONS', path, handler, middlewares);
95
+ }
96
+
97
+ /**
98
+ * Add route for any method
99
+ */
100
+ all(path: string, handler: RouteHandler, middlewares?: Middleware[]): Router {
101
+ return this.addRoute('*', path, handler, middlewares);
102
+ }
103
+
104
+ /**
105
+ * Add route
106
+ */
107
+ private addRoute(
108
+ method: string,
109
+ path: string,
110
+ handler: RouteHandler,
111
+ middlewares?: Middleware[]
112
+ ): Router {
113
+ // Convert path pattern to URLPattern
114
+ const pattern = new URLPattern({ pathname: path });
115
+
116
+ this.routes.push({
117
+ method,
118
+ pattern,
119
+ handler,
120
+ middlewares,
121
+ });
122
+
123
+ return this;
124
+ }
125
+
126
+ /**
127
+ * Group routes with prefix
128
+ */
129
+ group(prefix: string, callback: (router: Router) => void): Router {
130
+ const groupedRouter = new Router();
131
+ callback(groupedRouter);
132
+
133
+ // Add all routes from grouped router with prefix
134
+ groupedRouter.routes.forEach((route) => {
135
+ const prefixedPath = prefix + route.pattern.pathname;
136
+ this.routes.push({
137
+ ...route,
138
+ pattern: new URLPattern({ pathname: prefixedPath }),
139
+ });
140
+ });
141
+
142
+ return this;
143
+ }
144
+
145
+ /**
146
+ * Handle request
147
+ */
148
+ async handle(
149
+ request: Request,
150
+ env?: Env,
151
+ ctx?: ExecutionContext
152
+ ): Promise<Response> {
153
+ const url = new URL(request.url);
154
+ const method = request.method;
155
+
156
+ // Run global middlewares
157
+ for (const middleware of this.globalMiddlewares) {
158
+ const response = await middleware(request, env, ctx);
159
+ if (response) {
160
+ return response;
161
+ }
162
+ }
163
+
164
+ // Find matching route
165
+ for (const route of this.routes) {
166
+ // Check method (wildcard matches all)
167
+ if (route.method !== '*' && route.method !== method) {
168
+ continue;
169
+ }
170
+
171
+ // Check path pattern
172
+ const match = route.pattern.exec(url);
173
+ if (!match) {
174
+ continue;
175
+ }
176
+
177
+ // Extract params
178
+ const params = this.extractParams(match);
179
+
180
+ // Run route middlewares
181
+ if (route.middlewares) {
182
+ for (const middleware of route.middlewares) {
183
+ const response = await middleware(request, env, ctx);
184
+ if (response) {
185
+ return response;
186
+ }
187
+ }
188
+ }
189
+
190
+ // Run handler
191
+ try {
192
+ return await route.handler(request, params, env, ctx);
193
+ } catch (error) {
194
+ return json(
195
+ {
196
+ error: error instanceof Error ? error.message : 'Internal Server Error',
197
+ },
198
+ 500
199
+ );
200
+ }
201
+ }
202
+
203
+ // No route matched
204
+ return notFound();
205
+ }
206
+
207
+ /**
208
+ * Extract params from URLPattern result
209
+ */
210
+ private extractParams(
211
+ match: URLPatternResult | null
212
+ ): Record<string, string> {
213
+ if (!match) {
214
+ return {};
215
+ }
216
+
217
+ const params: Record<string, string> = {};
218
+
219
+ // Extract pathname groups
220
+ if (match.pathname?.groups) {
221
+ Object.assign(params, match.pathname.groups);
222
+ }
223
+
224
+ return params;
225
+ }
226
+
227
+ /**
228
+ * Get all registered routes
229
+ */
230
+ getRoutes(): Array<{ method: string; path: string }> {
231
+ return this.routes.map((route) => ({
232
+ method: route.method,
233
+ path: route.pattern.pathname,
234
+ }));
235
+ }
236
+
237
+ /**
238
+ * Clear all routes
239
+ */
240
+ clear(): Router {
241
+ this.routes = [];
242
+ this.globalMiddlewares = [];
243
+ return this;
244
+ }
245
+ }
246
+
247
+ // ============================================================
248
+ // Route Builder (Fluent API)
249
+ // ============================================================
250
+
251
+ export class RouteBuilder {
252
+ private router: Router;
253
+
254
+ constructor() {
255
+ this.router = new Router();
256
+ }
257
+
258
+ /**
259
+ * Define route with fluent API
260
+ */
261
+ route(method: string, path: string, handler: RouteHandler): RouteBuilder {
262
+ switch (method.toUpperCase()) {
263
+ case 'GET':
264
+ this.router.get(path, handler);
265
+ break;
266
+ case 'POST':
267
+ this.router.post(path, handler);
268
+ break;
269
+ case 'PUT':
270
+ this.router.put(path, handler);
271
+ break;
272
+ case 'PATCH':
273
+ this.router.patch(path, handler);
274
+ break;
275
+ case 'DELETE':
276
+ this.router.delete(path, handler);
277
+ break;
278
+ case 'HEAD':
279
+ this.router.head(path, handler);
280
+ break;
281
+ case 'OPTIONS':
282
+ this.router.options(path, handler);
283
+ break;
284
+ default:
285
+ this.router.all(path, handler);
286
+ }
287
+ return this;
288
+ }
289
+
290
+ /**
291
+ * Add middleware
292
+ */
293
+ use(middleware: Middleware): RouteBuilder {
294
+ this.router.use(middleware);
295
+ return this;
296
+ }
297
+
298
+ /**
299
+ * Get router instance
300
+ */
301
+ build(): Router {
302
+ return this.router;
303
+ }
304
+ }
305
+
306
+ // ============================================================
307
+ // Controller Helpers
308
+ // ============================================================
309
+
310
+ /**
311
+ * Create resource routes (CRUD)
312
+ */
313
+ export function resource(
314
+ router: Router,
315
+ path: string,
316
+ controller: {
317
+ index?: RouteHandler;
318
+ show?: RouteHandler;
319
+ create?: RouteHandler;
320
+ update?: RouteHandler;
321
+ delete?: RouteHandler;
322
+ }
323
+ ): Router {
324
+ if (controller.index) {
325
+ router.get(path, controller.index);
326
+ }
327
+ if (controller.show) {
328
+ router.get(`${path}/:id`, controller.show);
329
+ }
330
+ if (controller.create) {
331
+ router.post(path, controller.create);
332
+ }
333
+ if (controller.update) {
334
+ router.put(`${path}/:id`, controller.update);
335
+ router.patch(`${path}/:id`, controller.update);
336
+ }
337
+ if (controller.delete) {
338
+ router.delete(`${path}/:id`, controller.delete);
339
+ }
340
+ return router;
341
+ }
342
+
343
+ /**
344
+ * Create API routes
345
+ */
346
+ export function api(
347
+ router: Router,
348
+ path: string,
349
+ handlers: {
350
+ list?: RouteHandler;
351
+ get?: RouteHandler;
352
+ create?: RouteHandler;
353
+ update?: RouteHandler;
354
+ delete?: RouteHandler;
355
+ }
356
+ ): Router {
357
+ const basePath = path.startsWith('/') ? path : `/${path}`;
358
+
359
+ if (handlers.list) {
360
+ router.get(`${basePath}`, handlers.list);
361
+ }
362
+ if (handlers.get) {
363
+ router.get(`${basePath}/:id`, handlers.get);
364
+ }
365
+ if (handlers.create) {
366
+ router.post(`${basePath}`, handlers.create);
367
+ }
368
+ if (handlers.update) {
369
+ router.put(`${basePath}/:id`, handlers.update);
370
+ router.patch(`${basePath}/:id`, handlers.update);
371
+ }
372
+ if (handlers.delete) {
373
+ router.delete(`${basePath}/:id`, handlers.delete);
374
+ }
375
+
376
+ return router;
377
+ }
378
+
379
+ // ============================================================
380
+ // Middleware Helpers
381
+ // ============================================================
382
+
383
+ /**
384
+ * Combine multiple middlewares
385
+ */
386
+ export function combineMiddlewares(...middlewares: Middleware[]): Middleware {
387
+ return async (request, env, ctx) => {
388
+ for (const middleware of middlewares) {
389
+ const response = await middleware(request, env, ctx);
390
+ if (response) {
391
+ return response;
392
+ }
393
+ }
394
+ return null;
395
+ };
396
+ }
397
+
398
+ /**
399
+ * Create conditional middleware
400
+ */
401
+ export function conditionalMiddleware(
402
+ condition: (request: Request) => boolean,
403
+ middleware: Middleware
404
+ ): Middleware {
405
+ return async (request, env, ctx) => {
406
+ if (condition(request)) {
407
+ return middleware(request, env, ctx);
408
+ }
409
+ return null;
410
+ };
411
+ }
412
+
413
+ /**
414
+ * Create path-specific middleware
415
+ */
416
+ export function pathMiddleware(path: string, middleware: Middleware): Middleware {
417
+ return conditionalMiddleware(
418
+ (request) => {
419
+ const url = new URL(request.url);
420
+ return url.pathname.startsWith(path);
421
+ },
422
+ middleware
423
+ );
424
+ }
425
+
426
+ /**
427
+ * Create method-specific middleware
428
+ */
429
+ export function methodMiddleware(
430
+ methods: string[],
431
+ middleware: Middleware
432
+ ): Middleware {
433
+ return conditionalMiddleware(
434
+ (request) => methods.includes(request.method),
435
+ middleware
436
+ );
437
+ }
438
+
439
+ // ============================================================
440
+ // Response Helpers
441
+ // ============================================================
442
+
443
+ /**
444
+ * Send JSON response
445
+ */
446
+ export const send = json;
447
+
448
+ /**
449
+ * Send success response
450
+ */
451
+ export function success(data: unknown, message?: string): Response {
452
+ return json({
453
+ success: true,
454
+ ...(message && { message }),
455
+ data,
456
+ });
457
+ }
458
+
459
+ /**
460
+ * Send error response
461
+ */
462
+ export function fail(error: string, status: number = 400): Response {
463
+ return json(
464
+ {
465
+ success: false,
466
+ error,
467
+ },
468
+ status
469
+ );
470
+ }
471
+
472
+ /**
473
+ * Send validation error
474
+ */
475
+ export function validationError(errors: Record<string, string[]>): Response {
476
+ return json(
477
+ {
478
+ success: false,
479
+ error: 'Validation failed',
480
+ errors,
481
+ },
482
+ 400
483
+ );
484
+ }
485
+
486
+ // ============================================================
487
+ // Request Helpers
488
+ // ============================================================
489
+
490
+ /**
491
+ * Get request body as JSON
492
+ */
493
+ export async function body<T = unknown>(request: Request): Promise<T> {
494
+ return request.json() as Promise<T>;
495
+ }
496
+
497
+ /**
498
+ * Get query params
499
+ */
500
+ export function query(request: Request): Record<string, string> {
501
+ const url = new URL(request.url);
502
+ return Object.fromEntries(url.searchParams.entries());
503
+ }
504
+
505
+ /**
506
+ * Get path params
507
+ */
508
+ export function params(request: Request): Record<string, string> {
509
+ // This should be called from within a route handler
510
+ // and relies on the router passing params
511
+ return {};
512
+ }
513
+
514
+ /**
515
+ * Get headers
516
+ */
517
+ export function headers(request: Request): Headers {
518
+ return request.headers;
519
+ }
520
+
521
+ /**
522
+ * Get header value
523
+ */
524
+ export function header(request: Request, name: string): string | null {
525
+ return request.headers.get(name);
526
+ }
527
+
528
+ /**
529
+ * Get cookie value
530
+ */
531
+ export function cookie(request: Request, name: string): string | null {
532
+ const cookieHeader = request.headers.get('Cookie');
533
+ if (!cookieHeader) {
534
+ return null;
535
+ }
536
+
537
+ const cookies = cookieHeader.split(';').map((c) => c.trim());
538
+ const target = cookies.find((c) => c.startsWith(`${name}=`));
539
+
540
+ return target ? target.substring(name.length + 1) : null;
541
+ }
542
+
543
+ // ============================================================
544
+ // Export shorthand
545
+ // ============================================================
546
+
547
+ export const createRouter = (): Router => new Router();
548
+
549
+ export const createBuilder = (): RouteBuilder => new RouteBuilder();