@striae-org/striae 4.0.0 → 4.0.2

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.
Files changed (99) hide show
  1. package/.env.example +1 -0
  2. package/README.md +1 -1
  3. package/app/components/actions/case-export/data-processing.ts +1 -1
  4. package/app/components/actions/case-export/download-handlers.ts +5 -4
  5. package/app/components/actions/case-export/metadata-helpers.ts +1 -1
  6. package/app/components/actions/case-import/confirmation-import.ts +1 -1
  7. package/app/components/actions/case-import/image-operations.ts +1 -1
  8. package/app/components/actions/case-import/orchestrator.ts +1 -1
  9. package/app/components/actions/case-import/storage-operations.ts +3 -3
  10. package/app/components/actions/case-import/validation.ts +3 -4
  11. package/app/components/actions/case-import/zip-processing.ts +1 -1
  12. package/app/components/actions/case-manage.ts +3 -5
  13. package/app/components/actions/confirm-export.ts +4 -5
  14. package/app/components/actions/generate-pdf.ts +1 -1
  15. package/app/components/actions/image-manage.ts +4 -4
  16. package/app/components/actions/notes-manage.ts +1 -1
  17. package/app/components/actions/signout.tsx +1 -1
  18. package/app/components/audit/user-audit-viewer.tsx +1 -1
  19. package/app/components/auth/auth-provider.tsx +1 -1
  20. package/app/components/auth/mfa-verification.tsx +1 -1
  21. package/app/components/button/button.tsx +1 -1
  22. package/app/components/canvas/box-annotations/box-annotations.tsx +1 -1
  23. package/app/components/canvas/confirmation/confirmation.tsx +1 -1
  24. package/app/components/icon/icon.tsx +1 -1
  25. package/app/components/public-signing-key-modal/public-signing-key-modal.tsx +1 -1
  26. package/app/components/sidebar/case-export/case-export.tsx +1 -1
  27. package/app/components/sidebar/cases/case-sidebar.tsx +3 -3
  28. package/app/components/sidebar/cases/cases-modal.tsx +1 -1
  29. package/app/components/sidebar/files/files-modal.tsx +1 -1
  30. package/app/components/sidebar/notes/notes-sidebar.tsx +1 -1
  31. package/app/components/sidebar/sidebar-container.tsx +2 -17
  32. package/app/components/sidebar/sidebar.module.css +0 -29
  33. package/app/components/theme-provider/theme-provider.tsx +1 -1
  34. package/app/components/theme-provider/theme.ts +1 -1
  35. package/app/components/user/delete-account.tsx +1 -1
  36. package/app/components/user/manage-profile.tsx +1 -1
  37. package/app/components/user/mfa-phone-update.tsx +1 -1
  38. package/app/root.tsx +18 -51
  39. package/app/routes/auth/emailActionHandler.tsx +2 -3
  40. package/app/routes/auth/emailVerification.tsx +2 -2
  41. package/app/routes/auth/login.tsx +7 -9
  42. package/app/routes/auth/passwordReset.tsx +2 -2
  43. package/app/routes/striae/striae.tsx +2 -2
  44. package/app/services/audit/audit-export-signing.ts +2 -2
  45. package/app/services/audit/audit-export.service.ts +1 -2
  46. package/app/services/audit/audit.service.ts +1 -1
  47. package/app/services/firebase/index.ts +1 -1
  48. package/app/utils/api/index.ts +4 -0
  49. package/app/utils/auth/index.ts +5 -0
  50. package/app/utils/common/index.ts +3 -0
  51. package/app/utils/{version.ts → common/version.ts} +1 -1
  52. package/app/utils/{data-operations.ts → data/data-operations.ts} +4 -4
  53. package/app/utils/data/index.ts +2 -0
  54. package/app/utils/{permissions.ts → data/permissions.ts} +1 -1
  55. package/app/utils/forensics/index.ts +5 -0
  56. package/app/utils/ui/index.ts +2 -0
  57. package/functions/api/image/[[path]].ts +17 -1
  58. package/package.json +18 -20
  59. package/public/.well-known/keybase.txt +56 -0
  60. package/public/.well-known/security.txt +3 -4
  61. package/scripts/deploy-config.sh +178 -142
  62. package/scripts/deploy-worker-secrets.sh +1 -2
  63. package/worker-configuration.d.ts +7491 -11363
  64. package/workers/audit-worker/worker-configuration.d.ts +11323 -7448
  65. package/workers/audit-worker/wrangler.jsonc.example +1 -1
  66. package/workers/data-worker/worker-configuration.d.ts +11323 -7448
  67. package/workers/data-worker/wrangler.jsonc.example +1 -1
  68. package/workers/image-worker/src/image-worker.example.ts +10 -2
  69. package/workers/image-worker/worker-configuration.d.ts +11322 -7447
  70. package/workers/image-worker/wrangler.jsonc.example +1 -1
  71. package/workers/keys-worker/src/keys.ts +2 -1
  72. package/workers/keys-worker/worker-configuration.d.ts +11322 -7447
  73. package/workers/keys-worker/wrangler.jsonc.example +1 -1
  74. package/workers/pdf-worker/src/pdf-worker.example.ts +144 -39
  75. package/workers/pdf-worker/worker-configuration.d.ts +11323 -7448
  76. package/workers/pdf-worker/wrangler.jsonc.example +1 -1
  77. package/workers/user-worker/worker-configuration.d.ts +11323 -7448
  78. package/workers/user-worker/wrangler.jsonc.example +1 -1
  79. package/wrangler.toml.example +1 -1
  80. package/public/.well-known/publickey.info@striae.org.asc +0 -17
  81. package/public/oin-badge.png +0 -0
  82. /package/app/utils/{data-api-client.ts → api/data-api-client.ts} +0 -0
  83. /package/app/utils/{image-api-client.ts → api/image-api-client.ts} +0 -0
  84. /package/app/utils/{pdf-api-client.ts → api/pdf-api-client.ts} +0 -0
  85. /package/app/utils/{user-api-client.ts → api/user-api-client.ts} +0 -0
  86. /package/app/utils/{auth-action-settings.ts → auth/auth-action-settings.ts} +0 -0
  87. /package/app/utils/{auth.ts → auth/auth.ts} +0 -0
  88. /package/app/utils/{mfa-phone.ts → auth/mfa-phone.ts} +0 -0
  89. /package/app/utils/{mfa.ts → auth/mfa.ts} +0 -0
  90. /package/app/utils/{password-policy.ts → auth/password-policy.ts} +0 -0
  91. /package/app/utils/{batch-operations.ts → common/batch-operations.ts} +0 -0
  92. /package/app/utils/{id-generator.ts → common/id-generator.ts} +0 -0
  93. /package/app/utils/{SHA256.ts → forensics/SHA256.ts} +0 -0
  94. /package/app/utils/{audit-export-signature.ts → forensics/audit-export-signature.ts} +0 -0
  95. /package/app/utils/{confirmation-signature.ts → forensics/confirmation-signature.ts} +0 -0
  96. /package/app/utils/{export-verification.ts → forensics/export-verification.ts} +0 -0
  97. /package/app/utils/{signature-utils.ts → forensics/signature-utils.ts} +0 -0
  98. /package/app/utils/{annotation-timestamp.ts → ui/annotation-timestamp.ts} +0 -0
  99. /package/app/utils/{style.ts → ui/style.ts} +0 -0
@@ -181,6 +181,40 @@ normalize_domain_value() {
181
181
  printf '%s' "$domain"
182
182
  }
183
183
 
184
+ normalize_worker_label_value() {
185
+ local label="$1"
186
+
187
+ label=$(normalize_domain_value "$label")
188
+ label="${label#.}"
189
+ label="${label%.}"
190
+ label=$(printf '%s' "$label" | tr '[:upper:]' '[:lower:]')
191
+
192
+ printf '%s' "$label"
193
+ }
194
+
195
+ normalize_worker_subdomain_value() {
196
+ local subdomain="$1"
197
+
198
+ subdomain=$(normalize_domain_value "$subdomain")
199
+ subdomain="${subdomain#.}"
200
+ subdomain="${subdomain%.}"
201
+ subdomain=$(printf '%s' "$subdomain" | tr '[:upper:]' '[:lower:]')
202
+
203
+ printf '%s' "$subdomain"
204
+ }
205
+
206
+ is_valid_worker_label() {
207
+ local label="$1"
208
+
209
+ [[ "$label" =~ ^[a-z0-9-]+$ ]]
210
+ }
211
+
212
+ is_valid_worker_subdomain() {
213
+ local subdomain="$1"
214
+
215
+ [[ "$subdomain" =~ ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$ ]]
216
+ }
217
+
184
218
  strip_carriage_returns() {
185
219
  printf '%s' "$1" | tr -d '\r'
186
220
  }
@@ -245,54 +279,53 @@ generate_worker_subdomain_label() {
245
279
  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
246
280
  }
247
281
 
248
- worker_name_var_for_domain_var() {
249
- case "$1" in
250
- KEYS_WORKER_DOMAIN)
251
- printf '%s' "KEYS_WORKER_NAME"
252
- ;;
253
- USER_WORKER_DOMAIN)
254
- printf '%s' "USER_WORKER_NAME"
255
- ;;
256
- DATA_WORKER_DOMAIN)
257
- printf '%s' "DATA_WORKER_NAME"
258
- ;;
259
- AUDIT_WORKER_DOMAIN)
260
- printf '%s' "AUDIT_WORKER_NAME"
261
- ;;
262
- IMAGES_WORKER_DOMAIN)
263
- printf '%s' "IMAGES_WORKER_NAME"
264
- ;;
265
- PDF_WORKER_DOMAIN)
266
- printf '%s' "PDF_WORKER_NAME"
267
- ;;
268
- *)
269
- printf '%s' ""
270
- ;;
271
- esac
272
- }
273
-
274
282
  compose_worker_domain() {
275
283
  local worker_name=$1
276
284
  local worker_subdomain=$2
277
285
 
278
- worker_name=$(normalize_domain_value "$worker_name")
279
- worker_subdomain=$(normalize_domain_value "$worker_subdomain")
280
- worker_name="${worker_name#.}"
281
- worker_name="${worker_name%.}"
282
- worker_subdomain="${worker_subdomain#.}"
283
- worker_subdomain="${worker_subdomain%.}"
286
+ worker_name=$(normalize_worker_label_value "$worker_name")
287
+ worker_subdomain=$(normalize_worker_subdomain_value "$worker_subdomain")
284
288
 
285
289
  if [ -z "$worker_name" ] || [ -z "$worker_subdomain" ]; then
286
290
  return 1
287
291
  fi
288
292
 
289
- if [[ "$worker_name" == *.* ]] || [[ "$worker_name" == */* ]] || [[ "$worker_subdomain" == */* ]]; then
293
+ if ! is_valid_worker_label "$worker_name" || ! is_valid_worker_subdomain "$worker_subdomain"; then
290
294
  return 1
291
295
  fi
292
296
 
293
297
  printf '%s.%s' "$worker_name" "$worker_subdomain"
294
298
  }
295
299
 
300
+ infer_worker_subdomain_from_domain() {
301
+ local worker_name=$1
302
+ local worker_domain=$2
303
+ local worker_subdomain=""
304
+
305
+ worker_name=$(normalize_worker_label_value "$worker_name")
306
+ worker_domain=$(normalize_domain_value "$worker_domain")
307
+ worker_domain=$(printf '%s' "$worker_domain" | tr '[:upper:]' '[:lower:]')
308
+
309
+ if [ -z "$worker_name" ] || [ -z "$worker_domain" ] || is_placeholder "$worker_name" || is_placeholder "$worker_domain"; then
310
+ printf '%s' ""
311
+ return 0
312
+ fi
313
+
314
+ case "$worker_domain" in
315
+ "$worker_name".*)
316
+ worker_subdomain="${worker_domain#${worker_name}.}"
317
+ worker_subdomain=$(normalize_worker_subdomain_value "$worker_subdomain")
318
+
319
+ if is_valid_worker_subdomain "$worker_subdomain"; then
320
+ printf '%s' "$worker_subdomain"
321
+ return 0
322
+ fi
323
+ ;;
324
+ esac
325
+
326
+ printf '%s' ""
327
+ }
328
+
296
329
  write_env_var() {
297
330
  local var_name=$1
298
331
  local var_value=$2
@@ -526,6 +559,7 @@ required_vars=(
526
559
  "PDF_WORKER_AUTH"
527
560
  "ACCOUNT_HASH"
528
561
  "API_TOKEN"
562
+ "BROWSER_API_TOKEN"
529
563
  "HMAC_KEY"
530
564
  "MANIFEST_SIGNING_PRIVATE_KEY"
531
565
  "MANIFEST_SIGNING_KEY_ID"
@@ -975,7 +1009,7 @@ prompt_for_secrets() {
975
1009
 
976
1010
  current_value=$(strip_carriage_returns "$current_value")
977
1011
 
978
- if [ "$var_name" = "PAGES_CUSTOM_DOMAIN" ] || [[ "$var_name" == *_WORKER_DOMAIN ]]; then
1012
+ if [ "$var_name" = "PAGES_CUSTOM_DOMAIN" ]; then
979
1013
  current_value=$(resolve_existing_domain_value "$var_name" "$current_value")
980
1014
  fi
981
1015
 
@@ -1039,107 +1073,6 @@ prompt_for_secrets() {
1039
1073
  done
1040
1074
  fi
1041
1075
  fi
1042
- elif [[ "$var_name" == *_WORKER_DOMAIN ]]; then
1043
- local worker_name_var
1044
- local worker_name_current=""
1045
- local worker_name_input=""
1046
- local worker_subdomain_input=""
1047
- local inferred_subdomain=""
1048
- local domain_choice=""
1049
- local composed_domain=""
1050
-
1051
- worker_name_var=$(worker_name_var_for_domain_var "$var_name")
1052
- worker_name_current=$(strip_carriage_returns "${!worker_name_var}")
1053
-
1054
- if [ -n "$worker_name_current" ] && ! is_placeholder "$worker_name_current" && [ -n "$current_value" ] && ! is_placeholder "$current_value"; then
1055
- case "$current_value" in
1056
- "$worker_name_current".*)
1057
- inferred_subdomain="${current_value#${worker_name_current}.}"
1058
- ;;
1059
- esac
1060
- fi
1061
-
1062
- echo -e "${BLUE}$var_name${NC}"
1063
- echo -e "${YELLOW}$description${NC}"
1064
-
1065
- while true; do
1066
- if [ "$update_env" != "true" ] && [ -n "$current_value" ] && ! is_placeholder "$current_value"; then
1067
- echo -e "${GREEN}Current value: $current_value${NC}"
1068
- read -p "Press Enter to keep current, or type 'y' to rebuild from worker-name and worker-subdomain: " domain_choice
1069
- domain_choice=$(strip_carriage_returns "$domain_choice")
1070
-
1071
- if [ -z "$domain_choice" ]; then
1072
- new_value=""
1073
- break
1074
- fi
1075
-
1076
- if [ "$domain_choice" != "y" ] && [ "$domain_choice" != "Y" ]; then
1077
- echo -e "${RED}❌ Please press Enter to keep current or type 'y' to rebuild.${NC}"
1078
- continue
1079
- fi
1080
- fi
1081
-
1082
- if [ -n "$worker_name_current" ] && ! is_placeholder "$worker_name_current"; then
1083
- read -p "Prompt: worker-name [$worker_name_current]: " worker_name_input
1084
- worker_name_input=$(strip_carriage_returns "$worker_name_input")
1085
- if [ -z "$worker_name_input" ]; then
1086
- worker_name_input="$worker_name_current"
1087
- fi
1088
- else
1089
- read -p "Prompt: worker-name: " worker_name_input
1090
- worker_name_input=$(strip_carriage_returns "$worker_name_input")
1091
- fi
1092
-
1093
- if [ -z "$worker_name_input" ] || is_placeholder "$worker_name_input"; then
1094
- echo -e "${RED}❌ worker-name is required and cannot be a placeholder.${NC}"
1095
- continue
1096
- fi
1097
-
1098
- worker_name_input=$(normalize_domain_value "$worker_name_input")
1099
- worker_name_input="${worker_name_input#.}"
1100
- worker_name_input="${worker_name_input%.}"
1101
-
1102
- if [[ "$worker_name_input" == *.* ]] || [[ "$worker_name_input" == */* ]]; then
1103
- echo -e "${RED}❌ worker-name must be a single hostname label (for example: striae-dev-data).${NC}"
1104
- continue
1105
- fi
1106
-
1107
- if [ -n "$inferred_subdomain" ]; then
1108
- read -p "Prompt: worker-subdomain [$inferred_subdomain]: " worker_subdomain_input
1109
- worker_subdomain_input=$(strip_carriage_returns "$worker_subdomain_input")
1110
- if [ -z "$worker_subdomain_input" ]; then
1111
- worker_subdomain_input="$inferred_subdomain"
1112
- fi
1113
- else
1114
- read -p "Prompt: worker-subdomain: " worker_subdomain_input
1115
- worker_subdomain_input=$(strip_carriage_returns "$worker_subdomain_input")
1116
- fi
1117
-
1118
- if [ -z "$worker_subdomain_input" ] || is_placeholder "$worker_subdomain_input"; then
1119
- echo -e "${RED}❌ worker-subdomain is required and cannot be a placeholder.${NC}"
1120
- continue
1121
- fi
1122
-
1123
- worker_subdomain_input=$(normalize_domain_value "$worker_subdomain_input")
1124
- worker_subdomain_input="${worker_subdomain_input#.}"
1125
- worker_subdomain_input="${worker_subdomain_input%.}"
1126
-
1127
- composed_domain=$(compose_worker_domain "$worker_name_input" "$worker_subdomain_input" || echo "")
1128
- if [ -z "$composed_domain" ]; then
1129
- echo -e "${RED}❌ Invalid worker-name/worker-subdomain combination.${NC}"
1130
- continue
1131
- fi
1132
-
1133
- if [ -n "$worker_name_var" ]; then
1134
- write_env_var "$worker_name_var" "$worker_name_input"
1135
- export "$worker_name_var=$worker_name_input"
1136
- worker_name_current="$worker_name_input"
1137
- fi
1138
-
1139
- new_value="$composed_domain"
1140
- echo -e "${GREEN}Resulting worker domain: $new_value${NC}"
1141
- break
1142
- done
1143
1076
  else
1144
1077
  # Normal prompt for other variables
1145
1078
  echo -e "${BLUE}$var_name${NC}"
@@ -1175,12 +1108,22 @@ prompt_for_secrets() {
1175
1108
  continue
1176
1109
  fi
1177
1110
 
1111
+ if [[ "$var_name" == *_WORKER_NAME ]]; then
1112
+ new_value=$(normalize_worker_label_value "$new_value")
1113
+
1114
+ if [ -z "$new_value" ] || ! is_valid_worker_label "$new_value"; then
1115
+ echo -e "${RED}❌ $var_name must use only lowercase letters, numbers, and dashes.${NC}"
1116
+ new_value=""
1117
+ continue
1118
+ fi
1119
+ fi
1120
+
1178
1121
  break
1179
1122
  done
1180
1123
  fi
1181
1124
 
1182
1125
  if [ -n "$new_value" ]; then
1183
- if [ "$var_name" = "PAGES_CUSTOM_DOMAIN" ] || [[ "$var_name" == *_WORKER_DOMAIN ]]; then
1126
+ if [ "$var_name" = "PAGES_CUSTOM_DOMAIN" ]; then
1184
1127
  new_value=$(normalize_domain_value "$new_value")
1185
1128
  fi
1186
1129
 
@@ -1190,6 +1133,10 @@ prompt_for_secrets() {
1190
1133
  export "$var_name=$new_value"
1191
1134
  echo -e "${GREEN}✅ $var_name updated${NC}"
1192
1135
  elif [ -n "$current_value" ]; then
1136
+ if [[ "$var_name" == *_WORKER_NAME ]]; then
1137
+ current_value=$(normalize_worker_label_value "$current_value")
1138
+ fi
1139
+
1193
1140
  # Keep values aligned with .env.example ordering and remove stale duplicates.
1194
1141
  write_env_var "$var_name" "$current_value"
1195
1142
  export "$var_name=$current_value"
@@ -1197,6 +1144,31 @@ prompt_for_secrets() {
1197
1144
  fi
1198
1145
  echo ""
1199
1146
  }
1147
+
1148
+ set_worker_domain_from_shared_subdomain() {
1149
+ local worker_name_var=$1
1150
+ local worker_domain_var=$2
1151
+ local worker_name_value="${!worker_name_var}"
1152
+ local composed_domain=""
1153
+
1154
+ worker_name_value=$(normalize_worker_label_value "$worker_name_value")
1155
+
1156
+ if [ -z "$worker_name_value" ] || ! is_valid_worker_label "$worker_name_value"; then
1157
+ echo -e "${RED}❌ $worker_name_var must use only lowercase letters, numbers, and dashes.${NC}"
1158
+ exit 1
1159
+ fi
1160
+
1161
+ composed_domain=$(compose_worker_domain "$worker_name_value" "$shared_worker_subdomain" || echo "")
1162
+
1163
+ if [ -z "$composed_domain" ]; then
1164
+ echo -e "${RED}❌ Could not build $worker_domain_var from $worker_name_var and shared worker-subdomain.${NC}"
1165
+ exit 1
1166
+ fi
1167
+
1168
+ write_env_var "$worker_domain_var" "$composed_domain"
1169
+ export "$worker_domain_var=$composed_domain"
1170
+ echo -e "${GREEN}✅ $worker_domain_var set to $composed_domain${NC}"
1171
+ }
1200
1172
 
1201
1173
  echo -e "${BLUE}📊 CLOUDFLARE CORE CONFIGURATION${NC}"
1202
1174
  echo "=================================="
@@ -1225,18 +1197,81 @@ prompt_for_secrets() {
1225
1197
 
1226
1198
  echo -e "${BLUE}🔑 WORKER NAMES & DOMAINS${NC}"
1227
1199
  echo "========================="
1200
+ echo -e "${YELLOW}Worker names are lowercased automatically and must use only letters, numbers, and dashes.${NC}"
1201
+ echo -e "${YELLOW}Enter one shared worker-subdomain as a hostname (for example: team-name.workers.dev).${NC}"
1202
+ echo -e "${YELLOW}Each worker domain is generated as {worker-name}.{worker-subdomain}.${NC}"
1203
+
1204
+ local shared_worker_subdomain=""
1205
+ local shared_worker_subdomain_default=""
1206
+ local shared_worker_subdomain_input=""
1207
+
1208
+ shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$KEYS_WORKER_NAME" "$KEYS_WORKER_DOMAIN")
1209
+ if [ -z "$shared_worker_subdomain_default" ]; then
1210
+ shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$USER_WORKER_NAME" "$USER_WORKER_DOMAIN")
1211
+ fi
1212
+ if [ -z "$shared_worker_subdomain_default" ]; then
1213
+ shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$DATA_WORKER_NAME" "$DATA_WORKER_DOMAIN")
1214
+ fi
1215
+ if [ -z "$shared_worker_subdomain_default" ]; then
1216
+ shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$AUDIT_WORKER_NAME" "$AUDIT_WORKER_DOMAIN")
1217
+ fi
1218
+ if [ -z "$shared_worker_subdomain_default" ]; then
1219
+ shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$IMAGES_WORKER_NAME" "$IMAGES_WORKER_DOMAIN")
1220
+ fi
1221
+ if [ -z "$shared_worker_subdomain_default" ]; then
1222
+ shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$PDF_WORKER_NAME" "$PDF_WORKER_DOMAIN")
1223
+ fi
1224
+
1225
+ while true; do
1226
+ echo -e "${BLUE}WORKER_SUBDOMAIN${NC}"
1227
+
1228
+ if [ "$update_env" != "true" ] && [ -n "$shared_worker_subdomain_default" ] && ! is_placeholder "$shared_worker_subdomain_default"; then
1229
+ echo -e "${GREEN}Current value: $shared_worker_subdomain_default${NC}"
1230
+ read -p "New value (or press Enter to keep current): " shared_worker_subdomain_input
1231
+ shared_worker_subdomain_input=$(strip_carriage_returns "$shared_worker_subdomain_input")
1232
+
1233
+ if [ -z "$shared_worker_subdomain_input" ]; then
1234
+ shared_worker_subdomain="$shared_worker_subdomain_default"
1235
+ else
1236
+ shared_worker_subdomain="$shared_worker_subdomain_input"
1237
+ fi
1238
+ else
1239
+ read -p "Enter shared worker-subdomain (e.g., team-name.workers.dev): " shared_worker_subdomain_input
1240
+ shared_worker_subdomain_input=$(strip_carriage_returns "$shared_worker_subdomain_input")
1241
+ shared_worker_subdomain="$shared_worker_subdomain_input"
1242
+ fi
1243
+
1244
+ if [ -z "$shared_worker_subdomain" ] || is_placeholder "$shared_worker_subdomain"; then
1245
+ echo -e "${RED}❌ shared worker-subdomain is required and cannot be a placeholder.${NC}"
1246
+ continue
1247
+ fi
1248
+
1249
+ shared_worker_subdomain=$(normalize_worker_subdomain_value "$shared_worker_subdomain")
1250
+
1251
+ if [ -z "$shared_worker_subdomain" ] || ! is_valid_worker_subdomain "$shared_worker_subdomain"; then
1252
+ echo -e "${RED}❌ shared worker-subdomain must be a valid hostname like team-name.workers.dev (letters, numbers, dashes, and dots).${NC}"
1253
+ continue
1254
+ fi
1255
+
1256
+ echo -e "${GREEN}✅ Shared worker-subdomain set to: $shared_worker_subdomain${NC}"
1257
+ echo ""
1258
+ break
1259
+ done
1260
+
1228
1261
  prompt_for_var "KEYS_WORKER_NAME" "Keys worker name"
1229
- prompt_for_var "KEYS_WORKER_DOMAIN" "Keys worker domain (format: {worker-name}.{worker-subdomain})"
1230
1262
  prompt_for_var "USER_WORKER_NAME" "User worker name"
1231
- prompt_for_var "USER_WORKER_DOMAIN" "User worker domain (format: {worker-name}.{worker-subdomain})"
1232
1263
  prompt_for_var "DATA_WORKER_NAME" "Data worker name"
1233
- prompt_for_var "DATA_WORKER_DOMAIN" "Data worker domain (format: {worker-name}.{worker-subdomain})"
1234
1264
  prompt_for_var "AUDIT_WORKER_NAME" "Audit worker name"
1235
- prompt_for_var "AUDIT_WORKER_DOMAIN" "Audit worker domain (format: {worker-name}.{worker-subdomain})"
1236
1265
  prompt_for_var "IMAGES_WORKER_NAME" "Images worker name"
1237
- prompt_for_var "IMAGES_WORKER_DOMAIN" "Images worker domain (format: {worker-name}.{worker-subdomain})"
1238
1266
  prompt_for_var "PDF_WORKER_NAME" "PDF worker name"
1239
- prompt_for_var "PDF_WORKER_DOMAIN" "PDF worker domain (format: {worker-name}.{worker-subdomain})"
1267
+
1268
+ set_worker_domain_from_shared_subdomain "KEYS_WORKER_NAME" "KEYS_WORKER_DOMAIN"
1269
+ set_worker_domain_from_shared_subdomain "USER_WORKER_NAME" "USER_WORKER_DOMAIN"
1270
+ set_worker_domain_from_shared_subdomain "DATA_WORKER_NAME" "DATA_WORKER_DOMAIN"
1271
+ set_worker_domain_from_shared_subdomain "AUDIT_WORKER_NAME" "AUDIT_WORKER_DOMAIN"
1272
+ set_worker_domain_from_shared_subdomain "IMAGES_WORKER_NAME" "IMAGES_WORKER_DOMAIN"
1273
+ set_worker_domain_from_shared_subdomain "PDF_WORKER_NAME" "PDF_WORKER_DOMAIN"
1274
+ echo ""
1240
1275
 
1241
1276
  echo -e "${BLUE}🗄️ STORAGE CONFIGURATION${NC}"
1242
1277
  echo "========================="
@@ -1250,6 +1285,7 @@ prompt_for_secrets() {
1250
1285
  prompt_for_var "PDF_WORKER_AUTH" "PDF worker authentication token (generate with: openssl rand -hex 16)"
1251
1286
  prompt_for_var "ACCOUNT_HASH" "Cloudflare Images Account Hash"
1252
1287
  prompt_for_var "API_TOKEN" "Cloudflare Images API token (for Images Worker)"
1288
+ prompt_for_var "BROWSER_API_TOKEN" "Cloudflare Browser Rendering API token (for PDF Worker)"
1253
1289
  prompt_for_var "HMAC_KEY" "Cloudflare Images HMAC signing key"
1254
1290
 
1255
1291
  configure_manifest_signing_credentials
@@ -197,10 +197,9 @@ if ! set_worker_secrets "Images Worker" "workers/image-worker" \
197
197
  echo -e "${YELLOW}⚠️ Skipping Images Worker (not configured)${NC}"
198
198
  fi
199
199
 
200
- # PDF Worker (no secrets needed)
201
200
  # PDF Worker
202
201
  if ! set_worker_secrets "PDF Worker" "workers/pdf-worker" \
203
- "PDF_WORKER_AUTH"; then
202
+ "PDF_WORKER_AUTH" "ACCOUNT_ID" "BROWSER_API_TOKEN"; then
204
203
  echo -e "${YELLOW}⚠️ Skipping PDF Worker (not configured)${NC}"
205
204
  fi
206
205