@umituz/web-cloudflare 1.0.1 → 1.1.0
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 +48 -0
- package/package.json +4 -1
- package/src/domain/entities/wrangler.entity.ts +142 -0
- package/src/domain/interfaces/wrangler.interface.ts +130 -0
- package/src/index.ts +1 -0
- package/src/infrastructure/services/wrangler/index.ts +17 -0
- package/src/infrastructure/services/wrangler/wrangler.service.ts +461 -0
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ Comprehensive Cloudflare Workers integration with config-based patterns, middlew
|
|
|
5
5
|
## 🚀 Features
|
|
6
6
|
|
|
7
7
|
- ✅ **Config-Based Patterns** - Pre-built configurations for different app types
|
|
8
|
+
- ✅ **Wrangler CLI Integration** - TypeScript wrapper for Wrangler CLI commands
|
|
8
9
|
- ✅ **Express-like Router** - Simple, intuitive routing with middleware support
|
|
9
10
|
- ✅ **Comprehensive Middleware** - CORS, caching, rate limiting, security, compression
|
|
10
11
|
- ✅ **Workers AI Integration** - AI content generation with emotion control
|
|
@@ -130,6 +131,50 @@ const analysis = await aiService.analyzeSentiment(content);
|
|
|
130
131
|
// { sentiment: 'positive', confidence: 0.89, emotions: ['excited'] }
|
|
131
132
|
```
|
|
132
133
|
|
|
134
|
+
### Using Wrangler CLI
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { WranglerService } from '@umituz/web-cloudflare/wrangler';
|
|
138
|
+
|
|
139
|
+
const wrangler = new WranglerService();
|
|
140
|
+
|
|
141
|
+
// Authentication
|
|
142
|
+
await wrangler.login();
|
|
143
|
+
const authInfo = await wrangler.whoami();
|
|
144
|
+
|
|
145
|
+
// Project management
|
|
146
|
+
await wrangler.init('my-worker', 'typescript');
|
|
147
|
+
await wrangler.deploy({ env: 'production' });
|
|
148
|
+
|
|
149
|
+
// Start development server
|
|
150
|
+
await wrangler.dev({ port: 8787, local: true });
|
|
151
|
+
|
|
152
|
+
// KV operations
|
|
153
|
+
const namespace = await wrangler.kvNamespaceCreate('MY_KV');
|
|
154
|
+
await wrangler.kvKeyPut(namespace.id, 'key', 'value');
|
|
155
|
+
const value = await wrangler.kvKeyGet(namespace.id, 'key');
|
|
156
|
+
|
|
157
|
+
// R2 operations
|
|
158
|
+
await wrangler.r2BucketCreate('my-bucket');
|
|
159
|
+
const buckets = await wrangler.r2BucketList();
|
|
160
|
+
await wrangler.r2ObjectPut('my-bucket', 'file.txt', './local-file.txt');
|
|
161
|
+
|
|
162
|
+
// D1 operations
|
|
163
|
+
const db = await wrangler.d1Create('my-database');
|
|
164
|
+
const result = await wrangler.d1Execute('my-database', 'SELECT * FROM users');
|
|
165
|
+
|
|
166
|
+
// Secrets management
|
|
167
|
+
await wrangler.secretPut('API_KEY', 'secret-value');
|
|
168
|
+
const secrets = await wrangler.secretList();
|
|
169
|
+
|
|
170
|
+
// Monitoring
|
|
171
|
+
await wrangler.tail({ format: 'json' });
|
|
172
|
+
|
|
173
|
+
// Version management
|
|
174
|
+
const versions = await wrangler.versionsList();
|
|
175
|
+
await wrangler.versionsRollback(versions[0].id);
|
|
176
|
+
```
|
|
177
|
+
|
|
133
178
|
## 📚 Subpath Exports
|
|
134
179
|
|
|
135
180
|
### Services
|
|
@@ -152,6 +197,9 @@ import { ImagesService } from '@umituz/web-cloudflare/images';
|
|
|
152
197
|
|
|
153
198
|
// Analytics
|
|
154
199
|
import { AnalyticsService } from '@umituz/web-cloudflare/analytics';
|
|
200
|
+
|
|
201
|
+
// Wrangler CLI
|
|
202
|
+
import { WranglerService } from '@umituz/web-cloudflare/wrangler';
|
|
155
203
|
```
|
|
156
204
|
|
|
157
205
|
### Workflows & AI
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/web-cloudflare",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Comprehensive Cloudflare Workers integration with config-based patterns, middleware, router, workflows, and AI",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"./workflows": "./src/infrastructure/services/workflows/index.ts",
|
|
17
17
|
"./ai-gateway": "./src/infrastructure/services/ai-gateway/index.ts",
|
|
18
18
|
"./workers-ai": "./src/infrastructure/services/ai-gateway/index.ts",
|
|
19
|
+
"./wrangler": "./src/infrastructure/services/wrangler/index.ts",
|
|
19
20
|
"./router": "./src/infrastructure/router/index.ts",
|
|
20
21
|
"./middleware": "./src/infrastructure/middleware/index.ts",
|
|
21
22
|
"./utils": "./src/infrastructure/utils/helpers.ts",
|
|
@@ -36,6 +37,8 @@
|
|
|
36
37
|
"keywords": [
|
|
37
38
|
"cloudflare",
|
|
38
39
|
"workers",
|
|
40
|
+
"wrangler",
|
|
41
|
+
"wrangler-cli",
|
|
39
42
|
"edge",
|
|
40
43
|
"kv",
|
|
41
44
|
"r2",
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrangler CLI Domain Entities
|
|
3
|
+
* Defines entities for Wrangler CLI operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Wrangler command types
|
|
8
|
+
*/
|
|
9
|
+
export enum WranglerCommand {
|
|
10
|
+
// Authentication
|
|
11
|
+
LOGIN = 'login',
|
|
12
|
+
LOGOUT = 'logout',
|
|
13
|
+
WHOAMI = 'whoami',
|
|
14
|
+
|
|
15
|
+
// Project management
|
|
16
|
+
INIT = 'init',
|
|
17
|
+
DEV = 'dev',
|
|
18
|
+
DEPLOY = 'deploy',
|
|
19
|
+
DELETE = 'delete',
|
|
20
|
+
|
|
21
|
+
// KV operations
|
|
22
|
+
KV_NAMESPACE_CREATE = 'kv:namespace create',
|
|
23
|
+
KV_NAMESPACE_LIST = 'kv:namespace list',
|
|
24
|
+
KV_KEY_PUT = 'kv:key put',
|
|
25
|
+
KV_KEY_GET = 'kv:key get',
|
|
26
|
+
KV_KEY_LIST = 'kv:key list',
|
|
27
|
+
KV_KEY_DELETE = 'kv:key delete',
|
|
28
|
+
|
|
29
|
+
// R2 operations
|
|
30
|
+
R2_BUCKET_CREATE = 'r2 bucket create',
|
|
31
|
+
R2_BUCKET_LIST = 'r2 bucket list',
|
|
32
|
+
R2_BUCKET_DELETE = 'r2 bucket delete',
|
|
33
|
+
R2_OBJECT_PUT = 'r2 object put',
|
|
34
|
+
R2_OBJECT_GET = 'r2 object get',
|
|
35
|
+
R2_OBJECT_LIST = 'r2 object list',
|
|
36
|
+
R2_OBJECT_DELETE = 'r2 object delete',
|
|
37
|
+
|
|
38
|
+
// D1 operations
|
|
39
|
+
D1_CREATE = 'd1 create',
|
|
40
|
+
D1_LIST = 'd1 list',
|
|
41
|
+
D1_EXECUTE = 'd1 execute',
|
|
42
|
+
D1_BACKUP = 'd1 backups create',
|
|
43
|
+
|
|
44
|
+
// Secrets
|
|
45
|
+
SECRET_PUT = 'secret put',
|
|
46
|
+
SECRET_LIST = 'secret list',
|
|
47
|
+
SECRET_DELETE = 'secret delete',
|
|
48
|
+
|
|
49
|
+
// Monitoring
|
|
50
|
+
TAIL = 'tail',
|
|
51
|
+
ANALYTICS = 'analytics',
|
|
52
|
+
|
|
53
|
+
// Versions
|
|
54
|
+
VERSIONS_LIST = 'versions list',
|
|
55
|
+
VERSIONS_ROLLBACK = 'versions rollback',
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Wrangler execution result
|
|
60
|
+
*/
|
|
61
|
+
export interface WranglerResult<T = unknown> {
|
|
62
|
+
success: boolean;
|
|
63
|
+
data?: T;
|
|
64
|
+
error?: string;
|
|
65
|
+
stdout?: string;
|
|
66
|
+
stderr?: string;
|
|
67
|
+
exitCode?: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Wrangler command options
|
|
72
|
+
*/
|
|
73
|
+
export interface WranglerCommandOptions {
|
|
74
|
+
cwd?: string;
|
|
75
|
+
env?: Record<string, string>;
|
|
76
|
+
timeout?: number;
|
|
77
|
+
silent?: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Auth information
|
|
82
|
+
*/
|
|
83
|
+
export interface AuthInfo {
|
|
84
|
+
email?: string;
|
|
85
|
+
accountId?: string;
|
|
86
|
+
username?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* KV namespace info
|
|
91
|
+
*/
|
|
92
|
+
export interface KVNamespaceInfo {
|
|
93
|
+
id: string;
|
|
94
|
+
title: string;
|
|
95
|
+
supportsUrlEncoding?: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* R2 bucket info
|
|
100
|
+
*/
|
|
101
|
+
export interface R2BucketInfo {
|
|
102
|
+
name: string;
|
|
103
|
+
creationDate?: string;
|
|
104
|
+
location?: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* D1 database info
|
|
109
|
+
*/
|
|
110
|
+
export interface D1DatabaseInfo {
|
|
111
|
+
uuid: string;
|
|
112
|
+
name: string;
|
|
113
|
+
created_at: string;
|
|
114
|
+
version?: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Secret info
|
|
119
|
+
*/
|
|
120
|
+
export interface SecretInfo {
|
|
121
|
+
name: string;
|
|
122
|
+
type?: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Worker version info
|
|
127
|
+
*/
|
|
128
|
+
export interface WorkerVersionInfo {
|
|
129
|
+
id: string;
|
|
130
|
+
created_at: string;
|
|
131
|
+
metadata?: Record<string, unknown>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Analytics data
|
|
136
|
+
*/
|
|
137
|
+
export interface AnalyticsData {
|
|
138
|
+
requests?: number;
|
|
139
|
+
errors?: number;
|
|
140
|
+
statusCodes?: Record<string, number>;
|
|
141
|
+
countries?: Record<string, number>;
|
|
142
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrangler Service Interface
|
|
3
|
+
* Defines the contract for Wrangler CLI operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
WranglerResult,
|
|
8
|
+
WranglerCommandOptions,
|
|
9
|
+
AuthInfo,
|
|
10
|
+
KVNamespaceInfo,
|
|
11
|
+
R2BucketInfo,
|
|
12
|
+
D1DatabaseInfo,
|
|
13
|
+
SecretInfo,
|
|
14
|
+
WorkerVersionInfo,
|
|
15
|
+
AnalyticsData,
|
|
16
|
+
} from '../entities/wrangler.entity';
|
|
17
|
+
|
|
18
|
+
export interface IWranglerService {
|
|
19
|
+
// Authentication
|
|
20
|
+
login(options?: WranglerCommandOptions): Promise<WranglerResult<AuthInfo>>;
|
|
21
|
+
logout(options?: WranglerCommandOptions): Promise<WranglerResult<void>>;
|
|
22
|
+
whoami(options?: WranglerCommandOptions): Promise<WranglerResult<AuthInfo>>;
|
|
23
|
+
|
|
24
|
+
// Project management
|
|
25
|
+
init(
|
|
26
|
+
projectName: string,
|
|
27
|
+
template?: string,
|
|
28
|
+
options?: WranglerCommandOptions
|
|
29
|
+
): Promise<WranglerResult<void>>;
|
|
30
|
+
dev(
|
|
31
|
+
options?: WranglerCommandOptions & { port?: number; local?: boolean }
|
|
32
|
+
): Promise<WranglerResult<void>>;
|
|
33
|
+
deploy(
|
|
34
|
+
options?: WranglerCommandOptions & { env?: string }
|
|
35
|
+
): Promise<WranglerResult<{ url?: string }>>;
|
|
36
|
+
deleteWorker(
|
|
37
|
+
workerName: string,
|
|
38
|
+
options?: WranglerCommandOptions
|
|
39
|
+
): Promise<WranglerResult<void>>;
|
|
40
|
+
|
|
41
|
+
// KV operations
|
|
42
|
+
kvNamespaceCreate(
|
|
43
|
+
title: string,
|
|
44
|
+
options?: WranglerCommandOptions
|
|
45
|
+
): Promise<WranglerResult<KVNamespaceInfo>>;
|
|
46
|
+
kvNamespaceList(
|
|
47
|
+
options?: WranglerCommandOptions
|
|
48
|
+
): Promise<WranglerResult<KVNamespaceInfo[]>>;
|
|
49
|
+
kvKeyPut(
|
|
50
|
+
namespaceId: string,
|
|
51
|
+
key: string,
|
|
52
|
+
value: string,
|
|
53
|
+
options?: WranglerCommandOptions
|
|
54
|
+
): Promise<WranglerResult<void>>;
|
|
55
|
+
kvKeyGet(
|
|
56
|
+
namespaceId: string,
|
|
57
|
+
key: string,
|
|
58
|
+
options?: WranglerCommandOptions
|
|
59
|
+
): Promise<WranglerResult<string>>;
|
|
60
|
+
kvKeyDelete(
|
|
61
|
+
namespaceId: string,
|
|
62
|
+
key: string,
|
|
63
|
+
options?: WranglerCommandOptions
|
|
64
|
+
): Promise<WranglerResult<void>>;
|
|
65
|
+
|
|
66
|
+
// R2 operations
|
|
67
|
+
r2BucketCreate(
|
|
68
|
+
bucketName: string,
|
|
69
|
+
options?: WranglerCommandOptions
|
|
70
|
+
): Promise<WranglerResult<R2BucketInfo>>;
|
|
71
|
+
r2BucketList(
|
|
72
|
+
options?: WranglerCommandOptions
|
|
73
|
+
): Promise<WranglerResult<R2BucketInfo[]>>;
|
|
74
|
+
r2BucketDelete(
|
|
75
|
+
bucketName: string,
|
|
76
|
+
options?: WranglerCommandOptions
|
|
77
|
+
): Promise<WranglerResult<void>>;
|
|
78
|
+
r2ObjectPut(
|
|
79
|
+
bucketName: string,
|
|
80
|
+
key: string,
|
|
81
|
+
file: string,
|
|
82
|
+
options?: WranglerCommandOptions
|
|
83
|
+
): Promise<WranglerResult<void>>;
|
|
84
|
+
|
|
85
|
+
// D1 operations
|
|
86
|
+
d1Create(
|
|
87
|
+
databaseName: string,
|
|
88
|
+
options?: WranglerCommandOptions
|
|
89
|
+
): Promise<WranglerResult<D1DatabaseInfo>>;
|
|
90
|
+
d1List(options?: WranglerCommandOptions): Promise<WranglerResult<D1DatabaseInfo[]>>;
|
|
91
|
+
d1Execute(
|
|
92
|
+
databaseName: string,
|
|
93
|
+
command: string,
|
|
94
|
+
file?: string,
|
|
95
|
+
options?: WranglerCommandOptions
|
|
96
|
+
): Promise<WranglerResult<unknown[]>>;
|
|
97
|
+
|
|
98
|
+
// Secrets
|
|
99
|
+
secretPut(
|
|
100
|
+
secretName: string,
|
|
101
|
+
value: string,
|
|
102
|
+
options?: WranglerCommandOptions
|
|
103
|
+
): Promise<WranglerResult<void>>;
|
|
104
|
+
secretList(options?: WranglerCommandOptions): Promise<WranglerResult<SecretInfo[]>>;
|
|
105
|
+
secretDelete(
|
|
106
|
+
secretName: string,
|
|
107
|
+
options?: WranglerCommandOptions
|
|
108
|
+
): Promise<WranglerResult<void>>;
|
|
109
|
+
|
|
110
|
+
// Monitoring
|
|
111
|
+
tail(
|
|
112
|
+
options?: WranglerCommandOptions & { format?: 'pretty' | 'json' }
|
|
113
|
+
): Promise<WranglerResult<void>>;
|
|
114
|
+
|
|
115
|
+
// Versions
|
|
116
|
+
versionsList(
|
|
117
|
+
options?: WranglerCommandOptions
|
|
118
|
+
): Promise<WranglerResult<WorkerVersionInfo[]>>;
|
|
119
|
+
versionsRollback(
|
|
120
|
+
versionId: string,
|
|
121
|
+
options?: WranglerCommandOptions
|
|
122
|
+
): Promise<WranglerResult<void>>;
|
|
123
|
+
|
|
124
|
+
// Generic command execution
|
|
125
|
+
executeCommand(
|
|
126
|
+
command: string,
|
|
127
|
+
args: string[],
|
|
128
|
+
options?: WranglerCommandOptions
|
|
129
|
+
): Promise<WranglerResult<string>>;
|
|
130
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -38,6 +38,7 @@ export * from "./infrastructure/services/images";
|
|
|
38
38
|
export * from "./infrastructure/services/analytics";
|
|
39
39
|
export * from "./infrastructure/services/workflows";
|
|
40
40
|
export * from "./infrastructure/services/ai-gateway";
|
|
41
|
+
export * from "./infrastructure/services/wrangler";
|
|
41
42
|
|
|
42
43
|
// Infrastructure - Router, Middleware, Utils
|
|
43
44
|
export * from "./infrastructure/router";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrangler Service Exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { WranglerService } from './wrangler.service';
|
|
6
|
+
export type {
|
|
7
|
+
WranglerResult,
|
|
8
|
+
WranglerCommandOptions,
|
|
9
|
+
AuthInfo,
|
|
10
|
+
KVNamespaceInfo,
|
|
11
|
+
R2BucketInfo,
|
|
12
|
+
D1DatabaseInfo,
|
|
13
|
+
SecretInfo,
|
|
14
|
+
WorkerVersionInfo,
|
|
15
|
+
AnalyticsData,
|
|
16
|
+
} from '../../domain/entities/wrangler.entity';
|
|
17
|
+
export type { IWranglerService } from '../../domain/interfaces/wrangler.interface';
|
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrangler Service Implementation
|
|
3
|
+
* Wraps Wrangler CLI commands with TypeScript
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { exec, spawn } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import type {
|
|
9
|
+
WranglerResult,
|
|
10
|
+
WranglerCommandOptions,
|
|
11
|
+
AuthInfo,
|
|
12
|
+
KVNamespaceInfo,
|
|
13
|
+
R2BucketInfo,
|
|
14
|
+
D1DatabaseInfo,
|
|
15
|
+
SecretInfo,
|
|
16
|
+
WorkerVersionInfo,
|
|
17
|
+
} from '../../../domain/entities/wrangler.entity';
|
|
18
|
+
import type { IWranglerService } from '../../../domain/interfaces/wrangler.interface';
|
|
19
|
+
|
|
20
|
+
const execAsync = promisify(exec);
|
|
21
|
+
|
|
22
|
+
export class WranglerService implements IWranglerService {
|
|
23
|
+
private readonly wranglerCommand: string;
|
|
24
|
+
|
|
25
|
+
constructor(options?: { wranglerPath?: string }) {
|
|
26
|
+
this.wranglerCommand = options?.wranglerPath || 'npx wrangler';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Execute a wrangler command
|
|
31
|
+
*/
|
|
32
|
+
private async execute(
|
|
33
|
+
args: string[],
|
|
34
|
+
options: WranglerCommandOptions = {}
|
|
35
|
+
): Promise<WranglerResult<string>> {
|
|
36
|
+
const { cwd = process.cwd(), env = {}, timeout = 30000, silent = false } = options;
|
|
37
|
+
|
|
38
|
+
const command = `${this.wranglerCommand} ${args.join(' ')}`;
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
if (!silent) {
|
|
42
|
+
console.log(`🔧 Executing: ${command}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
46
|
+
cwd,
|
|
47
|
+
env: { ...process.env, ...env },
|
|
48
|
+
timeout,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
data: stdout.trim(),
|
|
54
|
+
stdout: stdout.trim(),
|
|
55
|
+
stderr: stderr.trim(),
|
|
56
|
+
};
|
|
57
|
+
} catch (error: unknown) {
|
|
58
|
+
const err = error as { stdout?: string; stderr?: string; code?: number };
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
error: err.stderr || err.stdout || String(error),
|
|
62
|
+
exitCode: err.code,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Execute a wrangler command with streaming (for dev, tail, etc.)
|
|
69
|
+
*/
|
|
70
|
+
private executeStreaming(
|
|
71
|
+
args: string[],
|
|
72
|
+
options: WranglerCommandOptions = {}
|
|
73
|
+
): Promise<WranglerResult<void>> {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const { cwd = process.cwd(), env = {} } = options;
|
|
76
|
+
const argsWithCommand = this.wranglerCommand.split(' ').concat(args);
|
|
77
|
+
|
|
78
|
+
const child = spawn(argsWithCommand[0], argsWithCommand.slice(1), {
|
|
79
|
+
cwd,
|
|
80
|
+
env: { ...process.env, ...env },
|
|
81
|
+
stdio: 'inherit',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
child.on('close', (code) => {
|
|
85
|
+
if (code === 0) {
|
|
86
|
+
resolve({ success: true });
|
|
87
|
+
} else {
|
|
88
|
+
resolve({
|
|
89
|
+
success: false,
|
|
90
|
+
error: `Command exited with code ${code}`,
|
|
91
|
+
exitCode: code,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
child.on('error', (error) => {
|
|
97
|
+
resolve({
|
|
98
|
+
success: false,
|
|
99
|
+
error: error.message,
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Parse JSON from stdout
|
|
107
|
+
*/
|
|
108
|
+
private parseJSON<T>(stdout: string): T | null {
|
|
109
|
+
try {
|
|
110
|
+
// Find JSON in output (wrangler sometimes outputs text before JSON)
|
|
111
|
+
const jsonMatch = stdout.match(/\{[\s\S]*\}/);
|
|
112
|
+
if (jsonMatch) {
|
|
113
|
+
return JSON.parse(jsonMatch[0]) as T;
|
|
114
|
+
}
|
|
115
|
+
return JSON.parse(stdout) as T;
|
|
116
|
+
} catch {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ==================== Authentication ====================
|
|
122
|
+
|
|
123
|
+
async login(options?: WranglerCommandOptions): Promise<WranglerResult<AuthInfo>> {
|
|
124
|
+
const result = await this.execute(['login'], options);
|
|
125
|
+
if (result.success) {
|
|
126
|
+
return {
|
|
127
|
+
...result,
|
|
128
|
+
data: { email: 'authenticated' },
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async logout(options?: WranglerCommandOptions): Promise<WranglerResult<void>> {
|
|
135
|
+
return this.execute(['logout'], options);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async whoami(options?: WranglerCommandOptions): Promise<WranglerResult<AuthInfo>> {
|
|
139
|
+
const result = await this.execute(['whoami', '--json'], options);
|
|
140
|
+
if (result.success && result.data) {
|
|
141
|
+
const data = this.parseJSON<AuthInfo>(result.data);
|
|
142
|
+
return {
|
|
143
|
+
...result,
|
|
144
|
+
data: data || { email: 'authenticated' },
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ==================== Project Management ====================
|
|
151
|
+
|
|
152
|
+
async init(
|
|
153
|
+
projectName: string,
|
|
154
|
+
template?: string,
|
|
155
|
+
options?: WranglerCommandOptions
|
|
156
|
+
): Promise<WranglerResult<void>> {
|
|
157
|
+
const args = ['init', projectName];
|
|
158
|
+
if (template) {
|
|
159
|
+
args.push('--template', template);
|
|
160
|
+
}
|
|
161
|
+
return this.execute(args, options);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async dev(
|
|
165
|
+
options?: WranglerCommandOptions & { port?: number; local?: boolean }
|
|
166
|
+
): Promise<WranglerResult<void>> {
|
|
167
|
+
const args = ['dev'];
|
|
168
|
+
if (options?.port) {
|
|
169
|
+
args.push('--port', options.port.toString());
|
|
170
|
+
}
|
|
171
|
+
if (options?.local) {
|
|
172
|
+
args.push('--local');
|
|
173
|
+
}
|
|
174
|
+
return this.executeStreaming(args, options);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async deploy(
|
|
178
|
+
options?: WranglerCommandOptions & { env?: string }
|
|
179
|
+
): Promise<WranglerResult<{ url?: string }>> {
|
|
180
|
+
const args = ['deploy'];
|
|
181
|
+
if (options?.env) {
|
|
182
|
+
args.push('--env', options.env);
|
|
183
|
+
}
|
|
184
|
+
const result = await this.execute(args, options);
|
|
185
|
+
|
|
186
|
+
if (result.success && result.data) {
|
|
187
|
+
// Extract URL from output
|
|
188
|
+
const urlMatch = result.data.match(/https?:\/\/[^\s]+/);
|
|
189
|
+
return {
|
|
190
|
+
...result,
|
|
191
|
+
data: { url: urlMatch?.[0] },
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async deleteWorker(
|
|
199
|
+
workerName: string,
|
|
200
|
+
options?: WranglerCommandOptions
|
|
201
|
+
): Promise<WranglerResult<void>> {
|
|
202
|
+
return this.execute(['delete', workerName], options);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ==================== KV Operations ====================
|
|
206
|
+
|
|
207
|
+
async kvNamespaceCreate(
|
|
208
|
+
title: string,
|
|
209
|
+
options?: WranglerCommandOptions
|
|
210
|
+
): Promise<WranglerResult<KVNamespaceInfo>> {
|
|
211
|
+
const result = await this.execute(['kv:namespace', 'create', title], options);
|
|
212
|
+
if (result.success && result.data) {
|
|
213
|
+
const data = this.parseJSON<KVNamespaceInfo>(result.data);
|
|
214
|
+
if (data) {
|
|
215
|
+
return { ...result, data };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async kvNamespaceList(
|
|
222
|
+
options?: WranglerCommandOptions
|
|
223
|
+
): Promise<WranglerResult<KVNamespaceInfo[]>> {
|
|
224
|
+
const result = await this.execute(['kv:namespace', 'list'], options);
|
|
225
|
+
if (result.success && result.data) {
|
|
226
|
+
const data = this.parseJSON<KVNamespaceInfo[]>(result.data);
|
|
227
|
+
if (data) {
|
|
228
|
+
return { ...result, data };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async kvKeyPut(
|
|
235
|
+
namespaceId: string,
|
|
236
|
+
key: string,
|
|
237
|
+
value: string,
|
|
238
|
+
options?: WranglerCommandOptions
|
|
239
|
+
): Promise<WranglerResult<void>> {
|
|
240
|
+
return this.execute(['kv:key', 'put', '--namespace-id', namespaceId, key, value], options);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async kvKeyGet(
|
|
244
|
+
namespaceId: string,
|
|
245
|
+
key: string,
|
|
246
|
+
options?: WranglerCommandOptions
|
|
247
|
+
): Promise<WranglerResult<string>> {
|
|
248
|
+
return this.execute(['kv:key', 'get', '--namespace-id', namespaceId, key], options);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async kvKeyDelete(
|
|
252
|
+
namespaceId: string,
|
|
253
|
+
key: string,
|
|
254
|
+
options?: WranglerCommandOptions
|
|
255
|
+
): Promise<WranglerResult<void>> {
|
|
256
|
+
return this.execute(['kv:key', 'delete', '--namespace-id', namespaceId, key], options);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ==================== R2 Operations ====================
|
|
260
|
+
|
|
261
|
+
async r2BucketCreate(
|
|
262
|
+
bucketName: string,
|
|
263
|
+
options?: WranglerCommandOptions
|
|
264
|
+
): Promise<WranglerResult<R2BucketInfo>> {
|
|
265
|
+
const result = await this.execute(['r2', 'bucket', 'create', bucketName], options);
|
|
266
|
+
if (result.success) {
|
|
267
|
+
return {
|
|
268
|
+
...result,
|
|
269
|
+
data: { name: bucketName },
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async r2BucketList(
|
|
276
|
+
options?: WranglerCommandOptions
|
|
277
|
+
): Promise<WranglerResult<R2BucketInfo[]>> {
|
|
278
|
+
const result = await this.execute(['r2', 'bucket', 'list'], options);
|
|
279
|
+
if (result.success && result.data) {
|
|
280
|
+
const data = this.parseJSON<R2BucketInfo[]>(result.data);
|
|
281
|
+
if (data) {
|
|
282
|
+
return { ...result, data };
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async r2BucketDelete(
|
|
289
|
+
bucketName: string,
|
|
290
|
+
options?: WranglerCommandOptions
|
|
291
|
+
): Promise<WranglerResult<void>> {
|
|
292
|
+
return this.execute(['r2', 'bucket', 'delete', bucketName], options);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async r2ObjectPut(
|
|
296
|
+
bucketName: string,
|
|
297
|
+
key: string,
|
|
298
|
+
file: string,
|
|
299
|
+
options?: WranglerCommandOptions
|
|
300
|
+
): Promise<WranglerResult<void>> {
|
|
301
|
+
return this.execute(['r2', 'object', 'put', bucketName, key, '--file', file], options);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ==================== D1 Operations ====================
|
|
305
|
+
|
|
306
|
+
async d1Create(
|
|
307
|
+
databaseName: string,
|
|
308
|
+
options?: WranglerCommandOptions
|
|
309
|
+
): Promise<WranglerResult<D1DatabaseInfo>> {
|
|
310
|
+
const result = await this.execute(['d1', 'create', databaseName], options);
|
|
311
|
+
if (result.success && result.data) {
|
|
312
|
+
const data = this.parseJSON<D1DatabaseInfo>(result.data);
|
|
313
|
+
if (data) {
|
|
314
|
+
return { ...result, data };
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async d1List(options?: WranglerCommandOptions): Promise<WranglerResult<D1DatabaseInfo[]>> {
|
|
321
|
+
const result = await this.execute(['d1', 'list'], options);
|
|
322
|
+
if (result.success && result.data) {
|
|
323
|
+
const data = this.parseJSON<D1DatabaseInfo[]>(result.data);
|
|
324
|
+
if (data) {
|
|
325
|
+
return { ...result, data };
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return result;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async d1Execute(
|
|
332
|
+
databaseName: string,
|
|
333
|
+
command: string,
|
|
334
|
+
file?: string,
|
|
335
|
+
options?: WranglerCommandOptions
|
|
336
|
+
): Promise<WranglerResult<unknown[]>> {
|
|
337
|
+
const args = ['d1', 'execute', databaseName];
|
|
338
|
+
if (file) {
|
|
339
|
+
args.push('--file', file);
|
|
340
|
+
} else {
|
|
341
|
+
args.push('--command', command);
|
|
342
|
+
}
|
|
343
|
+
const result = await this.execute(args, options);
|
|
344
|
+
if (result.success && result.data) {
|
|
345
|
+
const data = this.parseJSON<unknown[]>(result.data);
|
|
346
|
+
if (data) {
|
|
347
|
+
return { ...result, data };
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return result;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ==================== Secrets ====================
|
|
354
|
+
|
|
355
|
+
async secretPut(
|
|
356
|
+
secretName: string,
|
|
357
|
+
value: string,
|
|
358
|
+
options?: WranglerCommandOptions
|
|
359
|
+
): Promise<WranglerResult<void>> {
|
|
360
|
+
// For secrets, we need to use stdin
|
|
361
|
+
return new Promise((resolve) => {
|
|
362
|
+
const args = ['secret', 'put', secretName];
|
|
363
|
+
const argsWithCommand = this.wranglerCommand.split(' ').concat(args);
|
|
364
|
+
|
|
365
|
+
const child = spawn(argsWithCommand[0], argsWithCommand.slice(1), {
|
|
366
|
+
cwd: options?.cwd || process.cwd(),
|
|
367
|
+
env: { ...process.env, ...options?.env },
|
|
368
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
let stdout = '';
|
|
372
|
+
let stderr = '';
|
|
373
|
+
|
|
374
|
+
child.stdout?.on('data', (data) => {
|
|
375
|
+
stdout += data.toString();
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
child.stderr?.on('data', (data) => {
|
|
379
|
+
stderr += data.toString();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
child.on('close', (code) => {
|
|
383
|
+
if (code === 0) {
|
|
384
|
+
resolve({ success: true, stdout: stdout.trim() });
|
|
385
|
+
} else {
|
|
386
|
+
resolve({
|
|
387
|
+
success: false,
|
|
388
|
+
error: stderr || 'Failed to put secret',
|
|
389
|
+
exitCode: code,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// Write the secret value to stdin
|
|
395
|
+
child.stdin?.write(value);
|
|
396
|
+
child.stdin?.end();
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async secretList(options?: WranglerCommandOptions): Promise<WranglerResult<SecretInfo[]>> {
|
|
401
|
+
const result = await this.execute(['secret', 'list'], options);
|
|
402
|
+
if (result.success && result.data) {
|
|
403
|
+
const data = this.parseJSON<SecretInfo[]>(result.data);
|
|
404
|
+
if (data) {
|
|
405
|
+
return { ...result, data };
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return result;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async secretDelete(
|
|
412
|
+
secretName: string,
|
|
413
|
+
options?: WranglerCommandOptions
|
|
414
|
+
): Promise<WranglerResult<void>> {
|
|
415
|
+
return this.execute(['secret', 'delete', secretName], options);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ==================== Monitoring ====================
|
|
419
|
+
|
|
420
|
+
async tail(
|
|
421
|
+
options?: WranglerCommandOptions & { format?: 'pretty' | 'json' }
|
|
422
|
+
): Promise<WranglerResult<void>> {
|
|
423
|
+
const args = ['tail'];
|
|
424
|
+
if (options?.format) {
|
|
425
|
+
args.push('--format', options.format);
|
|
426
|
+
}
|
|
427
|
+
return this.executeStreaming(args, options);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// ==================== Versions ====================
|
|
431
|
+
|
|
432
|
+
async versionsList(
|
|
433
|
+
options?: WranglerCommandOptions
|
|
434
|
+
): Promise<WranglerResult<WorkerVersionInfo[]>> {
|
|
435
|
+
const result = await this.execute(['versions', 'list'], options);
|
|
436
|
+
if (result.success && result.data) {
|
|
437
|
+
const data = this.parseJSON<WorkerVersionInfo[]>(result.data);
|
|
438
|
+
if (data) {
|
|
439
|
+
return { ...result, data };
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return result;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
async versionsRollback(
|
|
446
|
+
versionId: string,
|
|
447
|
+
options?: WranglerCommandOptions
|
|
448
|
+
): Promise<WranglerResult<void>> {
|
|
449
|
+
return this.execute(['versions', 'rollback', '--version-id', versionId], options);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// ==================== Generic Command Execution ====================
|
|
453
|
+
|
|
454
|
+
async executeCommand(
|
|
455
|
+
command: string,
|
|
456
|
+
args: string[],
|
|
457
|
+
options?: WranglerCommandOptions
|
|
458
|
+
): Promise<WranglerResult<string>> {
|
|
459
|
+
return this.execute([command, ...args], options);
|
|
460
|
+
}
|
|
461
|
+
}
|