@firtoz/worker-helper 1.0.0 ā 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/CHANGELOG.md +10 -0
- package/README.md +61 -1
- package/package.json +13 -8
- package/src/cf-typegen.ts +138 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @firtoz/worker-helper
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`b0f7893`](https://github.com/firtoz/fullstack-toolkit/commit/b0f789314c4ee85d8c08466b968baad2977a2581) Thanks [@firtoz](https://github.com/firtoz)! - Added cf-typegen script utility for generating Cloudflare Workers TypeScript types
|
|
8
|
+
|
|
9
|
+
- Added cf-typegen script that runs wrangler types command for specified worker directory
|
|
10
|
+
- Utility used by test packages to generate worker-configuration.d.ts
|
|
11
|
+
- Simplified type generation workflow for Cloudflare Workers projects
|
|
12
|
+
|
|
3
13
|
## 1.0.0
|
|
4
14
|
|
|
5
15
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -6,19 +6,79 @@ Type-safe Web Worker helper with Zod validation for input and output messages. T
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
+
### Web Workers
|
|
10
|
+
|
|
9
11
|
- š **Type-safe**: Full TypeScript support with automatic type inference
|
|
10
12
|
- ā
**Zod Validation**: Automatic validation of both input and output messages
|
|
11
13
|
- šÆ **Custom Error Handlers**: Mandatory error handlers give you complete control over error handling
|
|
12
14
|
- š **Async Support**: Built-in support for async message handlers
|
|
13
15
|
- š§© **Discriminated Unions**: Works great with Zod's discriminated unions for type-safe message routing
|
|
14
16
|
|
|
17
|
+
### Cloudflare Workers
|
|
18
|
+
|
|
19
|
+
- š§ **cf-typegen**: Automatic `.env.local` creation from `wrangler.jsonc` vars
|
|
20
|
+
- š **Type Generation**: Wrapper around `wrangler types` with env preparation
|
|
21
|
+
|
|
15
22
|
## Installation
|
|
16
23
|
|
|
17
24
|
```bash
|
|
18
25
|
bun add @firtoz/worker-helper zod
|
|
19
26
|
```
|
|
20
27
|
|
|
21
|
-
##
|
|
28
|
+
## cf-typegen (Cloudflare Workers Utility)
|
|
29
|
+
|
|
30
|
+
Automatic TypeScript type generation and `.env.local` management for Cloudflare Workers projects.
|
|
31
|
+
|
|
32
|
+
### Setup
|
|
33
|
+
|
|
34
|
+
Add the script to your Cloudflare Workers package:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"scripts": {
|
|
39
|
+
"cf-typegen": "bun --cwd ../../packages/worker-helper cf-typegen $(pwd)"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### What It Does
|
|
45
|
+
|
|
46
|
+
1. **Reads `.env.local.example`** to find required env vars
|
|
47
|
+
2. **Creates/updates `.env.local`** with any missing vars (as empty strings)
|
|
48
|
+
3. **Runs `wrangler types`** to generate TypeScript definitions
|
|
49
|
+
|
|
50
|
+
### Example
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
cd your-worker-package
|
|
54
|
+
bun run cf-typegen
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Output:**
|
|
58
|
+
```
|
|
59
|
+
Running CF typegen for: /path/to/your-worker
|
|
60
|
+
ā Added missing env vars: OPENROUTER_API_KEY, DATABASE_URL
|
|
61
|
+
Running wrangler types...
|
|
62
|
+
ā Wrangler types generated
|
|
63
|
+
ā CF typegen completed successfully
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Generated `.env.local`:**
|
|
67
|
+
```env
|
|
68
|
+
OPENROUTER_API_KEY=
|
|
69
|
+
DATABASE_URL=
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Why This Matters
|
|
73
|
+
|
|
74
|
+
- Ensures `wrangler types` always succeeds (needs `.env.local` or `.dev.vars`)
|
|
75
|
+
- Keeps `.env.local` in sync with `.env.local.example`
|
|
76
|
+
- Avoids accidentally binding empty vars at runtime via `wrangler.jsonc` `vars`
|
|
77
|
+
- Developers can fill in actual values without committing them to git
|
|
78
|
+
- CI/CD can generate types without needing actual secrets
|
|
79
|
+
- `.env.local.example` serves as documentation for required env vars
|
|
80
|
+
|
|
81
|
+
## Web Worker Usage
|
|
22
82
|
|
|
23
83
|
### 1. Define Your Schemas
|
|
24
84
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firtoz/worker-helper",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Type-safe Web Worker helper with Zod validation
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Type-safe Web Worker helper with Zod validation and Cloudflare Workers utilities (cf-typegen)",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"module": "./src/index.ts",
|
|
7
7
|
"types": "./src/index.ts",
|
|
@@ -28,15 +28,20 @@
|
|
|
28
28
|
"lint:ci": "biome ci src",
|
|
29
29
|
"format": "biome format src --write",
|
|
30
30
|
"test": "bun test",
|
|
31
|
-
"test:watch": "bun test --watch"
|
|
31
|
+
"test:watch": "bun test --watch",
|
|
32
|
+
"cf-typegen": "bun ./src/cf-typegen.ts"
|
|
32
33
|
},
|
|
33
34
|
"keywords": [
|
|
34
35
|
"typescript",
|
|
35
36
|
"web-worker",
|
|
36
37
|
"worker",
|
|
38
|
+
"cloudflare-workers",
|
|
39
|
+
"cloudflare",
|
|
37
40
|
"zod",
|
|
38
41
|
"validation",
|
|
39
|
-
"type-safe"
|
|
42
|
+
"type-safe",
|
|
43
|
+
"wrangler",
|
|
44
|
+
"typegen"
|
|
40
45
|
],
|
|
41
46
|
"author": "Firtina Ozbalikchi <firtoz@github.com>",
|
|
42
47
|
"license": "MIT",
|
|
@@ -56,11 +61,11 @@
|
|
|
56
61
|
"access": "public"
|
|
57
62
|
},
|
|
58
63
|
"dependencies": {
|
|
59
|
-
"zod": "^4.
|
|
64
|
+
"zod": "^4.3.5"
|
|
60
65
|
},
|
|
61
66
|
"devDependencies": {
|
|
62
|
-
"@types/node": "^
|
|
63
|
-
"@firtoz/maybe-error": "^1.5.
|
|
64
|
-
"bun-types": "^1.3.
|
|
67
|
+
"@types/node": "^25.0.9",
|
|
68
|
+
"@firtoz/maybe-error": "^1.5.2",
|
|
69
|
+
"bun-types": "^1.3.6"
|
|
65
70
|
}
|
|
66
71
|
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
|
|
6
|
+
// Use the current working directory
|
|
7
|
+
const cwd = process.argv[2];
|
|
8
|
+
if (!cwd || !fs.existsSync(cwd)) {
|
|
9
|
+
console.error(
|
|
10
|
+
"Please specify a directory as the first parameter. Usually $(pwd).",
|
|
11
|
+
);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(`Running CF typegen for: ${cwd}`);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Extracts required env vars from .env.local.example
|
|
19
|
+
*/
|
|
20
|
+
function getRequiredEnvVars(examplePath: string): string[] {
|
|
21
|
+
try {
|
|
22
|
+
if (!fs.existsSync(examplePath)) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const content = fs.readFileSync(examplePath, "utf8");
|
|
27
|
+
const vars: string[] = [];
|
|
28
|
+
|
|
29
|
+
// Parse .env format: VAR_NAME=value
|
|
30
|
+
for (const line of content.split("\n")) {
|
|
31
|
+
const trimmed = line.trim();
|
|
32
|
+
// Skip comments and empty lines
|
|
33
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
34
|
+
|
|
35
|
+
const match = trimmed.match(/^([A-Z_][A-Z0-9_]*)=/);
|
|
36
|
+
if (match) {
|
|
37
|
+
vars.push(match[1]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return vars;
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.warn(`Failed to read ${examplePath}:`, err);
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Ensures .env.local exists with required env vars from .env.local.example
|
|
50
|
+
*/
|
|
51
|
+
function prepareEnvLocal(): { created: boolean; added: string[] } {
|
|
52
|
+
const envPath = path.join(cwd, ".env.local");
|
|
53
|
+
const examplePath = path.join(cwd, ".env.local.example");
|
|
54
|
+
|
|
55
|
+
if (!fs.existsSync(examplePath)) {
|
|
56
|
+
console.log("No .env.local.example found, skipping env preparation");
|
|
57
|
+
return { created: false, added: [] };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const requiredVars = getRequiredEnvVars(examplePath);
|
|
61
|
+
if (requiredVars.length === 0) {
|
|
62
|
+
console.log("No vars found in .env.local.example");
|
|
63
|
+
return { created: false, added: [] };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let content = "";
|
|
67
|
+
let created = false;
|
|
68
|
+
const added: string[] = [];
|
|
69
|
+
|
|
70
|
+
if (fs.existsSync(envPath)) {
|
|
71
|
+
content = fs.readFileSync(envPath, "utf8");
|
|
72
|
+
} else {
|
|
73
|
+
created = true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check which vars are missing
|
|
77
|
+
for (const varName of requiredVars) {
|
|
78
|
+
const regex = new RegExp(`^${varName}=`, "m");
|
|
79
|
+
if (!regex.test(content)) {
|
|
80
|
+
if (content && !content.endsWith("\n")) {
|
|
81
|
+
content += "\n";
|
|
82
|
+
}
|
|
83
|
+
content += `${varName}=\n`;
|
|
84
|
+
added.push(varName);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Write if there were any changes
|
|
89
|
+
if (created || added.length > 0) {
|
|
90
|
+
fs.writeFileSync(envPath, content);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { created, added };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Step 1: Prepare .env.local with required vars from wrangler.jsonc
|
|
97
|
+
function prepareEnv() {
|
|
98
|
+
try {
|
|
99
|
+
const updates = prepareEnvLocal();
|
|
100
|
+
if (updates.created) {
|
|
101
|
+
console.log("ā Created .env.local");
|
|
102
|
+
}
|
|
103
|
+
if (updates.added.length > 0) {
|
|
104
|
+
console.log(`ā Added missing env vars: ${updates.added.join(", ")}`);
|
|
105
|
+
}
|
|
106
|
+
if (!updates.created && updates.added.length === 0) {
|
|
107
|
+
console.log("ā .env.local file already has all required vars");
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error(String(error));
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Step 2: Run wrangler types
|
|
116
|
+
function runWranglerTypes() {
|
|
117
|
+
console.log("Running wrangler types...");
|
|
118
|
+
try {
|
|
119
|
+
execSync("wrangler types -c wrangler.jsonc --env-file .env.local", {
|
|
120
|
+
cwd,
|
|
121
|
+
stdio: "inherit",
|
|
122
|
+
});
|
|
123
|
+
console.log("ā Wrangler types generated");
|
|
124
|
+
} catch {
|
|
125
|
+
console.error("Failed to run wrangler types");
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Run all steps
|
|
131
|
+
try {
|
|
132
|
+
prepareEnv();
|
|
133
|
+
runWranglerTypes();
|
|
134
|
+
console.log("\nā CF typegen completed successfully");
|
|
135
|
+
} catch (error: unknown) {
|
|
136
|
+
console.error("\nā CF typegen failed:", error);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|