@striae-org/striae 6.1.8 → 7.0.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/.env.example +0 -26
- package/app/components/actions/image-manage.ts +17 -67
- package/functions/api/audit/[[path]].ts +9 -24
- package/functions/api/data/[[path]].ts +9 -24
- package/functions/api/image/[[path]].ts +14 -30
- package/functions/api/pdf/[[path]].ts +9 -24
- package/functions/api/user/[[path]].ts +20 -36
- package/package.json +9 -10
- package/scripts/deploy-all.sh +29 -10
- package/scripts/deploy-config/modules/env-utils.sh +0 -68
- package/scripts/deploy-config/modules/prompt.sh +4 -110
- package/scripts/deploy-config/modules/scaffolding.sh +5 -0
- package/scripts/deploy-config/modules/validation.sh +1 -19
- package/scripts/deploy-pages-secrets.sh +0 -9
- package/scripts/deploy-worker-secrets.sh +2 -8
- package/tsconfig.json +1 -4
- package/workers/audit-worker/package.json +2 -2
- package/workers/audit-worker/src/audit-worker.ts +0 -5
- package/workers/audit-worker/src/config.ts +1 -6
- package/workers/audit-worker/src/types.ts +0 -1
- package/workers/audit-worker/wrangler.jsonc.example +2 -6
- package/workers/data-worker/package.json +3 -3
- package/workers/data-worker/src/config.ts +1 -6
- package/workers/data-worker/src/data-worker.ts +1 -6
- package/workers/data-worker/src/types.ts +0 -1
- package/workers/data-worker/wrangler.jsonc.example +2 -4
- package/workers/image-worker/package.json +2 -2
- package/workers/image-worker/src/handlers/delete-image.ts +0 -5
- package/workers/image-worker/src/handlers/mint-signed-url.ts +0 -5
- package/workers/image-worker/src/handlers/serve-image.ts +1 -2
- package/workers/image-worker/src/handlers/upload-image.ts +0 -5
- package/workers/image-worker/src/security/signed-url.ts +2 -2
- package/workers/image-worker/src/types.ts +0 -1
- package/workers/image-worker/wrangler.jsonc.example +2 -1
- package/workers/pdf-worker/package.json +2 -2
- package/workers/pdf-worker/src/pdf-worker.ts +0 -8
- package/workers/pdf-worker/wrangler.jsonc.example +2 -1
- package/workers/user-worker/package.json +2 -2
- package/workers/user-worker/src/auth.ts +0 -7
- package/workers/user-worker/src/types.ts +0 -2
- package/workers/user-worker/src/user-worker.ts +1 -3
- package/workers/user-worker/wrangler.jsonc.example +2 -1
- package/wrangler.toml.example +22 -2
- package/worker-configuration.d.ts +0 -7509
- package/workers/image-worker/src/auth.ts +0 -7
package/scripts/deploy-all.sh
CHANGED
|
@@ -79,7 +79,7 @@ echo -e "${GREEN}✅ Preflight checks passed${NC}"
|
|
|
79
79
|
echo ""
|
|
80
80
|
|
|
81
81
|
# Step 1: Configuration Setup
|
|
82
|
-
echo -e "${PURPLE}Step 1/
|
|
82
|
+
echo -e "${PURPLE}Step 1/7: Configuration Setup${NC}"
|
|
83
83
|
echo "------------------------------"
|
|
84
84
|
echo -e "${YELLOW}⚙️ Setting up configuration files and replacing placeholders...${NC}"
|
|
85
85
|
if ! bash "$SCRIPT_DIR/deploy-config.sh"; then
|
|
@@ -92,7 +92,7 @@ run_config_checkpoint
|
|
|
92
92
|
echo ""
|
|
93
93
|
|
|
94
94
|
# Step 2: Install Worker Dependencies
|
|
95
|
-
echo -e "${PURPLE}Step 2/
|
|
95
|
+
echo -e "${PURPLE}Step 2/7: Installing Worker Dependencies${NC}"
|
|
96
96
|
echo "----------------------------------------"
|
|
97
97
|
echo -e "${YELLOW}📦 Installing npm dependencies for all workers...${NC}"
|
|
98
98
|
if ! bash "$SCRIPT_DIR/install-workers.sh"; then
|
|
@@ -102,8 +102,26 @@ fi
|
|
|
102
102
|
echo -e "${GREEN}✅ All worker dependencies installed successfully${NC}"
|
|
103
103
|
echo ""
|
|
104
104
|
|
|
105
|
-
# Step 3:
|
|
106
|
-
echo -e "${PURPLE}Step 3/
|
|
105
|
+
# Step 3: Generate Wrangler Types
|
|
106
|
+
echo -e "${PURPLE}Step 3/7: Generating Wrangler Types${NC}"
|
|
107
|
+
echo "-------------------------------------"
|
|
108
|
+
echo -e "${YELLOW}📝 Running wrangler types in root and all worker directories...${NC}"
|
|
109
|
+
if ! npx wrangler types; then
|
|
110
|
+
echo -e "${RED}❌ Root wrangler types generation failed!${NC}"
|
|
111
|
+
exit 1
|
|
112
|
+
fi
|
|
113
|
+
for WORKER in audit-worker data-worker image-worker pdf-worker user-worker; do
|
|
114
|
+
echo -e "${YELLOW} → Generating types for ${WORKER}...${NC}"
|
|
115
|
+
if ! (cd "workers/$WORKER" && npx wrangler types); then
|
|
116
|
+
echo -e "${RED}❌ wrangler types failed for ${WORKER}!${NC}"
|
|
117
|
+
exit 1
|
|
118
|
+
fi
|
|
119
|
+
done
|
|
120
|
+
echo -e "${GREEN}✅ Wrangler types generated successfully${NC}"
|
|
121
|
+
echo ""
|
|
122
|
+
|
|
123
|
+
# Step 4: Deploy Workers
|
|
124
|
+
echo -e "${PURPLE}Step 4/7: Deploying Workers${NC}"
|
|
107
125
|
echo "----------------------------"
|
|
108
126
|
echo -e "${YELLOW}🔧 Deploying all 5 Cloudflare Workers...${NC}"
|
|
109
127
|
if ! npm run deploy-workers; then
|
|
@@ -113,8 +131,8 @@ fi
|
|
|
113
131
|
echo -e "${GREEN}✅ All workers deployed successfully${NC}"
|
|
114
132
|
echo ""
|
|
115
133
|
|
|
116
|
-
# Step
|
|
117
|
-
echo -e "${PURPLE}Step
|
|
134
|
+
# Step 5: Deploy Worker Secrets
|
|
135
|
+
echo -e "${PURPLE}Step 5/7: Deploying Worker Secrets${NC}"
|
|
118
136
|
echo "-----------------------------------"
|
|
119
137
|
echo -e "${YELLOW}🔐 Deploying worker environment variables...${NC}"
|
|
120
138
|
if ! bash "$SCRIPT_DIR/deploy-worker-secrets.sh"; then
|
|
@@ -124,8 +142,8 @@ fi
|
|
|
124
142
|
echo -e "${GREEN}✅ Worker secrets deployed successfully${NC}"
|
|
125
143
|
echo ""
|
|
126
144
|
|
|
127
|
-
# Step
|
|
128
|
-
echo -e "${PURPLE}Step
|
|
145
|
+
# Step 6: Deploy Pages Secrets
|
|
146
|
+
echo -e "${PURPLE}Step 6/7: Deploying Pages Secrets${NC}"
|
|
129
147
|
echo "----------------------------------"
|
|
130
148
|
echo -e "${YELLOW}🔐 Deploying Pages environment variables...${NC}"
|
|
131
149
|
if ! bash "$SCRIPT_DIR/deploy-pages-secrets.sh"; then
|
|
@@ -135,8 +153,8 @@ fi
|
|
|
135
153
|
echo -e "${GREEN}✅ Pages secrets deployed successfully${NC}"
|
|
136
154
|
echo ""
|
|
137
155
|
|
|
138
|
-
# Step
|
|
139
|
-
echo -e "${PURPLE}Step
|
|
156
|
+
# Step 7: Deploy Pages
|
|
157
|
+
echo -e "${PURPLE}Step 7/7: Deploying Pages${NC}"
|
|
140
158
|
echo "--------------------------"
|
|
141
159
|
echo -e "${YELLOW}🌐 Building and deploying Pages...${NC}"
|
|
142
160
|
if ! npm run deploy-pages; then
|
|
@@ -153,6 +171,7 @@ echo "=========================================="
|
|
|
153
171
|
echo ""
|
|
154
172
|
echo -e "${BLUE}Deployed Components:${NC}"
|
|
155
173
|
echo " ✅ Worker dependencies (npm install)"
|
|
174
|
+
echo " ✅ Wrangler types (root + all workers)"
|
|
156
175
|
echo " ✅ 5 Cloudflare Workers"
|
|
157
176
|
echo " ✅ Worker environment variables"
|
|
158
177
|
echo " ✅ Pages environment variables"
|
|
@@ -56,29 +56,12 @@ normalize_worker_label_value() {
|
|
|
56
56
|
printf '%s' "$label"
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
normalize_worker_subdomain_value() {
|
|
60
|
-
local subdomain="$1"
|
|
61
|
-
|
|
62
|
-
subdomain=$(normalize_domain_value "$subdomain")
|
|
63
|
-
subdomain="${subdomain#.}"
|
|
64
|
-
subdomain="${subdomain%.}"
|
|
65
|
-
subdomain=$(printf '%s' "$subdomain" | tr '[:upper:]' '[:lower:]')
|
|
66
|
-
|
|
67
|
-
printf '%s' "$subdomain"
|
|
68
|
-
}
|
|
69
|
-
|
|
70
59
|
is_valid_worker_label() {
|
|
71
60
|
local label="$1"
|
|
72
61
|
|
|
73
62
|
[[ "$label" =~ ^[a-z0-9-]+$ ]]
|
|
74
63
|
}
|
|
75
64
|
|
|
76
|
-
is_valid_worker_subdomain() {
|
|
77
|
-
local subdomain="$1"
|
|
78
|
-
|
|
79
|
-
[[ "$subdomain" =~ ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$ ]]
|
|
80
|
-
}
|
|
81
|
-
|
|
82
65
|
strip_carriage_returns() {
|
|
83
66
|
printf '%s' "$1" | tr -d '\r'
|
|
84
67
|
}
|
|
@@ -196,57 +179,6 @@ confirm_key_pair_regeneration() {
|
|
|
196
179
|
return 1
|
|
197
180
|
}
|
|
198
181
|
|
|
199
|
-
generate_worker_subdomain_label() {
|
|
200
|
-
node -e "const { randomInt } = require('crypto'); const alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789'; let value = ''; for (let index = 0; index < 10; index += 1) { value += alphabet[randomInt(alphabet.length)]; } process.stdout.write(value);" 2>/dev/null
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
compose_worker_domain() {
|
|
204
|
-
local worker_name=$1
|
|
205
|
-
local worker_subdomain=$2
|
|
206
|
-
|
|
207
|
-
worker_name=$(normalize_worker_label_value "$worker_name")
|
|
208
|
-
worker_subdomain=$(normalize_worker_subdomain_value "$worker_subdomain")
|
|
209
|
-
|
|
210
|
-
if [ -z "$worker_name" ] || [ -z "$worker_subdomain" ]; then
|
|
211
|
-
return 1
|
|
212
|
-
fi
|
|
213
|
-
|
|
214
|
-
if ! is_valid_worker_label "$worker_name" || ! is_valid_worker_subdomain "$worker_subdomain"; then
|
|
215
|
-
return 1
|
|
216
|
-
fi
|
|
217
|
-
|
|
218
|
-
printf '%s.%s' "$worker_name" "$worker_subdomain"
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
infer_worker_subdomain_from_domain() {
|
|
222
|
-
local worker_name=$1
|
|
223
|
-
local worker_domain=$2
|
|
224
|
-
local worker_subdomain=""
|
|
225
|
-
|
|
226
|
-
worker_name=$(normalize_worker_label_value "$worker_name")
|
|
227
|
-
worker_domain=$(normalize_domain_value "$worker_domain")
|
|
228
|
-
worker_domain=$(printf '%s' "$worker_domain" | tr '[:upper:]' '[:lower:]')
|
|
229
|
-
|
|
230
|
-
if [ -z "$worker_name" ] || [ -z "$worker_domain" ] || is_placeholder "$worker_name" || is_placeholder "$worker_domain"; then
|
|
231
|
-
printf '%s' ""
|
|
232
|
-
return 0
|
|
233
|
-
fi
|
|
234
|
-
|
|
235
|
-
case "$worker_domain" in
|
|
236
|
-
"$worker_name".*)
|
|
237
|
-
worker_subdomain="${worker_domain#${worker_name}.}"
|
|
238
|
-
worker_subdomain=$(normalize_worker_subdomain_value "$worker_subdomain")
|
|
239
|
-
|
|
240
|
-
if is_valid_worker_subdomain "$worker_subdomain"; then
|
|
241
|
-
printf '%s' "$worker_subdomain"
|
|
242
|
-
return 0
|
|
243
|
-
fi
|
|
244
|
-
;;
|
|
245
|
-
esac
|
|
246
|
-
|
|
247
|
-
printf '%s' ""
|
|
248
|
-
}
|
|
249
|
-
|
|
250
182
|
write_env_var() {
|
|
251
183
|
local var_name=$1
|
|
252
184
|
local var_value=$2
|
|
@@ -23,7 +23,7 @@ prompt_for_secrets() {
|
|
|
23
23
|
is_auto_generated_secret_var() {
|
|
24
24
|
local var_name=$1
|
|
25
25
|
case "$var_name" in
|
|
26
|
-
|
|
26
|
+
IMAGE_SIGNED_URL_SECRET)
|
|
27
27
|
return 0
|
|
28
28
|
;;
|
|
29
29
|
*)
|
|
@@ -36,18 +36,6 @@ prompt_for_secrets() {
|
|
|
36
36
|
local var_name=$1
|
|
37
37
|
local value=$2
|
|
38
38
|
case "$var_name" in
|
|
39
|
-
USER_DB_AUTH)
|
|
40
|
-
[ "$value" = "your_custom_user_db_auth_token_here" ]
|
|
41
|
-
;;
|
|
42
|
-
R2_KEY_SECRET)
|
|
43
|
-
[ "$value" = "your_custom_r2_secret_here" ]
|
|
44
|
-
;;
|
|
45
|
-
PDF_WORKER_AUTH)
|
|
46
|
-
[ "$value" = "your_custom_pdf_worker_auth_token_here" ]
|
|
47
|
-
;;
|
|
48
|
-
IMAGES_API_TOKEN)
|
|
49
|
-
[ "$value" = "your_cloudflare_images_api_token_here" ]
|
|
50
|
-
;;
|
|
51
39
|
IMAGE_SIGNED_URL_SECRET)
|
|
52
40
|
[ "$value" = "your_image_signed_url_secret_here" ]
|
|
53
41
|
;;
|
|
@@ -214,42 +202,11 @@ prompt_for_secrets() {
|
|
|
214
202
|
echo ""
|
|
215
203
|
}
|
|
216
204
|
|
|
217
|
-
set_worker_domain_from_shared_subdomain() {
|
|
218
|
-
local worker_name_var=$1
|
|
219
|
-
local worker_domain_var=$2
|
|
220
|
-
local worker_name_value="${!worker_name_var}"
|
|
221
|
-
local composed_domain=""
|
|
222
|
-
|
|
223
|
-
worker_name_value=$(normalize_worker_label_value "$worker_name_value")
|
|
224
|
-
|
|
225
|
-
if [ -z "$worker_name_value" ] || ! is_valid_worker_label "$worker_name_value"; then
|
|
226
|
-
echo -e "${RED}❌ $worker_name_var must use only lowercase letters, numbers, and dashes.${NC}"
|
|
227
|
-
exit 1
|
|
228
|
-
fi
|
|
229
|
-
|
|
230
|
-
composed_domain=$(compose_worker_domain "$worker_name_value" "$shared_worker_subdomain" || echo "")
|
|
231
|
-
|
|
232
|
-
if [ -z "$composed_domain" ]; then
|
|
233
|
-
echo -e "${RED}❌ Could not build $worker_domain_var from $worker_name_var and shared worker-subdomain.${NC}"
|
|
234
|
-
exit 1
|
|
235
|
-
fi
|
|
236
|
-
|
|
237
|
-
write_env_var "$worker_domain_var" "$composed_domain"
|
|
238
|
-
export "$worker_domain_var=$composed_domain"
|
|
239
|
-
echo -e "${GREEN}✅ $worker_domain_var set to $composed_domain${NC}"
|
|
240
|
-
}
|
|
241
|
-
|
|
242
205
|
echo -e "${BLUE}📊 CLOUDFLARE CORE CONFIGURATION${NC}"
|
|
243
206
|
echo "=================================="
|
|
244
207
|
prompt_for_var "ACCOUNT_ID" "Your Cloudflare Account ID"
|
|
245
208
|
|
|
246
|
-
echo -e "${BLUE}
|
|
247
|
-
echo "==================================="
|
|
248
|
-
prompt_for_var "USER_DB_AUTH" "Custom user database authentication token (generate with: openssl rand -hex 16)"
|
|
249
|
-
prompt_for_var "R2_KEY_SECRET" "Custom R2 storage authentication token (generate with: openssl rand -hex 16)"
|
|
250
|
-
prompt_for_var "IMAGES_API_TOKEN" "Image worker API token (shared between workers)"
|
|
251
|
-
|
|
252
|
-
echo -e "${BLUE}🔥 FIREBASE AUTH CONFIGURATION${NC}"
|
|
209
|
+
echo -e "${BLUE} FIREBASE AUTH CONFIGURATION${NC}"
|
|
253
210
|
echo "==============================="
|
|
254
211
|
prompt_for_var "API_KEY" "Firebase API key"
|
|
255
212
|
prompt_for_var "AUTH_DOMAIN" "Firebase auth domain (project-id.firebaseapp.com)"
|
|
@@ -264,77 +221,15 @@ prompt_for_secrets() {
|
|
|
264
221
|
prompt_for_var "PAGES_PROJECT_NAME" "Your Cloudflare Pages project name"
|
|
265
222
|
prompt_for_var "PAGES_CUSTOM_DOMAIN" "Your custom domain (e.g., striae.org) - DO NOT include https://"
|
|
266
223
|
|
|
267
|
-
echo -e "${BLUE}🔑 WORKER NAMES
|
|
268
|
-
echo "
|
|
224
|
+
echo -e "${BLUE}🔑 WORKER NAMES${NC}"
|
|
225
|
+
echo "==============="
|
|
269
226
|
echo -e "${YELLOW}Worker names are lowercased automatically and must use only letters, numbers, and dashes.${NC}"
|
|
270
|
-
echo -e "${YELLOW}Enter one shared worker-subdomain as a hostname (for example: team-name.workers.dev).${NC}"
|
|
271
|
-
echo -e "${YELLOW}Each worker domain is generated as {worker-name}.{worker-subdomain}.${NC}"
|
|
272
|
-
|
|
273
|
-
local shared_worker_subdomain=""
|
|
274
|
-
local shared_worker_subdomain_default=""
|
|
275
|
-
local shared_worker_subdomain_input=""
|
|
276
|
-
|
|
277
|
-
shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$USER_WORKER_NAME" "$USER_WORKER_DOMAIN")
|
|
278
|
-
if [ -z "$shared_worker_subdomain_default" ]; then
|
|
279
|
-
shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$DATA_WORKER_NAME" "$DATA_WORKER_DOMAIN")
|
|
280
|
-
fi
|
|
281
|
-
if [ -z "$shared_worker_subdomain_default" ]; then
|
|
282
|
-
shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$AUDIT_WORKER_NAME" "$AUDIT_WORKER_DOMAIN")
|
|
283
|
-
fi
|
|
284
|
-
if [ -z "$shared_worker_subdomain_default" ]; then
|
|
285
|
-
shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$IMAGES_WORKER_NAME" "$IMAGES_WORKER_DOMAIN")
|
|
286
|
-
fi
|
|
287
|
-
if [ -z "$shared_worker_subdomain_default" ]; then
|
|
288
|
-
shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$PDF_WORKER_NAME" "$PDF_WORKER_DOMAIN")
|
|
289
|
-
fi
|
|
290
|
-
|
|
291
|
-
while true; do
|
|
292
|
-
echo -e "${BLUE}WORKER_SUBDOMAIN${NC}"
|
|
293
|
-
|
|
294
|
-
if [ "$update_env" != "true" ] && [ -n "$shared_worker_subdomain_default" ] && ! is_placeholder "$shared_worker_subdomain_default"; then
|
|
295
|
-
echo -e "${GREEN}Current value: $shared_worker_subdomain_default${NC}"
|
|
296
|
-
read -p "New value (or press Enter to keep current): " shared_worker_subdomain_input
|
|
297
|
-
shared_worker_subdomain_input=$(strip_carriage_returns "$shared_worker_subdomain_input")
|
|
298
|
-
|
|
299
|
-
if [ -z "$shared_worker_subdomain_input" ]; then
|
|
300
|
-
shared_worker_subdomain="$shared_worker_subdomain_default"
|
|
301
|
-
else
|
|
302
|
-
shared_worker_subdomain="$shared_worker_subdomain_input"
|
|
303
|
-
fi
|
|
304
|
-
else
|
|
305
|
-
read -p "Enter shared worker-subdomain (e.g., team-name.workers.dev): " shared_worker_subdomain_input
|
|
306
|
-
shared_worker_subdomain_input=$(strip_carriage_returns "$shared_worker_subdomain_input")
|
|
307
|
-
shared_worker_subdomain="$shared_worker_subdomain_input"
|
|
308
|
-
fi
|
|
309
|
-
|
|
310
|
-
if [ -z "$shared_worker_subdomain" ] || is_placeholder "$shared_worker_subdomain"; then
|
|
311
|
-
echo -e "${RED}❌ shared worker-subdomain is required and cannot be a placeholder.${NC}"
|
|
312
|
-
continue
|
|
313
|
-
fi
|
|
314
|
-
|
|
315
|
-
shared_worker_subdomain=$(normalize_worker_subdomain_value "$shared_worker_subdomain")
|
|
316
|
-
|
|
317
|
-
if [ -z "$shared_worker_subdomain" ] || ! is_valid_worker_subdomain "$shared_worker_subdomain"; then
|
|
318
|
-
echo -e "${RED}❌ shared worker-subdomain must be a valid hostname like team-name.workers.dev (letters, numbers, dashes, and dots).${NC}"
|
|
319
|
-
continue
|
|
320
|
-
fi
|
|
321
|
-
|
|
322
|
-
echo -e "${GREEN}✅ Shared worker-subdomain set to: $shared_worker_subdomain${NC}"
|
|
323
|
-
echo ""
|
|
324
|
-
break
|
|
325
|
-
done
|
|
326
227
|
|
|
327
228
|
prompt_for_var "USER_WORKER_NAME" "User worker name"
|
|
328
229
|
prompt_for_var "DATA_WORKER_NAME" "Data worker name"
|
|
329
230
|
prompt_for_var "AUDIT_WORKER_NAME" "Audit worker name"
|
|
330
231
|
prompt_for_var "IMAGES_WORKER_NAME" "Images worker name"
|
|
331
232
|
prompt_for_var "PDF_WORKER_NAME" "PDF worker name"
|
|
332
|
-
|
|
333
|
-
set_worker_domain_from_shared_subdomain "USER_WORKER_NAME" "USER_WORKER_DOMAIN"
|
|
334
|
-
set_worker_domain_from_shared_subdomain "DATA_WORKER_NAME" "DATA_WORKER_DOMAIN"
|
|
335
|
-
set_worker_domain_from_shared_subdomain "AUDIT_WORKER_NAME" "AUDIT_WORKER_DOMAIN"
|
|
336
|
-
set_worker_domain_from_shared_subdomain "IMAGES_WORKER_NAME" "IMAGES_WORKER_DOMAIN"
|
|
337
|
-
set_worker_domain_from_shared_subdomain "PDF_WORKER_NAME" "PDF_WORKER_DOMAIN"
|
|
338
233
|
echo ""
|
|
339
234
|
|
|
340
235
|
echo -e "${BLUE}🗄️ STORAGE CONFIGURATION${NC}"
|
|
@@ -346,7 +241,6 @@ prompt_for_secrets() {
|
|
|
346
241
|
|
|
347
242
|
echo -e "${BLUE}🔐 SERVICE-SPECIFIC SECRETS${NC}"
|
|
348
243
|
echo "============================"
|
|
349
|
-
prompt_for_var "PDF_WORKER_AUTH" "PDF worker authentication token (generate with: openssl rand -hex 16)"
|
|
350
244
|
prompt_for_var "IMAGE_SIGNED_URL_SECRET" "Image signed URL secret (generate with: openssl rand -base64 48 | tr '+/' '-_' | tr -d '=')"
|
|
351
245
|
|
|
352
246
|
# Auto-derive IMAGE_SIGNED_URL_BASE_URL from PAGES_CUSTOM_DOMAIN if not yet set or still
|
|
@@ -185,6 +185,11 @@ update_wrangler_configs() {
|
|
|
185
185
|
if [ -f "wrangler.toml" ]; then
|
|
186
186
|
echo -e "${YELLOW} Updating wrangler.toml...${NC}"
|
|
187
187
|
sed -i "s/\"PAGES_PROJECT_NAME\"/\"$PAGES_PROJECT_NAME\"/g" wrangler.toml
|
|
188
|
+
sed -i "s/USER_WORKER_NAME/$USER_WORKER_NAME/g" wrangler.toml
|
|
189
|
+
sed -i "s/DATA_WORKER_NAME/$DATA_WORKER_NAME/g" wrangler.toml
|
|
190
|
+
sed -i "s/AUDIT_WORKER_NAME/$AUDIT_WORKER_NAME/g" wrangler.toml
|
|
191
|
+
sed -i "s/IMAGES_WORKER_NAME/$IMAGES_WORKER_NAME/g" wrangler.toml
|
|
192
|
+
sed -i "s/PDF_WORKER_NAME/$PDF_WORKER_NAME/g" wrangler.toml
|
|
188
193
|
echo -e "${GREEN} ✅ main wrangler.toml configuration updated${NC}"
|
|
189
194
|
fi
|
|
190
195
|
|
|
@@ -75,11 +75,6 @@ required_vars=(
|
|
|
75
75
|
# Core Cloudflare Configuration
|
|
76
76
|
"ACCOUNT_ID"
|
|
77
77
|
|
|
78
|
-
# Shared Authentication & Storage
|
|
79
|
-
"USER_DB_AUTH"
|
|
80
|
-
"R2_KEY_SECRET"
|
|
81
|
-
"IMAGES_API_TOKEN"
|
|
82
|
-
|
|
83
78
|
# Firebase Auth Configuration
|
|
84
79
|
"API_KEY"
|
|
85
80
|
"AUTH_DOMAIN"
|
|
@@ -102,13 +97,6 @@ required_vars=(
|
|
|
102
97
|
"IMAGES_WORKER_NAME"
|
|
103
98
|
"PDF_WORKER_NAME"
|
|
104
99
|
|
|
105
|
-
# Worker Domains (required for proxy/env secrets and worker fallbacks)
|
|
106
|
-
"USER_WORKER_DOMAIN"
|
|
107
|
-
"DATA_WORKER_DOMAIN"
|
|
108
|
-
"AUDIT_WORKER_DOMAIN"
|
|
109
|
-
"IMAGES_WORKER_DOMAIN"
|
|
110
|
-
"PDF_WORKER_DOMAIN"
|
|
111
|
-
|
|
112
100
|
# Storage Configuration (required for config replacement)
|
|
113
101
|
"DATA_BUCKET_NAME"
|
|
114
102
|
"AUDIT_BUCKET_NAME"
|
|
@@ -116,7 +104,6 @@ required_vars=(
|
|
|
116
104
|
"KV_STORE_ID"
|
|
117
105
|
|
|
118
106
|
# Worker-Specific Secrets (required for deployment)
|
|
119
|
-
"PDF_WORKER_AUTH"
|
|
120
107
|
"IMAGE_SIGNED_URL_SECRET"
|
|
121
108
|
"BROWSER_API_TOKEN"
|
|
122
109
|
"MANIFEST_SIGNING_PRIVATE_KEY"
|
|
@@ -212,11 +199,6 @@ validate_env_value_formats() {
|
|
|
212
199
|
echo -e "${YELLOW}🔍 Validating environment value formats...${NC}"
|
|
213
200
|
|
|
214
201
|
validate_domain_var "PAGES_CUSTOM_DOMAIN"
|
|
215
|
-
validate_domain_var "USER_WORKER_DOMAIN"
|
|
216
|
-
validate_domain_var "DATA_WORKER_DOMAIN"
|
|
217
|
-
validate_domain_var "AUDIT_WORKER_DOMAIN"
|
|
218
|
-
validate_domain_var "IMAGES_WORKER_DOMAIN"
|
|
219
|
-
validate_domain_var "PDF_WORKER_DOMAIN"
|
|
220
202
|
|
|
221
203
|
if ! [[ "$KV_STORE_ID" =~ ^([0-9a-fA-F]{32}|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$ ]]; then
|
|
222
204
|
echo -e "${RED}❌ Error: KV_STORE_ID must be a 32-character hex namespace ID (or UUID format)${NC}"
|
|
@@ -313,7 +295,7 @@ validate_generated_configs() {
|
|
|
313
295
|
assert_contains_literal "app/config/firebase.ts" "$MEASUREMENT_ID" "MEASUREMENT_ID missing in app/config/firebase.ts"
|
|
314
296
|
|
|
315
297
|
local placeholder_pattern
|
|
316
|
-
placeholder_pattern="(\"(ACCOUNT_ID|PAGES_PROJECT_NAME|PAGES_CUSTOM_DOMAIN|USER_WORKER_NAME|DATA_WORKER_NAME|AUDIT_WORKER_NAME|IMAGES_WORKER_NAME|PDF_WORKER_NAME|
|
|
298
|
+
placeholder_pattern="(\"(ACCOUNT_ID|PAGES_PROJECT_NAME|PAGES_CUSTOM_DOMAIN|USER_WORKER_NAME|DATA_WORKER_NAME|AUDIT_WORKER_NAME|IMAGES_WORKER_NAME|PDF_WORKER_NAME|DATA_BUCKET_NAME|AUDIT_BUCKET_NAME|FILES_BUCKET_NAME|KV_STORE_ID|MANIFEST_SIGNING_KEY_ID|MANIFEST_SIGNING_PUBLIC_KEY|EXPORT_ENCRYPTION_KEY_ID|EXPORT_ENCRYPTION_PUBLIC_KEY|YOUR_FIREBASE_API_KEY|YOUR_FIREBASE_AUTH_DOMAIN|YOUR_FIREBASE_PROJECT_ID|YOUR_FIREBASE_STORAGE_BUCKET|YOUR_FIREBASE_MESSAGING_SENDER_ID|YOUR_FIREBASE_APP_ID|YOUR_FIREBASE_MEASUREMENT_ID)\")"
|
|
317
299
|
|
|
318
300
|
local files_to_scan=(
|
|
319
301
|
"wrangler.toml"
|
|
@@ -151,16 +151,7 @@ if [ -z "$PAGES_PROJECT_NAME" ] || is_placeholder "$PAGES_PROJECT_NAME"; then
|
|
|
151
151
|
fi
|
|
152
152
|
|
|
153
153
|
required_pages_secrets=(
|
|
154
|
-
"AUDIT_WORKER_DOMAIN"
|
|
155
|
-
"DATA_WORKER_DOMAIN"
|
|
156
|
-
"IMAGES_API_TOKEN"
|
|
157
|
-
"IMAGES_WORKER_DOMAIN"
|
|
158
|
-
"PDF_WORKER_AUTH"
|
|
159
|
-
"PDF_WORKER_DOMAIN"
|
|
160
154
|
"PROJECT_ID"
|
|
161
|
-
"R2_KEY_SECRET"
|
|
162
|
-
"USER_DB_AUTH"
|
|
163
|
-
"USER_WORKER_DOMAIN"
|
|
164
155
|
)
|
|
165
156
|
|
|
166
157
|
echo -e "${YELLOW}🔍 Validating required Pages secret values...${NC}"
|
|
@@ -97,8 +97,6 @@ load_required_admin_service_credentials
|
|
|
97
97
|
|
|
98
98
|
build_user_worker_secret_list() {
|
|
99
99
|
local secrets=(
|
|
100
|
-
"USER_DB_AUTH"
|
|
101
|
-
"R2_KEY_SECRET"
|
|
102
100
|
"PROJECT_ID"
|
|
103
101
|
"FIREBASE_SERVICE_ACCOUNT_EMAIL"
|
|
104
102
|
"FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY"
|
|
@@ -149,9 +147,7 @@ build_user_worker_secret_list() {
|
|
|
149
147
|
}
|
|
150
148
|
|
|
151
149
|
build_audit_worker_secret_list() {
|
|
152
|
-
local secrets=(
|
|
153
|
-
"R2_KEY_SECRET"
|
|
154
|
-
)
|
|
150
|
+
local secrets=()
|
|
155
151
|
|
|
156
152
|
if [ -n "${DATA_AT_REST_ENCRYPTION_ENABLED:-}" ]; then
|
|
157
153
|
secrets+=("DATA_AT_REST_ENCRYPTION_ENABLED")
|
|
@@ -230,7 +226,6 @@ set_worker_secrets() {
|
|
|
230
226
|
|
|
231
227
|
build_data_worker_secret_list() {
|
|
232
228
|
local secrets=(
|
|
233
|
-
"R2_KEY_SECRET"
|
|
234
229
|
"MANIFEST_SIGNING_PRIVATE_KEY"
|
|
235
230
|
"MANIFEST_SIGNING_KEY_ID"
|
|
236
231
|
"EXPORT_ENCRYPTION_PRIVATE_KEY"
|
|
@@ -274,7 +269,6 @@ build_data_worker_secret_list() {
|
|
|
274
269
|
|
|
275
270
|
build_images_worker_secret_list() {
|
|
276
271
|
local secrets=(
|
|
277
|
-
"IMAGES_API_TOKEN"
|
|
278
272
|
"DATA_AT_REST_ENCRYPTION_PUBLIC_KEY"
|
|
279
273
|
"DATA_AT_REST_ENCRYPTION_KEY_ID"
|
|
280
274
|
"IMAGE_SIGNED_URL_SECRET"
|
|
@@ -365,7 +359,7 @@ fi
|
|
|
365
359
|
|
|
366
360
|
# PDF Worker
|
|
367
361
|
if ! set_worker_secrets "PDF Worker" "workers/pdf-worker" \
|
|
368
|
-
"
|
|
362
|
+
"ACCOUNT_ID" "BROWSER_API_TOKEN"; then
|
|
369
363
|
echo -e "${YELLOW}⚠️ Skipping PDF Worker (not configured)${NC}"
|
|
370
364
|
fi
|
|
371
365
|
|
package/tsconfig.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "audit-worker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"deploy": "wrangler deploy",
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
"start": "wrangler dev"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"wrangler": "^4.84.
|
|
11
|
+
"wrangler": "^4.84.1"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { hasValidHeader } from './config';
|
|
2
1
|
import { handleAuditRequest } from './handlers/audit-routes';
|
|
3
2
|
import type { CreateResponse, Env } from './types';
|
|
4
3
|
|
|
@@ -9,10 +8,6 @@ const createWorkerResponse: CreateResponse = (data, status: number = 200): Respo
|
|
|
9
8
|
|
|
10
9
|
export default {
|
|
11
10
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
12
|
-
if (!hasValidHeader(request, env)) {
|
|
13
|
-
return createWorkerResponse({ error: 'Forbidden' }, 403);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
try {
|
|
17
12
|
const url = new URL(request.url);
|
|
18
13
|
const pathname = url.pathname;
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
import type { Env } from './types';
|
|
2
|
-
|
|
3
1
|
export const DATA_AT_REST_ENCRYPTION_ALGORITHM = 'RSA-OAEP-AES-256-GCM';
|
|
4
|
-
export const DATA_AT_REST_ENCRYPTION_VERSION = '1.0';
|
|
5
|
-
|
|
6
|
-
export const hasValidHeader = (request: Request, env: Env): boolean =>
|
|
7
|
-
request.headers.get('X-Custom-Auth-Key') === env.R2_KEY_SECRET;
|
|
2
|
+
export const DATA_AT_REST_ENCRYPTION_VERSION = '1.0';
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
// Required secrets: R2_KEY_SECRET
|
|
3
|
-
// Optional data-at-rest secrets/vars:
|
|
4
|
-
// - DATA_AT_REST_ENCRYPTION_ENABLED=true
|
|
5
|
-
// - DATA_AT_REST_ENCRYPTION_PRIVATE_KEY (required for decrypting encrypted records)
|
|
6
|
-
// - DATA_AT_REST_ENCRYPTION_PUBLIC_KEY and DATA_AT_REST_ENCRYPTION_KEY_ID (required when encrypt-on-write is enabled)
|
|
7
2
|
"name": "AUDIT_WORKER_NAME",
|
|
8
3
|
"account_id": "ACCOUNT_ID",
|
|
9
4
|
"main": "src/audit-worker.ts",
|
|
10
|
-
"
|
|
5
|
+
"workers_dev": false,
|
|
6
|
+
"compatibility_date": "2026-04-21",
|
|
11
7
|
"compatibility_flags": [
|
|
12
8
|
"nodejs_compat"
|
|
13
9
|
],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-worker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"deploy": "wrangler deploy",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"start": "wrangler dev"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"@cloudflare/vitest-pool-workers": "^0.14.
|
|
12
|
-
"wrangler": "^4.84.
|
|
11
|
+
"@cloudflare/vitest-pool-workers": "^0.14.9",
|
|
12
|
+
"wrangler": "^4.84.1"
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import type { Env } from './types';
|
|
2
|
-
|
|
3
1
|
export const SIGN_MANIFEST_PATH = '/api/forensic/sign-manifest';
|
|
4
2
|
export const SIGN_CONFIRMATION_PATH = '/api/forensic/sign-confirmation';
|
|
5
3
|
export const SIGN_AUDIT_EXPORT_PATH = '/api/forensic/sign-audit-export';
|
|
6
4
|
export const DECRYPT_EXPORT_PATH = '/api/forensic/decrypt-export';
|
|
7
5
|
export const DATA_AT_REST_ENCRYPTION_ALGORITHM = 'RSA-OAEP-AES-256-GCM';
|
|
8
|
-
export const DATA_AT_REST_ENCRYPTION_VERSION = '1.0';
|
|
9
|
-
|
|
10
|
-
export const hasValidHeader = (request: Request, env: Env): boolean =>
|
|
11
|
-
request.headers.get('X-Custom-Auth-Key') === env.R2_KEY_SECRET;
|
|
6
|
+
export const DATA_AT_REST_ENCRYPTION_VERSION = '1.0';
|
|
@@ -2,8 +2,7 @@ import {
|
|
|
2
2
|
DECRYPT_EXPORT_PATH,
|
|
3
3
|
SIGN_AUDIT_EXPORT_PATH,
|
|
4
4
|
SIGN_CONFIRMATION_PATH,
|
|
5
|
-
SIGN_MANIFEST_PATH
|
|
6
|
-
hasValidHeader
|
|
5
|
+
SIGN_MANIFEST_PATH
|
|
7
6
|
} from './config';
|
|
8
7
|
import { handleDecryptExport } from './handlers/decrypt-export';
|
|
9
8
|
import {
|
|
@@ -21,10 +20,6 @@ const createWorkerResponse: CreateResponse = (data, status: number = 200): Respo
|
|
|
21
20
|
|
|
22
21
|
export default {
|
|
23
22
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
24
|
-
if (!hasValidHeader(request, env)) {
|
|
25
|
-
return createWorkerResponse({ error: 'Forbidden' }, 403);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
23
|
try {
|
|
29
24
|
const url = new URL(request.url);
|
|
30
25
|
const pathname = url.pathname;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
// Required secrets: R2_KEY_SECRET, MANIFEST_SIGNING_PRIVATE_KEY, MANIFEST_SIGNING_KEY_ID, EXPORT_ENCRYPTION_PRIVATE_KEY, EXPORT_ENCRYPTION_KEY_ID
|
|
3
|
-
// - DATA_AT_REST_ENCRYPTION_PRIVATE_KEY (required for decrypting encrypted records)
|
|
4
|
-
// - DATA_AT_REST_ENCRYPTION_PUBLIC_KEY and DATA_AT_REST_ENCRYPTION_KEY_ID (required when encrypt-on-write is enabled)
|
|
5
2
|
"name": "DATA_WORKER_NAME",
|
|
6
3
|
"account_id": "ACCOUNT_ID",
|
|
7
4
|
"main": "src/data-worker.ts",
|
|
8
|
-
"
|
|
5
|
+
"workers_dev": false,
|
|
6
|
+
"compatibility_date": "2026-04-21",
|
|
9
7
|
"compatibility_flags": [
|
|
10
8
|
"nodejs_compat"
|
|
11
9
|
],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "image-worker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"deploy": "wrangler deploy",
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
"start": "wrangler dev"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"wrangler": "^4.84.
|
|
11
|
+
"wrangler": "^4.84.1"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { hasValidToken } from '../auth';
|
|
2
1
|
import type { CreateImageWorkerResponse, Env } from '../types';
|
|
3
2
|
import { parseFileId } from '../utils/path-utils';
|
|
4
3
|
|
|
@@ -7,10 +6,6 @@ export async function handleImageDelete(
|
|
|
7
6
|
env: Env,
|
|
8
7
|
createJsonResponse: CreateImageWorkerResponse
|
|
9
8
|
): Promise<Response> {
|
|
10
|
-
if (!hasValidToken(request, env)) {
|
|
11
|
-
return createJsonResponse({ error: 'Unauthorized' }, 403);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
9
|
const fileId = parseFileId(new URL(request.url).pathname);
|
|
15
10
|
if (!fileId) {
|
|
16
11
|
return createJsonResponse({ error: 'Image ID is required' }, 400);
|