@umituz/web-cloudflare 1.4.7 → 1.4.9

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @umituz/web-cloudflare
2
2
 
3
- Comprehensive Cloudflare Workers integration with config-based patterns, middleware, router, workflows, and AI.
3
+ Comprehensive Cloudflare Workers & Pages integration with config-based patterns, middleware, router, workflows, and AI.
4
4
 
5
5
  ## 🚀 Features
6
6
 
@@ -177,6 +177,39 @@ const versions = await wrangler.versionsList();
177
177
  await wrangler.versionsRollback(versions[0].id);
178
178
  ```
179
179
 
180
+ ### Using Cloudflare Pages
181
+
182
+ ```typescript
183
+ import { PagesService } from '@umituz/web-cloudflare/pages';
184
+
185
+ const pages = new PagesService();
186
+
187
+ // Create a new Pages project
188
+ await pages.createProject('my-app', {
189
+ productionBranch: 'main',
190
+ });
191
+
192
+ // Deploy to Pages
193
+ const deployment = await pages.deploy({
194
+ projectName: 'my-app',
195
+ directory: 'dist', // Build output directory
196
+ branch: 'main',
197
+ environment: 'production',
198
+ vars: {
199
+ API_URL: 'https://api.example.com',
200
+ },
201
+ });
202
+
203
+ // List all projects
204
+ const projects = await pages.listProjects();
205
+
206
+ // List deployments for a project
207
+ const deployments = await pages.listDeployments('my-app');
208
+
209
+ // Delete a deployment
210
+ await pages.deleteDeployment('my-app', deployment.id);
211
+ ```
212
+
180
213
  **Note:** All services now follow Domain-Driven Design (DDD) architecture with their own domain structures:
181
214
  - Wrangler CLI: `src/domains/wrangler/`
182
215
  - Workers: `src/domains/workers/`
@@ -187,6 +220,7 @@ await wrangler.versionsRollback(versions[0].id);
187
220
  - Images: `src/domains/images/`
188
221
  - Analytics: `src/domains/analytics/`
189
222
  - Workflows: `src/domains/workflows/`
223
+ - Pages: `src/domains/pages/`
190
224
 
191
225
  ## 📚 Subpath Exports
192
226
 
@@ -216,6 +250,9 @@ import { WorkflowService } from '@umituz/web-cloudflare/workflows';
216
250
 
217
251
  // Wrangler CLI
218
252
  import { WranglerService } from '@umituz/web-cloudflare/wrangler';
253
+
254
+ // Pages deployment
255
+ import { PagesService, pagesService } from '@umituz/web-cloudflare/pages';
219
256
  ```
220
257
 
221
258
  ### Workflows & AI
@@ -680,7 +717,8 @@ Contributions are welcome!
680
717
  │ │ ├── kv/ # KV storage domain
681
718
  │ │ ├── images/ # Images optimization domain
682
719
  │ │ ├── analytics/ # Analytics domain
683
- │ │ └── workflows/ # Workflows domain
720
+ │ │ ├── workflows/ # Workflows domain
721
+ │ │ ├── pages/ # Pages deployment domain
684
722
  │ ├── infrastructure/
685
723
  │ │ ├── router/ # Express-like router
686
724
  │ │ ├── middleware/ # Middleware collection
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@umituz/web-cloudflare",
3
- "version": "1.4.7",
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)",
3
+ "version": "1.4.9",
4
+ "description": "Comprehensive Cloudflare Workers & Pages 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",
7
7
  "sideEffects": false,
@@ -17,6 +17,7 @@
17
17
  "./ai-gateway": "./src/domains/ai-gateway/index.ts",
18
18
  "./workers-ai": "./src/domains/ai-gateway/index.ts",
19
19
  "./wrangler": "./src/domains/wrangler/index.ts",
20
+ "./pages": "./src/domains/pages/index.ts",
20
21
  "./middleware": "./src/domains/middleware/index.ts",
21
22
  "./router": "./src/infrastructure/router/index.ts",
22
23
  "./utils": "./src/infrastructure/utils/helpers.ts",
@@ -47,6 +48,10 @@
47
48
  "workflows",
48
49
  "ai-gateway",
49
50
  "workers-ai",
51
+ "pages",
52
+ "cloudflare-pages",
53
+ "static-site",
54
+ "deployment",
50
55
  "router",
51
56
  "middleware",
52
57
  "config-patterns",
@@ -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[key as keyof T];
264
+ const targetValue = (target as Record<string, unknown>)[key];
265
265
 
266
266
  if (isObject(sourceValue)) {
267
267
  if (!(key in target)) {
268
- (output as any)[key] = sourceValue;
268
+ output[key] = sourceValue;
269
269
  } else if (isObject(targetValue)) {
270
- (output as any)[key] = deepMerge(targetValue, sourceValue);
270
+ output[key] = deepMerge(
271
+ targetValue as Record<string, any>,
272
+ sourceValue
273
+ );
271
274
  } else {
272
- (output as any)[key] = sourceValue;
275
+ output[key] = sourceValue;
273
276
  }
274
277
  } else {
275
- (output as any)[key] = sourceValue;
278
+ output[key] = sourceValue;
276
279
  }
277
280
  });
278
281
  }
@@ -629,7 +629,7 @@ export interface EnvConfig {
629
629
  /**
630
630
  * AI bindings
631
631
  */
632
- AI?: any;
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?: any;
229
+ AI?: WorkersAIBinding;
229
230
  bindings?: {
230
- AI?: any;
231
+ AI?: WorkersAIBinding;
231
232
  };
232
233
  };
233
234
 
234
- constructor(env: { AI?: any; bindings?: any }) {
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
- // @ts-ignore - Workers AI runtime binding
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
- const response = await ai.run(model, inputs);
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 || response.output || response.text,
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
- // @ts-ignore - Workers AI runtime binding
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
- const response = await ai.run(model, inputs);
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 || response.output,
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
- // @ts-ignore - Workers AI runtime binding
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
- // @ts-ignore - Workers AI runtime binding
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 || response.output || response.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: (list as any).cursor as string | undefined,
91
+ cursor: cursor,
88
92
  };
89
93
  }
90
94
 
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Pages Domain Entities
3
+ * Defines entities for Cloudflare Pages operations
4
+ */
5
+
6
+ /**
7
+ * Pages project info
8
+ */
9
+ export interface PagesProject {
10
+ name: string;
11
+ production_branch?: string;
12
+ created_on?: string;
13
+ deployment_configs?: {
14
+ preview?: {
15
+ branch?: string;
16
+ env_vars?: Record<string, string>;
17
+ };
18
+ production?: {
19
+ branch?: string;
20
+ env_vars?: Record<string, string>;
21
+ };
22
+ };
23
+ }
24
+
25
+ /**
26
+ * Pages deployment info
27
+ */
28
+ export interface PagesDeployment {
29
+ id: string;
30
+ project: string;
31
+ url: string;
32
+ latest_stage?: string;
33
+ created_on?: string;
34
+ deployment_trigger?: {
35
+ metadata?: {
36
+ branch?: string;
37
+ commit_hash?: string;
38
+ };
39
+ };
40
+ stages?: {
41
+ environment: string;
42
+ function?: string;
43
+ url?: string;
44
+ }[];
45
+ }
46
+
47
+ /**
48
+ * Pages deploy options
49
+ */
50
+ export interface PagesDeployOptions {
51
+ projectName: string;
52
+ directory?: string; // Build output directory (default: dist)
53
+ branch?: string;
54
+ preview?: boolean;
55
+ environment?: 'preview' | 'production';
56
+ compatibilityDate?: string;
57
+ compatibilityFlags?: string[];
58
+ vars?: Record<string, string>;
59
+ functions?: boolean; // Deploy with functions
60
+ }
61
+
62
+ /**
63
+ * Pages function info
64
+ */
65
+ export interface PagesFunction {
66
+ name: string;
67
+ scriptPath?: string;
68
+ compatibilityDate?: string;
69
+ compatibilityFlags?: string[];
70
+ }
71
+
72
+ /**
73
+ * Pages deployment result
74
+ */
75
+ export interface PagesDeploymentResult {
76
+ deployment: PagesDeployment;
77
+ url?: string;
78
+ alias?: string;
79
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @umituz/web-cloudflare - Pages Domain
3
+ * Cloudflare Pages deployment and management
4
+ */
5
+
6
+ // Services
7
+ export { PagesService, pagesService } from './services';
8
+
9
+ // Types
10
+ export type {
11
+ IPagesService,
12
+ } from './types';
13
+
14
+ // Entities
15
+ export type {
16
+ PagesProject,
17
+ PagesDeployment,
18
+ PagesDeployOptions,
19
+ PagesFunction,
20
+ PagesDeploymentResult,
21
+ } from './entities';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Pages Domain Services
3
+ */
4
+
5
+ export { PagesService, pagesService } from './pages.service';
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Pages Service Implementation
3
+ * Cloudflare Pages deployment and management
4
+ *
5
+ * ⚠️ NODE.JS ONLY: This service requires Node.js runtime and is NOT compatible
6
+ * with Cloudflare Workers runtime. Use this service only in build/development
7
+ * scripts running in Node.js environment.
8
+ */
9
+
10
+ import { execSync } from 'child_process';
11
+ import type { IPagesService } from '../types/service.interface';
12
+ import type {
13
+ PagesProject,
14
+ PagesDeployment,
15
+ PagesDeployOptions,
16
+ PagesFunction,
17
+ PagesDeploymentResult,
18
+ } from '../entities';
19
+
20
+ export class PagesService implements IPagesService {
21
+ private readonly wranglerCommand: string;
22
+
23
+ constructor(options?: { wranglerPath?: string }) {
24
+ this.wranglerCommand = options?.wranglerPath || 'npx wrangler';
25
+ }
26
+
27
+ /**
28
+ * Create a new Pages project
29
+ */
30
+ async createProject(
31
+ projectName: string,
32
+ options?: {
33
+ productionBranch?: string;
34
+ compatibilityDate?: string;
35
+ }
36
+ ): Promise<{ success: boolean; data?: PagesProject; error?: string }> {
37
+ return this.nodeNotRequired();
38
+ }
39
+
40
+ /**
41
+ * List all Pages projects
42
+ */
43
+ async listProjects(): Promise<{ success: boolean; data?: PagesProject[]; error?: string }> {
44
+ return this.nodeNotRequired();
45
+ }
46
+
47
+ /**
48
+ * Get project details
49
+ */
50
+ async getProject(projectName: string): Promise<{ success: boolean; data?: PagesProject; error?: string }> {
51
+ return this.nodeNotRequired();
52
+ }
53
+
54
+ /**
55
+ * Deploy to Pages
56
+ */
57
+ async deploy(
58
+ options: PagesDeployOptions
59
+ ): Promise<{ success: boolean; data?: PagesDeploymentResult; error?: string }> {
60
+ return this.nodeNotRequired();
61
+ }
62
+
63
+ /**
64
+ * Create a Pages function
65
+ */
66
+ async createFunction(
67
+ projectName: string,
68
+ functionName: string,
69
+ options?: {
70
+ compatibilityDate?: string;
71
+ compatibilityFlags?: string[];
72
+ }
73
+ ): Promise<{ success: boolean; data?: PagesFunction; error?: string }> {
74
+ return this.nodeNotRequired();
75
+ }
76
+
77
+ /**
78
+ * List deployments for a project
79
+ */
80
+ async listDeployments(
81
+ projectName: string
82
+ ): Promise<{ success: boolean; data?: PagesDeployment[]; error?: string }> {
83
+ return this.nodeNotRequired();
84
+ }
85
+
86
+ /**
87
+ * Get deployment details
88
+ */
89
+ async getDeployment(
90
+ projectName: string,
91
+ deploymentId: string
92
+ ): Promise<{ success: boolean; data?: PagesDeployment; error?: string }> {
93
+ return this.nodeNotRequired();
94
+ }
95
+
96
+ /**
97
+ * Delete a deployment
98
+ */
99
+ async deleteDeployment(
100
+ projectName: string,
101
+ deploymentId: string
102
+ ): Promise<{ success: boolean; error?: string }> {
103
+ return this.nodeNotRequired();
104
+ }
105
+
106
+ /**
107
+ * Execute wrangler pages command
108
+ */
109
+ private executeWranglerPages(
110
+ args: string[],
111
+ options?: { cwd?: string; env?: Record<string, string> }
112
+ ): { success: boolean; stdout: string; stderr: string; exitCode?: number } {
113
+ try {
114
+ const command = `${this.wranglerCommand} pages ${args.join(' ')}`;
115
+ const stdout = execSync(command, {
116
+ cwd: options?.cwd,
117
+ env: { ...process.env, ...options?.env },
118
+ encoding: 'utf-8',
119
+ });
120
+ return { success: true, stdout, stderr: '', exitCode: 0 };
121
+ } catch (error: unknown) {
122
+ if (error instanceof Error) {
123
+ const err = error as { stdout?: string; stderr?: string; code?: number };
124
+ return {
125
+ success: false,
126
+ stdout: err.stdout || '',
127
+ stderr: err.stderr || error.message,
128
+ exitCode: err.code,
129
+ };
130
+ }
131
+ return { success: false, stdout: '', stderr: 'Unknown error', exitCode: -1 };
132
+ }
133
+ }
134
+
135
+ private nodeNotRequired<T>(): never {
136
+ throw new Error(
137
+ 'PagesService requires Node.js runtime. ' +
138
+ 'This service only works in Node.js environment, not in Cloudflare Workers. ' +
139
+ 'Use this service in build scripts or deployment tools only.'
140
+ );
141
+ }
142
+ }
143
+
144
+ export const pagesService = new PagesService();
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Pages Domain Types
3
+ */
4
+
5
+ export * from './service.interface';
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Pages Service Interface
3
+ * Defines the contract for Cloudflare Pages operations
4
+ */
5
+
6
+ import type {
7
+ PagesProject,
8
+ PagesDeployment,
9
+ PagesDeployOptions,
10
+ PagesFunction,
11
+ PagesDeploymentResult,
12
+ } from '../entities';
13
+
14
+ export interface IPagesService {
15
+ /**
16
+ * Create a new Pages project
17
+ */
18
+ createProject(
19
+ projectName: string,
20
+ options?: {
21
+ productionBranch?: string;
22
+ compatibilityDate?: string;
23
+ }
24
+ ): Promise<{ success: boolean; data?: PagesProject; error?: string }>;
25
+
26
+ /**
27
+ * List all Pages projects
28
+ */
29
+ listProjects(): Promise<{ success: boolean; data?: PagesProject[]; error?: string }>;
30
+
31
+ /**
32
+ * Get project details
33
+ */
34
+ getProject(projectName: string): Promise<{ success: boolean; data?: PagesProject; error?: string }>;
35
+
36
+ /**
37
+ * Deploy to Pages
38
+ */
39
+ deploy(
40
+ options: PagesDeployOptions
41
+ ): Promise<{ success: boolean; data?: PagesDeploymentResult; error?: string }>;
42
+
43
+ /**
44
+ * Create a Pages function
45
+ */
46
+ createFunction(
47
+ projectName: string,
48
+ functionName: string,
49
+ options?: {
50
+ compatibilityDate?: string;
51
+ compatibilityFlags?: string[];
52
+ }
53
+ ): Promise<{ success: boolean; data?: PagesFunction; error?: string }>;
54
+
55
+ /**
56
+ * List deployments for a project
57
+ */
58
+ listDeployments(
59
+ projectName: string
60
+ ): Promise<{ success: boolean; data?: PagesDeployment[]; error?: string }>;
61
+
62
+ /**
63
+ * Get deployment details
64
+ */
65
+ getDeployment(
66
+ projectName: string,
67
+ deploymentId: string
68
+ ): Promise<{ success: boolean; data?: PagesDeployment; error?: string }>;
69
+
70
+ /**
71
+ * Delete a deployment
72
+ */
73
+ deleteDeployment(
74
+ projectName: string,
75
+ deploymentId: string
76
+ ): Promise<{ success: boolean; error?: string }>;
77
+ }
@@ -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: (listed as any).cursor as string | undefined,
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 any, env, ctx),
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
- this.cache = (caches as any).default;
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
@@ -53,6 +53,12 @@ export enum WranglerCommand {
53
53
  // Versions
54
54
  VERSIONS_LIST = 'versions list',
55
55
  VERSIONS_ROLLBACK = 'versions rollback',
56
+
57
+ // Pages operations
58
+ PAGES_PROJECT_CREATE = 'pages project create',
59
+ PAGES_PROJECT_LIST = 'pages project list',
60
+ PAGES_DEPLOY = 'pages deploy',
61
+ PAGES_FUNCTION = 'pages function',
56
62
  }
57
63
 
58
64
  /**
@@ -140,3 +146,54 @@ export interface WranglerAnalyticsData {
140
146
  statusCodes?: Record<string, number>;
141
147
  countries?: Record<string, number>;
142
148
  }
149
+
150
+ /**
151
+ * Pages project info
152
+ */
153
+ export interface PagesProjectInfo {
154
+ name: string;
155
+ production_branch?: string;
156
+ creation_date?: string;
157
+ deployment_configs?: {
158
+ preview?: {
159
+ branch?: string;
160
+ env_vars?: Record<string, string>;
161
+ };
162
+ production?: {
163
+ branch?: string;
164
+ env_vars?: Record<string, string>;
165
+ };
166
+ };
167
+ }
168
+
169
+ /**
170
+ * Pages deployment info
171
+ */
172
+ export interface PagesDeploymentInfo {
173
+ id: string;
174
+ project: string;
175
+ url: string;
176
+ latest_stage?: string;
177
+ created_on?: string;
178
+ deployment_trigger?: {
179
+ metadata?: {
180
+ branch?: string;
181
+ commit_hash?: string;
182
+ };
183
+ };
184
+ }
185
+
186
+ /**
187
+ * Pages deploy options
188
+ */
189
+ export interface PagesDeployOptions {
190
+ projectName: string;
191
+ directory?: string;
192
+ branch?: string;
193
+ preview?: boolean;
194
+ environment?: 'preview' | 'production';
195
+ compatibilityDate?: string;
196
+ compatibilityFlags?: string[];
197
+ vars?: Record<string, string>;
198
+ }
199
+
@@ -13,6 +13,9 @@ import type {
13
13
  SecretInfo,
14
14
  WorkerVersionInfo,
15
15
  WranglerAnalyticsData,
16
+ PagesProjectInfo,
17
+ PagesDeploymentInfo,
18
+ PagesDeployOptions,
16
19
  } from '../entities';
17
20
 
18
21
  export interface IWranglerService {
@@ -127,4 +130,21 @@ export interface IWranglerService {
127
130
  args: string[],
128
131
  options?: WranglerCommandOptions
129
132
  ): Promise<WranglerResult<string>>;
133
+
134
+ // Pages operations
135
+ pagesProjectCreate(
136
+ projectName: string,
137
+ options?: WranglerCommandOptions & { productionBranch?: string }
138
+ ): Promise<WranglerResult<PagesProjectInfo>>;
139
+ pagesProjectList(
140
+ options?: WranglerCommandOptions
141
+ ): Promise<WranglerResult<PagesProjectInfo[]>>;
142
+ pagesDeploy(
143
+ options: PagesDeployOptions & WranglerCommandOptions
144
+ ): Promise<WranglerResult<PagesDeploymentInfo>>;
145
+ pagesFunctionCreate(
146
+ projectName: string,
147
+ functionName: string,
148
+ options?: WranglerCommandOptions
149
+ ): Promise<WranglerResult<void>>;
130
150
  }
package/src/index.ts CHANGED
@@ -35,6 +35,15 @@ export { d1Service, D1Service } from "./domains/d1";
35
35
  export { kvService, KVService } from "./domains/kv";
36
36
  export { imagesService, ImagesService } from "./domains/images";
37
37
  export { analyticsService, AnalyticsService } from "./domains/analytics";
38
+ // Pages - Node.js-only service
39
+ export { pagesService, PagesService } from "./domains/pages";
40
+ export type {
41
+ PagesProject,
42
+ PagesDeployment,
43
+ PagesDeployOptions,
44
+ PagesFunction,
45
+ PagesDeploymentResult,
46
+ } from "./domains/pages";
38
47
  // Workflows - selective exports to avoid conflicts
39
48
  export type {
40
49
  WorkflowStep,
@@ -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?: any;
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
- switch (config.level) {
200
- case 'debug':
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?: any;
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 any)[key];
639
+ const targetValue = (target as Record<string, unknown>)[key];
640
640
 
641
641
  if (isObject(sourceValue)) {
642
642
  if (!targetValue) {
643
- (target as any)[key] = {};
643
+ (target as Record<string, unknown>)[key] = {};
644
644
  }
645
- deepMerge((target as any)[key], sourceValue);
645
+ deepMerge((target as Record<string, unknown>)[key] as Record<string, any>, sourceValue);
646
646
  } else {
647
- (target as any)[key] = sourceValue;
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 any)[key] = obj[key];
666
+ (result as Record<string, unknown>)[key as string] = obj[key as keyof T];
667
667
  }
668
668
  });
669
669
  return result;