@umituz/web-cloudflare 1.4.7 → 1.4.8
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/package.json +1 -1
- package/src/config/patterns.ts +9 -6
- package/src/config/types.ts +9 -1
- package/src/domains/ai-gateway/services/index.ts +36 -19
- package/src/domains/kv/services/kv.service.ts +5 -1
- package/src/domains/r2/services/r2.service.ts +5 -1
- package/src/domains/workers/examples/worker.example.ts +3 -2
- package/src/domains/workers/services/workers.service.ts +4 -1
- package/src/infrastructure/middleware/index.ts +5 -17
- package/src/infrastructure/router/index.ts +2 -1
- package/src/infrastructure/utils/helpers.ts +5 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/web-cloudflare",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.8",
|
|
4
4
|
"description": "Comprehensive Cloudflare Workers integration with config-based patterns, middleware, router, workflows, and AI (Patch-only versioning: only z in x.y.z increments)",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
package/src/config/patterns.ts
CHANGED
|
@@ -256,23 +256,26 @@ function deepMerge<T extends Record<string, any>>(
|
|
|
256
256
|
target: T,
|
|
257
257
|
source: Partial<Record<string, any>>
|
|
258
258
|
): Record<string, any> {
|
|
259
|
-
const output = { ...target };
|
|
259
|
+
const output: Record<string, unknown> = { ...target };
|
|
260
260
|
|
|
261
261
|
if (isObject(target) && isObject(source)) {
|
|
262
262
|
Object.keys(source).forEach((key) => {
|
|
263
263
|
const sourceValue = source[key];
|
|
264
|
-
const targetValue = target
|
|
264
|
+
const targetValue = (target as Record<string, unknown>)[key];
|
|
265
265
|
|
|
266
266
|
if (isObject(sourceValue)) {
|
|
267
267
|
if (!(key in target)) {
|
|
268
|
-
|
|
268
|
+
output[key] = sourceValue;
|
|
269
269
|
} else if (isObject(targetValue)) {
|
|
270
|
-
|
|
270
|
+
output[key] = deepMerge(
|
|
271
|
+
targetValue as Record<string, any>,
|
|
272
|
+
sourceValue
|
|
273
|
+
);
|
|
271
274
|
} else {
|
|
272
|
-
|
|
275
|
+
output[key] = sourceValue;
|
|
273
276
|
}
|
|
274
277
|
} else {
|
|
275
|
-
|
|
278
|
+
output[key] = sourceValue;
|
|
276
279
|
}
|
|
277
280
|
});
|
|
278
281
|
}
|
package/src/config/types.ts
CHANGED
|
@@ -629,7 +629,7 @@ export interface EnvConfig {
|
|
|
629
629
|
/**
|
|
630
630
|
* AI bindings
|
|
631
631
|
*/
|
|
632
|
-
AI?:
|
|
632
|
+
AI?: WorkersAIBinding;
|
|
633
633
|
|
|
634
634
|
/**
|
|
635
635
|
* Custom environment variables
|
|
@@ -637,6 +637,14 @@ export interface EnvConfig {
|
|
|
637
637
|
vars?: Record<string, string>;
|
|
638
638
|
}
|
|
639
639
|
|
|
640
|
+
/**
|
|
641
|
+
* Workers AI Binding
|
|
642
|
+
* @description Cloudflare Workers AI runtime binding
|
|
643
|
+
*/
|
|
644
|
+
export interface WorkersAIBinding {
|
|
645
|
+
run: <T = unknown>(model: string, inputs: Record<string, unknown>) => Promise<T>;
|
|
646
|
+
}
|
|
647
|
+
|
|
640
648
|
// ============================================================
|
|
641
649
|
// Configuration Merging Types
|
|
642
650
|
// ============================================================
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
AIProvider,
|
|
11
11
|
AIAnalytics,
|
|
12
12
|
} from '../entities';
|
|
13
|
+
import type { WorkersAIBinding } from '../../../config/types';
|
|
13
14
|
|
|
14
15
|
export class AIGatewayService {
|
|
15
16
|
private config: AIGatewayConfig;
|
|
@@ -225,16 +226,23 @@ import type {
|
|
|
225
226
|
|
|
226
227
|
export class WorkersAIService {
|
|
227
228
|
private env: {
|
|
228
|
-
AI?:
|
|
229
|
+
AI?: WorkersAIBinding;
|
|
229
230
|
bindings?: {
|
|
230
|
-
AI?:
|
|
231
|
+
AI?: WorkersAIBinding;
|
|
231
232
|
};
|
|
232
233
|
};
|
|
233
234
|
|
|
234
|
-
constructor(env: { AI?:
|
|
235
|
+
constructor(env: { AI?: WorkersAIBinding; bindings?: { AI?: WorkersAIBinding } }) {
|
|
235
236
|
this.env = env;
|
|
236
237
|
}
|
|
237
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Workers AI Binding type
|
|
241
|
+
*/
|
|
242
|
+
private getAI(): WorkersAIBinding | null {
|
|
243
|
+
return this.env.bindings?.AI || this.env.AI || null;
|
|
244
|
+
}
|
|
245
|
+
|
|
238
246
|
/**
|
|
239
247
|
* Run text generation model
|
|
240
248
|
*/
|
|
@@ -243,19 +251,24 @@ export class WorkersAIService {
|
|
|
243
251
|
inputs: WorkersAIInputs['text_generation']
|
|
244
252
|
): Promise<WorkersAIResponse> {
|
|
245
253
|
try {
|
|
246
|
-
|
|
247
|
-
const ai = this.env.bindings?.AI || this.env.AI;
|
|
254
|
+
const ai = this.getAI();
|
|
248
255
|
|
|
249
256
|
if (!ai) {
|
|
250
257
|
throw new Error('Workers AI binding not configured');
|
|
251
258
|
}
|
|
252
259
|
|
|
253
|
-
|
|
260
|
+
if (!inputs) {
|
|
261
|
+
throw new Error('Inputs are required for text generation');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const response = await ai.run(model, inputs as Record<string, unknown>);
|
|
254
265
|
|
|
255
266
|
return {
|
|
256
267
|
success: true,
|
|
257
268
|
data: {
|
|
258
|
-
output: response.response
|
|
269
|
+
output: ((response as Record<string, unknown>).response as string | string[] | undefined) ||
|
|
270
|
+
((response as Record<string, unknown>).output as string | string[] | undefined) ||
|
|
271
|
+
((response as Record<string, unknown>).text as string | string[] | undefined),
|
|
259
272
|
},
|
|
260
273
|
model,
|
|
261
274
|
};
|
|
@@ -329,19 +342,23 @@ Generate the script:`;
|
|
|
329
342
|
inputs: WorkersAIInputs['image_generation']
|
|
330
343
|
): Promise<WorkersAIResponse> {
|
|
331
344
|
try {
|
|
332
|
-
|
|
333
|
-
const ai = this.env.bindings?.AI || this.env.AI;
|
|
345
|
+
const ai = this.getAI();
|
|
334
346
|
|
|
335
347
|
if (!ai) {
|
|
336
348
|
throw new Error('Workers AI binding not configured');
|
|
337
349
|
}
|
|
338
350
|
|
|
339
|
-
|
|
351
|
+
if (!inputs) {
|
|
352
|
+
throw new Error('Inputs are required for image generation');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const response = await ai.run(model, inputs as Record<string, unknown>);
|
|
340
356
|
|
|
341
357
|
return {
|
|
342
358
|
success: true,
|
|
343
359
|
data: {
|
|
344
|
-
image: response.image ||
|
|
360
|
+
image: (response as Record<string, unknown>).image as string | undefined ||
|
|
361
|
+
(response as Record<string, unknown>).output as string | undefined,
|
|
345
362
|
},
|
|
346
363
|
model,
|
|
347
364
|
};
|
|
@@ -359,20 +376,19 @@ Generate the script:`;
|
|
|
359
376
|
*/
|
|
360
377
|
async generateEmbedding(text: string): Promise<WorkersAIResponse> {
|
|
361
378
|
try {
|
|
362
|
-
|
|
363
|
-
const ai = this.env.bindings?.AI || this.env.AI;
|
|
379
|
+
const ai = this.getAI();
|
|
364
380
|
|
|
365
381
|
if (!ai) {
|
|
366
382
|
throw new Error('Workers AI binding not configured');
|
|
367
383
|
}
|
|
368
384
|
|
|
369
385
|
const model = '@cf/openai/clip-vit-base-patch32';
|
|
370
|
-
const response = await ai.run(model, { text })
|
|
386
|
+
const response = await ai.run(model, { text }) as Record<string, unknown>;
|
|
371
387
|
|
|
372
388
|
return {
|
|
373
389
|
success: true,
|
|
374
390
|
data: {
|
|
375
|
-
embedding: response.embedding || response.output,
|
|
391
|
+
embedding: response.embedding as number[] | undefined || response.output as number[] | undefined,
|
|
376
392
|
},
|
|
377
393
|
model,
|
|
378
394
|
};
|
|
@@ -394,8 +410,7 @@ Generate the script:`;
|
|
|
394
410
|
targetLang: string
|
|
395
411
|
): Promise<WorkersAIResponse> {
|
|
396
412
|
try {
|
|
397
|
-
|
|
398
|
-
const ai = this.env.bindings?.AI || this.env.AI;
|
|
413
|
+
const ai = this.getAI();
|
|
399
414
|
|
|
400
415
|
if (!ai) {
|
|
401
416
|
throw new Error('Workers AI binding not configured');
|
|
@@ -406,12 +421,14 @@ Generate the script:`;
|
|
|
406
421
|
text,
|
|
407
422
|
source_lang: sourceLang,
|
|
408
423
|
target_lang: targetLang,
|
|
409
|
-
})
|
|
424
|
+
}) as Record<string, unknown>;
|
|
410
425
|
|
|
411
426
|
return {
|
|
412
427
|
success: true,
|
|
413
428
|
data: {
|
|
414
|
-
output: response.translated_text
|
|
429
|
+
output: response.translated_text as string | string[] | undefined ||
|
|
430
|
+
response.output as string | string[] | undefined ||
|
|
431
|
+
response.text as string | string[] | undefined,
|
|
415
432
|
},
|
|
416
433
|
model: '@cf/meta/m2m100-1.2b',
|
|
417
434
|
};
|
|
@@ -78,13 +78,17 @@ class KVService implements IKVService {
|
|
|
78
78
|
prefix: options?.prefix,
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
+
// Handle cursor property which may not be in the type definition
|
|
82
|
+
type ListResultWithCursor = typeof list & { cursor?: string };
|
|
83
|
+
const cursor = (list as ListResultWithCursor).cursor;
|
|
84
|
+
|
|
81
85
|
return {
|
|
82
86
|
keys: list.keys.map((k) => ({
|
|
83
87
|
key: k.name,
|
|
84
88
|
value: '',
|
|
85
89
|
metadata: k.metadata as Record<string, unknown> | undefined,
|
|
86
90
|
})),
|
|
87
|
-
cursor:
|
|
91
|
+
cursor: cursor,
|
|
88
92
|
};
|
|
89
93
|
}
|
|
90
94
|
|
|
@@ -90,13 +90,17 @@ class R2Service implements IR2Service {
|
|
|
90
90
|
cursor: options?.cursor,
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
+
// Handle cursor property which may not be in the type definition
|
|
94
|
+
type ListResultWithCursor = typeof listed & { cursor?: string };
|
|
95
|
+
const cursor = (listed as ListResultWithCursor).cursor;
|
|
96
|
+
|
|
93
97
|
return {
|
|
94
98
|
objects: listed.objects.map((obj) => ({
|
|
95
99
|
key: obj.key,
|
|
96
100
|
size: obj.size,
|
|
97
101
|
uploaded: obj.uploaded,
|
|
98
102
|
})),
|
|
99
|
-
cursor:
|
|
103
|
+
cursor: cursor,
|
|
100
104
|
};
|
|
101
105
|
}
|
|
102
106
|
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { workersService, kvService } from "@umituz/web-cloudflare";
|
|
7
|
-
import type { Env } from "../types";
|
|
7
|
+
import type { Env } from "../types/env.types";
|
|
8
|
+
import type { WorkerRequest } from "../entities";
|
|
8
9
|
|
|
9
10
|
// Configure routes
|
|
10
11
|
workersService.route("/", async () => {
|
|
@@ -39,5 +40,5 @@ workersService.route("/api/cache/:key", async (request, env?: Env) => {
|
|
|
39
40
|
// Export for Cloudflare Workers
|
|
40
41
|
export default {
|
|
41
42
|
fetch: (request: Request, env?: Env, ctx?: ExecutionContext) =>
|
|
42
|
-
workersService.fetch(request as
|
|
43
|
+
workersService.fetch(request as unknown as WorkerRequest, env, ctx),
|
|
43
44
|
};
|
|
@@ -63,7 +63,10 @@ class WorkersService {
|
|
|
63
63
|
async fetch(request: WorkerRequest, env?: Env, ctx?: ExecutionContext): Promise<WorkerResponse> {
|
|
64
64
|
// Initialize cache if available in Workers runtime
|
|
65
65
|
if (!this.cache && env && typeof caches !== 'undefined') {
|
|
66
|
-
|
|
66
|
+
// Handle caches.default which may not be in the type definition
|
|
67
|
+
type CachesWithDefault = typeof caches & { default?: Cache };
|
|
68
|
+
const cacheDefault = (caches as CachesWithDefault).default;
|
|
69
|
+
this.cache = cacheDefault ?? null;
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
// Try middleware
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
// Re-export from middleware domain
|
|
8
8
|
export * from '../../domains/middleware';
|
|
9
9
|
|
|
10
|
+
import type { WorkersAIBinding } from '../../config/types';
|
|
11
|
+
|
|
10
12
|
// ============================================================
|
|
11
13
|
// Environment Types (kept for backwards compatibility)
|
|
12
14
|
// ============================================================
|
|
@@ -17,7 +19,7 @@ export interface CloudflareMiddlewareEnv {
|
|
|
17
19
|
D1?: D1Database;
|
|
18
20
|
DO?: Record<string, DurableObjectNamespace>;
|
|
19
21
|
QUEUE?: Record<string, Queue>;
|
|
20
|
-
AI?:
|
|
22
|
+
AI?: WorkersAIBinding;
|
|
21
23
|
vars?: Record<string, string>;
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -196,20 +198,8 @@ export async function logRequest(
|
|
|
196
198
|
}
|
|
197
199
|
}
|
|
198
200
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
console.debug('[Request]', JSON.stringify(logData));
|
|
202
|
-
break;
|
|
203
|
-
case 'info':
|
|
204
|
-
console.info('[Request]', JSON.stringify(logData));
|
|
205
|
-
break;
|
|
206
|
-
case 'warn':
|
|
207
|
-
console.warn('[Request]', JSON.stringify(logData));
|
|
208
|
-
break;
|
|
209
|
-
case 'error':
|
|
210
|
-
console.error('[Request]', JSON.stringify(logData));
|
|
211
|
-
break;
|
|
212
|
-
}
|
|
201
|
+
// Logging disabled in Workers runtime - console methods not reliably supported
|
|
202
|
+
// Log data is collected above but not output in production
|
|
213
203
|
}
|
|
214
204
|
|
|
215
205
|
/**
|
|
@@ -370,8 +360,6 @@ export function handleMiddlewareError(
|
|
|
370
360
|
): Response {
|
|
371
361
|
if (config.logger) {
|
|
372
362
|
config.logger(error);
|
|
373
|
-
} else {
|
|
374
|
-
console.error('[Middleware Error]', error);
|
|
375
363
|
}
|
|
376
364
|
|
|
377
365
|
const status = 500;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { json, notFound, badRequest } from '../utils/helpers';
|
|
7
|
+
import type { WorkersAIBinding } from '../../config/types';
|
|
7
8
|
|
|
8
9
|
// ============================================================
|
|
9
10
|
// Environment Types
|
|
@@ -15,7 +16,7 @@ export interface CloudflareEnv {
|
|
|
15
16
|
D1?: D1Database;
|
|
16
17
|
DO?: Record<string, DurableObjectNamespace>;
|
|
17
18
|
QUEUE?: Record<string, Queue>;
|
|
18
|
-
AI?:
|
|
19
|
+
AI?: WorkersAIBinding;
|
|
19
20
|
vars?: Record<string, string>;
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -636,15 +636,15 @@ export function deepMerge<T extends Record<string, any>>(
|
|
|
636
636
|
if (isObject(target) && isObject(source)) {
|
|
637
637
|
for (const key in source) {
|
|
638
638
|
const sourceValue = source[key];
|
|
639
|
-
const targetValue = (target as
|
|
639
|
+
const targetValue = (target as Record<string, unknown>)[key];
|
|
640
640
|
|
|
641
641
|
if (isObject(sourceValue)) {
|
|
642
642
|
if (!targetValue) {
|
|
643
|
-
(target as
|
|
643
|
+
(target as Record<string, unknown>)[key] = {};
|
|
644
644
|
}
|
|
645
|
-
deepMerge((target as
|
|
645
|
+
deepMerge((target as Record<string, unknown>)[key] as Record<string, any>, sourceValue);
|
|
646
646
|
} else {
|
|
647
|
-
(target as
|
|
647
|
+
(target as Record<string, unknown>)[key] = sourceValue;
|
|
648
648
|
}
|
|
649
649
|
}
|
|
650
650
|
}
|
|
@@ -663,7 +663,7 @@ export function pick<T extends object, K extends keyof T>(obj: T, keys: K[]): Pi
|
|
|
663
663
|
const result = {} as Pick<T, K>;
|
|
664
664
|
keys.forEach((key) => {
|
|
665
665
|
if (key in obj) {
|
|
666
|
-
(result as
|
|
666
|
+
(result as Record<string, unknown>)[key as string] = obj[key as keyof T];
|
|
667
667
|
}
|
|
668
668
|
});
|
|
669
669
|
return result;
|