@striae-org/striae 5.3.2 → 5.4.1

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 (112) hide show
  1. package/app/components/auth/auth.module.css +531 -0
  2. package/app/components/auth/mfa-enrollment.tsx +132 -79
  3. package/app/components/auth/mfa-totp-enrollment.tsx +231 -0
  4. package/app/components/auth/mfa-verification.tsx +162 -33
  5. package/app/components/{sidebar/cases/cases-modal.tsx → navbar/case-modals/all-cases-modal.tsx} +4 -4
  6. package/app/components/navbar/case-modals/archive-case-modal.tsx +9 -10
  7. package/app/components/navbar/case-modals/case-modal-shared.module.css +88 -0
  8. package/app/components/navbar/case-modals/delete-case-modal.tsx +9 -10
  9. package/app/components/navbar/case-modals/export-case-modal.tsx +9 -10
  10. package/app/components/navbar/case-modals/export-confirmations-modal.tsx +9 -10
  11. package/app/components/navbar/case-modals/open-case-modal.tsx +4 -4
  12. package/app/components/navbar/case-modals/rename-case-modal.tsx +9 -10
  13. package/app/components/navbar/navbar.tsx +1 -1
  14. package/app/components/sidebar/files/delete-files-modal.tsx +3 -3
  15. package/app/components/sidebar/files/files-modal.module.css +29 -0
  16. package/app/components/sidebar/notes/{class-details-fields.tsx → class-details/class-details-fields.tsx} +1 -1
  17. package/app/components/sidebar/notes/{class-details-modal.tsx → class-details/class-details-modal.tsx} +1 -1
  18. package/app/components/sidebar/notes/{class-details-sections.tsx → class-details/class-details-sections.tsx} +1 -1
  19. package/app/components/sidebar/notes/notes-editor-form.tsx +2 -2
  20. package/app/components/sidebar/notes/notes-editor-modal.tsx +6 -6
  21. package/app/components/sidebar/notes/notes.module.css +52 -0
  22. package/app/components/toolbar/toolbar-color-selector.tsx +8 -8
  23. package/app/components/toolbar/toolbar.module.css +181 -2
  24. package/app/components/user/delete-account.tsx +7 -7
  25. package/app/components/user/inactivity-warning.tsx +6 -6
  26. package/app/components/user/manage-profile.tsx +18 -1
  27. package/app/components/user/mfa-enrolled-factors.tsx +117 -0
  28. package/app/components/user/mfa-phone-update.tsx +8 -4
  29. package/app/components/user/mfa-totp-section.tsx +446 -0
  30. package/app/components/user/user.module.css +665 -0
  31. package/app/routes/striae/striae.tsx +1 -1
  32. package/app/services/audit/audit.service.ts +1 -1
  33. package/app/services/audit/builders/audit-event-builders-user-security.ts +4 -2
  34. package/app/services/firebase/errors.ts +2 -0
  35. package/app/utils/auth/mfa.ts +35 -1
  36. package/package.json +23 -28
  37. package/scripts/deploy-all.sh +166 -0
  38. package/scripts/deploy-config/modules/env-utils.sh +322 -0
  39. package/scripts/deploy-config/modules/keys.sh +404 -0
  40. package/scripts/deploy-config/modules/prompt.sh +375 -0
  41. package/scripts/deploy-config/modules/scaffolding.sh +310 -0
  42. package/scripts/deploy-config/modules/validation.sh +354 -0
  43. package/scripts/deploy-config.sh +236 -0
  44. package/scripts/deploy-pages-secrets.sh +231 -0
  45. package/scripts/deploy-pages.sh +34 -0
  46. package/scripts/deploy-primershear-emails.sh +167 -0
  47. package/scripts/deploy-worker-secrets.sh +385 -0
  48. package/scripts/dev.cjs +23 -0
  49. package/scripts/enable-totp-mfa.mjs +57 -0
  50. package/scripts/install-workers.sh +87 -0
  51. package/scripts/run-eslint.cjs +43 -0
  52. package/scripts/unenroll-totp-mfa.mjs +82 -0
  53. package/scripts/update-compatibility-dates.cjs +124 -0
  54. package/scripts/update-markdown-versions.cjs +43 -0
  55. package/workers/audit-worker/.editorconfig +12 -0
  56. package/workers/audit-worker/.prettierrc +6 -0
  57. package/workers/audit-worker/package.json +1 -1
  58. package/workers/audit-worker/wrangler.jsonc.example +1 -1
  59. package/workers/data-worker/.editorconfig +12 -0
  60. package/workers/data-worker/.prettierrc +6 -0
  61. package/workers/data-worker/package.json +1 -1
  62. package/workers/data-worker/wrangler.jsonc.example +1 -1
  63. package/workers/image-worker/.editorconfig +12 -0
  64. package/workers/image-worker/.prettierrc +6 -0
  65. package/workers/image-worker/package.json +1 -1
  66. package/workers/image-worker/wrangler.jsonc.example +1 -1
  67. package/workers/pdf-worker/.editorconfig +12 -0
  68. package/workers/pdf-worker/.prettierrc +6 -0
  69. package/workers/pdf-worker/package.json +1 -1
  70. package/workers/pdf-worker/wrangler.jsonc.example +1 -1
  71. package/workers/user-worker/.editorconfig +12 -0
  72. package/workers/user-worker/.prettierrc +6 -0
  73. package/workers/user-worker/package.json +1 -1
  74. package/workers/user-worker/wrangler.jsonc.example +1 -1
  75. package/wrangler.toml.example +1 -1
  76. package/app/components/auth/mfa-enrollment.module.css +0 -276
  77. package/app/components/auth/mfa-verification.module.css +0 -259
  78. package/app/components/navbar/case-modals/archive-case-modal.module.css +0 -34
  79. package/app/components/navbar/case-modals/delete-case-modal.module.css +0 -9
  80. package/app/components/navbar/case-modals/export-case-modal.module.css +0 -27
  81. package/app/components/navbar/case-modals/export-confirmations-modal.module.css +0 -24
  82. package/app/components/navbar/case-modals/open-case-modal.module.css +0 -82
  83. package/app/components/navbar/case-modals/rename-case-modal.module.css +0 -9
  84. package/app/components/sidebar/files/delete-files-modal.module.css +0 -26
  85. package/app/components/sidebar/notes/notes-editor-modal.module.css +0 -49
  86. package/app/components/toolbar/toolbar-color-selector.module.css +0 -171
  87. package/app/components/user/delete-account.module.css +0 -277
  88. package/app/components/user/inactivity-warning.module.css +0 -148
  89. package/app/components/user/manage-profile.module.css +0 -192
  90. package/app/routes/auth/login.module.css +0 -523
  91. package/app/routes/auth/login.tsx +0 -705
  92. package/workers/audit-worker/worker-configuration.d.ts +0 -7448
  93. package/workers/data-worker/worker-configuration.d.ts +0 -7448
  94. package/workers/image-worker/worker-configuration.d.ts +0 -7448
  95. package/workers/pdf-worker/worker-configuration.d.ts +0 -7447
  96. package/workers/user-worker/worker-configuration.d.ts +0 -7450
  97. /package/app/components/{sidebar → navbar}/case-import/case-import.module.css +0 -0
  98. /package/app/components/{sidebar → navbar}/case-import/case-import.tsx +0 -0
  99. /package/app/components/{sidebar → navbar}/case-import/components/CasePreviewSection.tsx +0 -0
  100. /package/app/components/{sidebar → navbar}/case-import/components/ConfirmationDialog.tsx +0 -0
  101. /package/app/components/{sidebar → navbar}/case-import/components/ConfirmationPreviewSection.tsx +0 -0
  102. /package/app/components/{sidebar → navbar}/case-import/components/ExistingCaseSection.tsx +0 -0
  103. /package/app/components/{sidebar → navbar}/case-import/components/FileSelector.tsx +0 -0
  104. /package/app/components/{sidebar → navbar}/case-import/components/ProgressSection.tsx +0 -0
  105. /package/app/components/{sidebar → navbar}/case-import/hooks/useFilePreview.ts +0 -0
  106. /package/app/components/{sidebar → navbar}/case-import/hooks/useImportExecution.ts +0 -0
  107. /package/app/components/{sidebar → navbar}/case-import/hooks/useImportState.ts +0 -0
  108. /package/app/components/{sidebar → navbar}/case-import/index.ts +0 -0
  109. /package/app/components/{sidebar → navbar}/case-import/utils/file-validation.ts +0 -0
  110. /package/app/components/{sidebar/cases/cases-modal.module.css → navbar/case-modals/all-cases-modal.module.css} +0 -0
  111. /package/app/components/sidebar/notes/{class-details-shared.ts → class-details/class-details-shared.ts} +0 -0
  112. /package/app/components/sidebar/notes/{use-class-details-state.ts → class-details/use-class-details-state.ts} +0 -0
@@ -0,0 +1,236 @@
1
+ #!/bin/bash
2
+
3
+ # ===================================
4
+ # STRIAE CONFIGURATION SETUP SCRIPT
5
+ # ===================================
6
+ # This script sets up all configuration files and replaces placeholders
7
+ # Run this BEFORE installing worker dependencies to avoid wrangler validation errors
8
+
9
+ set -e
10
+ set -o pipefail
11
+
12
+ # Colors for output
13
+ RED='\033[0;31m'
14
+ GREEN='\033[0;32m'
15
+ YELLOW='\033[1;33m'
16
+ BLUE='\033[0;34m'
17
+ NC='\033[0m' # No Color
18
+
19
+ echo -e "${BLUE}⚙️ Striae Configuration Setup Script${NC}"
20
+ echo "====================================="
21
+
22
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
24
+ cd "$PROJECT_ROOT"
25
+
26
+ trap 'echo -e "\n${RED}❌ deploy-config.sh failed near line ${LINENO}${NC}"' ERR
27
+
28
+ update_env=false
29
+ show_help=false
30
+ validate_only=false
31
+ force_rotate_keys=false
32
+ for arg in "$@"; do
33
+ case "$arg" in
34
+ -h|--help)
35
+ show_help=true
36
+ ;;
37
+ --update-env)
38
+ update_env=true
39
+ ;;
40
+ --validate-only)
41
+ validate_only=true
42
+ ;;
43
+ --force-rotate-keys)
44
+ force_rotate_keys=true
45
+ ;;
46
+ *)
47
+ echo -e "${RED}❌ Unknown option: $arg${NC}"
48
+ echo "Use --help to see supported options."
49
+ exit 1
50
+ ;;
51
+ esac
52
+ done
53
+
54
+ if [ "$update_env" = "true" ] && [ "$validate_only" = "true" ]; then
55
+ echo -e "${RED}❌ --update-env and --validate-only cannot be used together${NC}"
56
+ exit 1
57
+ fi
58
+
59
+ if [ "$force_rotate_keys" = "true" ] && [ "$validate_only" = "true" ]; then
60
+ echo -e "${RED}❌ --force-rotate-keys and --validate-only cannot be used together${NC}"
61
+ exit 1
62
+ fi
63
+
64
+ if [ "$show_help" = "true" ]; then
65
+ echo "Usage: bash ./scripts/deploy-config.sh [--update-env] [--validate-only] [--force-rotate-keys]"
66
+ echo ""
67
+ echo "Options:"
68
+ echo " --update-env Reset .env from .env.example and overwrite configs"
69
+ echo " --validate-only Validate current .env and generated config files without modifying them"
70
+ echo " --force-rotate-keys Force regeneration of all encryption/signing key pairs without prompts"
71
+ echo " -h, --help Show this help message"
72
+ exit 0
73
+ fi
74
+
75
+ if [ "$update_env" = "true" ]; then
76
+ echo -e "${YELLOW}⚠️ Update-env mode: overwriting configs and resetting .env values from template${NC}"
77
+ fi
78
+
79
+ if [ "$force_rotate_keys" = "true" ]; then
80
+ echo -e "${YELLOW}⚠️ Force-rotate-keys mode: all encryption/signing key pairs will be regenerated without prompts${NC}"
81
+ fi
82
+
83
+ require_command() {
84
+ local cmd=$1
85
+ if ! command -v "$cmd" > /dev/null 2>&1; then
86
+ echo -e "${RED}❌ Error: required command '$cmd' is not installed or not in PATH${NC}"
87
+ exit 1
88
+ fi
89
+ }
90
+
91
+ require_command node
92
+ require_command sed
93
+ require_command awk
94
+ require_command grep
95
+
96
+ is_placeholder() {
97
+ local value="$1"
98
+ local normalized
99
+
100
+ normalized=$(printf '%s' "$value" | tr -d '\r' | tr '[:upper:]' '[:lower:]')
101
+ normalized=$(printf '%s' "$normalized" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
102
+ normalized=${normalized#\"}
103
+ normalized=${normalized%\"}
104
+
105
+ if [ -z "$normalized" ]; then
106
+ return 1
107
+ fi
108
+
109
+ [[ "$normalized" =~ ^your_[a-z0-9_]+_here$ || \
110
+ "$normalized" =~ ^your-[a-z0-9-]+-here$ || \
111
+ "$normalized" == "placeholder" || \
112
+ "$normalized" == "changeme" || \
113
+ "$normalized" == "replace_me" || \
114
+ "$normalized" == "replace-me" ]]
115
+ }
116
+
117
+ # Check if .env file exists
118
+ env_created_from_example=false
119
+ preserved_domain_env_file=""
120
+
121
+ if [ -f ".env" ]; then
122
+ preserved_domain_env_file=".env"
123
+ fi
124
+
125
+ if [ "$update_env" = "true" ]; then
126
+ if [ -f ".env" ]; then
127
+ cp .env .env.backup
128
+ preserved_domain_env_file=".env.backup"
129
+ echo -e "${GREEN}📄 Existing .env backed up to .env.backup${NC}"
130
+ fi
131
+
132
+ if [ -f ".env.example" ]; then
133
+ cp ".env.example" ".env"
134
+ echo -e "${GREEN}✅ .env file reset from .env.example${NC}"
135
+ env_created_from_example=true
136
+ else
137
+ echo -e "${RED}❌ Error: .env.example file not found!${NC}"
138
+ exit 1
139
+ fi
140
+ elif [ ! -f ".env" ]; then
141
+ if [ "$validate_only" = "true" ]; then
142
+ echo -e "${RED}❌ Error: .env file not found. --validate-only does not create files.${NC}"
143
+ echo -e "${YELLOW}Run deploy-config without --validate-only first to generate and populate .env.${NC}"
144
+ exit 1
145
+ fi
146
+
147
+ echo -e "${YELLOW}📄 .env file not found, copying from .env.example...${NC}"
148
+ if [ -f ".env.example" ]; then
149
+ cp ".env.example" ".env"
150
+ echo -e "${GREEN}✅ .env file created from .env.example${NC}"
151
+ env_created_from_example=true
152
+ else
153
+ echo -e "${RED}❌ Error: Neither .env nor .env.example file found!${NC}"
154
+ echo "Please create a .env.example file or provide a .env file."
155
+ exit 1
156
+ fi
157
+ fi
158
+
159
+ # Source the .env file
160
+ echo -e "${YELLOW}📖 Loading environment variables from .env...${NC}"
161
+ source .env
162
+
163
+ DEPLOY_CONFIG_MODULES_DIR="$SCRIPT_DIR/deploy-config/modules"
164
+ DEPLOY_CONFIG_ENV_UTILS_MODULE="$DEPLOY_CONFIG_MODULES_DIR/env-utils.sh"
165
+
166
+ if [ ! -f "$DEPLOY_CONFIG_ENV_UTILS_MODULE" ]; then
167
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_ENV_UTILS_MODULE${NC}"
168
+ exit 1
169
+ fi
170
+
171
+ source "$DEPLOY_CONFIG_ENV_UTILS_MODULE"
172
+
173
+ DEPLOY_CONFIG_KEYS_MODULE="$DEPLOY_CONFIG_MODULES_DIR/keys.sh"
174
+ DEPLOY_CONFIG_VALIDATION_MODULE="$DEPLOY_CONFIG_MODULES_DIR/validation.sh"
175
+ DEPLOY_CONFIG_SCAFFOLDING_MODULE="$DEPLOY_CONFIG_MODULES_DIR/scaffolding.sh"
176
+ DEPLOY_CONFIG_PROMPT_MODULE="$DEPLOY_CONFIG_MODULES_DIR/prompt.sh"
177
+
178
+ if [ ! -f "$DEPLOY_CONFIG_KEYS_MODULE" ]; then
179
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_KEYS_MODULE${NC}"
180
+ exit 1
181
+ fi
182
+
183
+ if [ ! -f "$DEPLOY_CONFIG_VALIDATION_MODULE" ]; then
184
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_VALIDATION_MODULE${NC}"
185
+ exit 1
186
+ fi
187
+
188
+ if [ ! -f "$DEPLOY_CONFIG_SCAFFOLDING_MODULE" ]; then
189
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_SCAFFOLDING_MODULE${NC}"
190
+ exit 1
191
+ fi
192
+
193
+ if [ ! -f "$DEPLOY_CONFIG_PROMPT_MODULE" ]; then
194
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_PROMPT_MODULE${NC}"
195
+ exit 1
196
+ fi
197
+
198
+ source "$DEPLOY_CONFIG_KEYS_MODULE"
199
+ source "$DEPLOY_CONFIG_VALIDATION_MODULE"
200
+ source "$DEPLOY_CONFIG_SCAFFOLDING_MODULE"
201
+ source "$DEPLOY_CONFIG_PROMPT_MODULE"
202
+
203
+ if [ "$validate_only" = "true" ]; then
204
+ echo -e "\n${BLUE}🧪 Validate-only mode enabled${NC}"
205
+ run_validation_checkpoint
206
+ echo -e "\n${GREEN}🎉 Configuration validation completed successfully!${NC}"
207
+ exit 0
208
+ fi
209
+
210
+
211
+ # Copy example configuration files
212
+ copy_example_configs
213
+
214
+ # Load required Firebase admin service credentials from app/config/admin-service.json
215
+ load_admin_service_credentials
216
+
217
+ # Always prompt for secrets to ensure configuration
218
+ prompt_for_secrets
219
+
220
+ # Validate after secrets have been configured
221
+ validate_required_vars
222
+
223
+
224
+ # Update wrangler configurations
225
+ update_wrangler_configs
226
+
227
+ # Validate generated files and values after replacements
228
+ run_validation_checkpoint
229
+
230
+ echo -e "\n${GREEN}🎉 Configuration setup completed!${NC}"
231
+ echo -e "${BLUE}📝 Next Steps:${NC}"
232
+ echo " 1. Install worker dependencies"
233
+ echo " 2. Deploy workers"
234
+ echo " 3. Deploy worker secrets"
235
+ echo " 4. Deploy pages"
236
+ echo -e "\n${GREEN}✨ Ready for deployment!${NC}"
@@ -0,0 +1,231 @@
1
+ #!/bin/bash
2
+
3
+ # ======================================
4
+ # STRIAE PAGES SECRETS DEPLOYMENT SCRIPT
5
+ # ======================================
6
+ # This script deploys required secrets to Cloudflare Pages environments.
7
+
8
+ set -e
9
+ set -o pipefail
10
+
11
+ # Colors for output
12
+ RED='\033[0;31m'
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ BLUE='\033[0;34m'
16
+ NC='\033[0m' # No Color
17
+
18
+ echo -e "${BLUE}🔐 Striae Pages Secrets Deployment Script${NC}"
19
+ echo "=========================================="
20
+
21
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
23
+ cd "$PROJECT_ROOT"
24
+
25
+ trap 'echo -e "\n${RED}❌ deploy-pages-secrets.sh failed near line ${LINENO}${NC}"' ERR
26
+
27
+ show_help=false
28
+ deploy_production=true
29
+ deploy_preview=true
30
+
31
+ for arg in "$@"; do
32
+ case "$arg" in
33
+ -h|--help)
34
+ show_help=true
35
+ ;;
36
+ --production-only)
37
+ deploy_production=true
38
+ deploy_preview=false
39
+ ;;
40
+ --preview-only)
41
+ deploy_production=false
42
+ deploy_preview=true
43
+ ;;
44
+ *)
45
+ echo -e "${RED}❌ Unknown option: $arg${NC}"
46
+ echo "Use --help to see supported options."
47
+ exit 1
48
+ ;;
49
+ esac
50
+ done
51
+
52
+ if [ "$show_help" = "true" ]; then
53
+ echo "Usage: bash ./scripts/deploy-pages-secrets.sh [--production-only|--preview-only]"
54
+ echo ""
55
+ echo "Options:"
56
+ echo " --production-only Deploy secrets only to the production Pages environment"
57
+ echo " --preview-only Deploy secrets only to the preview Pages environment"
58
+ echo " -h, --help Show this help message"
59
+ exit 0
60
+ fi
61
+
62
+ if [ "$deploy_production" != "true" ] && [ "$deploy_preview" != "true" ]; then
63
+ echo -e "${RED}❌ No target environment selected${NC}"
64
+ exit 1
65
+ fi
66
+
67
+ require_command() {
68
+ local cmd=$1
69
+ if ! command -v "$cmd" > /dev/null 2>&1; then
70
+ echo -e "${RED}❌ Error: required command '$cmd' is not installed or not in PATH${NC}"
71
+ exit 1
72
+ fi
73
+ }
74
+
75
+ strip_carriage_returns() {
76
+ printf '%s' "$1" | tr -d '\r'
77
+ }
78
+
79
+ is_placeholder() {
80
+ local value="$1"
81
+ local normalized
82
+
83
+ normalized=$(echo "$value" | tr '[:upper:]' '[:lower:]')
84
+
85
+ if [ -z "$normalized" ]; then
86
+ return 0
87
+ fi
88
+
89
+ [[ "$normalized" == your_*_here ]]
90
+ }
91
+
92
+ load_required_project_id() {
93
+ local admin_service_path="app/config/admin-service.json"
94
+ local service_project_id
95
+
96
+ if [ ! -f "$admin_service_path" ]; then
97
+ echo -e "${RED}❌ Error: Required Firebase admin service file not found: $admin_service_path${NC}"
98
+ echo -e "${YELLOW} Create app/config/admin-service.json before deploying Pages secrets.${NC}"
99
+ exit 1
100
+ fi
101
+
102
+ if ! service_project_id=$(node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(data.project_id || '');" "$admin_service_path"); then
103
+ echo -e "${RED}❌ Error: Could not parse project_id from $admin_service_path${NC}"
104
+ exit 1
105
+ fi
106
+
107
+ service_project_id=$(strip_carriage_returns "$service_project_id")
108
+
109
+ if [ -z "$service_project_id" ] || is_placeholder "$service_project_id"; then
110
+ echo -e "${RED}❌ Error: project_id in $admin_service_path is missing or placeholder${NC}"
111
+ exit 1
112
+ fi
113
+
114
+ PROJECT_ID="$service_project_id"
115
+ export PROJECT_ID
116
+
117
+ echo -e "${GREEN}✅ Loaded PROJECT_ID from $admin_service_path${NC}"
118
+ }
119
+
120
+ get_required_value() {
121
+ local var_name=$1
122
+ local value="${!var_name}"
123
+
124
+ value=$(strip_carriage_returns "$value")
125
+
126
+ if [ -z "$value" ] || is_placeholder "$value"; then
127
+ echo -e "${RED}❌ Error: required value for $var_name is missing or placeholder${NC}" >&2
128
+ exit 1
129
+ fi
130
+
131
+ printf '%s' "$value"
132
+ }
133
+
134
+ get_optional_value() {
135
+ local var_name=$1
136
+ local value="${!var_name}"
137
+
138
+ value=$(strip_carriage_returns "$value")
139
+
140
+ if [ -z "$value" ] || is_placeholder "$value"; then
141
+ printf ''
142
+ return 0
143
+ fi
144
+
145
+ printf '%s' "$value"
146
+ }
147
+
148
+ set_pages_secret() {
149
+ local secret_name=$1
150
+ local secret_value=$2
151
+ local pages_env=$3
152
+
153
+ echo -e "${YELLOW} Setting $secret_name for $pages_env...${NC}"
154
+
155
+ if [ "$pages_env" = "production" ]; then
156
+ printf '%s' "$secret_value" | wrangler pages secret put "$secret_name" --project-name "$PAGES_PROJECT_NAME"
157
+ return 0
158
+ fi
159
+
160
+ printf '%s' "$secret_value" | wrangler pages secret put "$secret_name" --project-name "$PAGES_PROJECT_NAME" --env "$pages_env"
161
+ }
162
+
163
+ deploy_pages_environment_secrets() {
164
+ local pages_env=$1
165
+ local secret
166
+ local secret_value
167
+
168
+ echo -e "\n${BLUE}🔧 Deploying Pages secrets to $pages_env...${NC}"
169
+
170
+ for secret in "${required_pages_secrets[@]}"; do
171
+ secret_value=$(get_required_value "$secret")
172
+ set_pages_secret "$secret" "$secret_value" "$pages_env"
173
+ done
174
+
175
+ local optional_primershear_emails
176
+ optional_primershear_emails=$(get_optional_value "PRIMERSHEAR_EMAILS")
177
+ if [ -n "$optional_primershear_emails" ]; then
178
+ set_pages_secret "PRIMERSHEAR_EMAILS" "$optional_primershear_emails" "$pages_env"
179
+ fi
180
+
181
+ echo -e "${GREEN}✅ Pages secrets deployed to $pages_env${NC}"
182
+ }
183
+
184
+ require_command wrangler
185
+ require_command node
186
+
187
+ if [ ! -f ".env" ]; then
188
+ echo -e "${RED}❌ Error: .env file not found${NC}"
189
+ echo -e "${YELLOW} Run deploy-config first to generate and populate .env.${NC}"
190
+ exit 1
191
+ fi
192
+
193
+ echo -e "${YELLOW}📖 Loading environment variables from .env...${NC}"
194
+ source .env
195
+
196
+ load_required_project_id
197
+
198
+ PAGES_PROJECT_NAME=$(strip_carriage_returns "$PAGES_PROJECT_NAME")
199
+ if [ -z "$PAGES_PROJECT_NAME" ] || is_placeholder "$PAGES_PROJECT_NAME"; then
200
+ echo -e "${RED}❌ Error: PAGES_PROJECT_NAME is missing or placeholder in .env${NC}"
201
+ exit 1
202
+ fi
203
+
204
+ required_pages_secrets=(
205
+ "AUDIT_WORKER_DOMAIN"
206
+ "DATA_WORKER_DOMAIN"
207
+ "IMAGES_API_TOKEN"
208
+ "IMAGES_WORKER_DOMAIN"
209
+ "PDF_WORKER_AUTH"
210
+ "PDF_WORKER_DOMAIN"
211
+ "PROJECT_ID"
212
+ "R2_KEY_SECRET"
213
+ "USER_DB_AUTH"
214
+ "USER_WORKER_DOMAIN"
215
+ )
216
+
217
+ echo -e "${YELLOW}🔍 Validating required Pages secret values...${NC}"
218
+ for secret in "${required_pages_secrets[@]}"; do
219
+ get_required_value "$secret" > /dev/null
220
+ done
221
+ echo -e "${GREEN}✅ Required Pages secret values found${NC}"
222
+
223
+ if [ "$deploy_production" = "true" ]; then
224
+ deploy_pages_environment_secrets "production"
225
+ fi
226
+
227
+ if [ "$deploy_preview" = "true" ]; then
228
+ deploy_pages_environment_secrets "preview"
229
+ fi
230
+
231
+ echo -e "\n${GREEN}🎉 Pages secrets deployment completed!${NC}"
@@ -0,0 +1,34 @@
1
+ #!/bin/bash
2
+
3
+ # ======================================
4
+ # STRIAE PAGES DEPLOYMENT SCRIPT
5
+ # ======================================
6
+ # This script deploys the Striae frontend to Cloudflare Pages
7
+
8
+ set -e
9
+
10
+ # Colors for output
11
+ RED='\033[0;31m'
12
+ GREEN='\033[0;32m'
13
+ YELLOW='\033[1;33m'
14
+ BLUE='\033[0;34m'
15
+ NC='\033[0m' # No Color
16
+
17
+ echo -e "${BLUE}📄 Striae Pages Deployment Script${NC}"
18
+ echo "=================================="
19
+
20
+ # Deploy to Cloudflare Pages (includes build step)
21
+ echo -e "${YELLOW}🚀 Building and deploying to Cloudflare Pages...${NC}"
22
+ if ! npm run deploy; then
23
+ echo -e "${RED}❌ Deployment failed!${NC}"
24
+ exit 1
25
+ fi
26
+
27
+ echo -e "${GREEN}✅ Pages deployment completed successfully${NC}"
28
+
29
+ echo -e "\n${BLUE}💡 Next Steps:${NC}"
30
+ echo " 1. Test your application"
31
+ echo " 2. Configure custom domain (optional)"
32
+ echo " 3. Verify Pages environment variables in Cloudflare dashboard"
33
+
34
+ echo -e "\n${GREEN}✨ Pages deployment complete!${NC}"
@@ -0,0 +1,167 @@
1
+ #!/bin/bash
2
+
3
+ # ============================================
4
+ # PRIMERSHEAR EMAIL LIST DEPLOYMENT SCRIPT
5
+ # ============================================
6
+ # Reads primershear.emails, updates PRIMERSHEAR_EMAILS in .env,
7
+ # then deploys that secret directly to Cloudflare Pages.
8
+ #
9
+ # Usage:
10
+ # bash ./scripts/deploy-primershear-emails.sh [--production-only|--preview-only|--env-only]
11
+ #
12
+ # Options:
13
+ # --production-only Deploy to production Pages environment only
14
+ # --preview-only Deploy to preview Pages environment only
15
+ # --env-only Update .env only; do not deploy to Cloudflare
16
+ # -h, --help Show this help message
17
+
18
+ set -e
19
+ set -o pipefail
20
+
21
+ RED='\033[0;31m'
22
+ GREEN='\033[0;32m'
23
+ YELLOW='\033[1;33m'
24
+ BLUE='\033[0;34m'
25
+ NC='\033[0m'
26
+
27
+ echo -e "${BLUE}📧 PrimerShear Email List Deployment${NC}"
28
+ echo "======================================"
29
+
30
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
31
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
32
+ cd "$PROJECT_ROOT"
33
+
34
+ trap 'echo -e "\n${RED}❌ deploy-primershear-emails.sh failed near line ${LINENO}${NC}"' ERR
35
+
36
+ # ── Argument parsing ─────────────────────────────────────────────────────────
37
+
38
+ deploy_production=true
39
+ deploy_preview=true
40
+ env_only=false
41
+
42
+ for arg in "$@"; do
43
+ case "$arg" in
44
+ -h|--help)
45
+ echo "Usage: bash ./scripts/deploy-primershear-emails.sh [--production-only|--preview-only|--env-only]"
46
+ echo ""
47
+ echo "Options:"
48
+ echo " --production-only Deploy to production Pages environment only"
49
+ echo " --preview-only Deploy to preview Pages environment only"
50
+ echo " --env-only Update .env only; do not deploy to Cloudflare"
51
+ echo " -h, --help Show this help message"
52
+ exit 0
53
+ ;;
54
+ --production-only)
55
+ deploy_production=true
56
+ deploy_preview=false
57
+ ;;
58
+ --preview-only)
59
+ deploy_production=false
60
+ deploy_preview=true
61
+ ;;
62
+ --env-only)
63
+ env_only=true
64
+ ;;
65
+ *)
66
+ echo -e "${RED}❌ Unknown option: $arg${NC}"
67
+ echo "Use --help to see supported options."
68
+ exit 1
69
+ ;;
70
+ esac
71
+ done
72
+
73
+ # ── Read emails file ──────────────────────────────────────────────────────────
74
+
75
+ EMAILS_FILE="$PROJECT_ROOT/primershear.emails"
76
+
77
+ if [ ! -f "$EMAILS_FILE" ]; then
78
+ echo -e "${RED}❌ primershear.emails not found at: $EMAILS_FILE${NC}"
79
+ echo -e "${YELLOW} Create it with one email address per line.${NC}"
80
+ exit 1
81
+ fi
82
+
83
+ # Strip comment lines and blank lines, then join with commas
84
+ # Use || true to avoid failure if paste gets no input (handles empty file gracefully)
85
+ PRIMERSHEAR_EMAILS=$(grep -v '^[[:space:]]*#' "$EMAILS_FILE" | grep -v '^[[:space:]]*$' | paste -sd ',' - || true)
86
+
87
+ if [ -z "$PRIMERSHEAR_EMAILS" ]; then
88
+ echo -e "${YELLOW}⚠️ primershear.emails contains no active email addresses.${NC}"
89
+ echo -e "${YELLOW} The secret will be set to an empty string, disabling the feature.${NC}"
90
+ fi
91
+
92
+ EMAIL_COUNT=$(echo "$PRIMERSHEAR_EMAILS" | tr ',' '\n' | grep -c '[^[:space:]]' || true)
93
+ echo -e "${GREEN}✅ Loaded $EMAIL_COUNT email address(es) from primershear.emails${NC}"
94
+
95
+ # ── Update .env ───────────────────────────────────────────────────────────────
96
+
97
+ ENV_FILE="$PROJECT_ROOT/.env"
98
+
99
+ if [ ! -f "$ENV_FILE" ]; then
100
+ echo -e "${RED}❌ .env not found. Run deploy-config first.${NC}"
101
+ exit 1
102
+ fi
103
+
104
+ # Replace the PRIMERSHEAR_EMAILS= line in .env (handles both empty and populated values)
105
+ if grep -q '^PRIMERSHEAR_EMAILS=' "$ENV_FILE"; then
106
+ # Use a temp file to avoid sed -i portability issues across macOS/Linux
107
+ local_tmp=$(mktemp)
108
+ sed "s|^PRIMERSHEAR_EMAILS=.*|PRIMERSHEAR_EMAILS=${PRIMERSHEAR_EMAILS}|" "$ENV_FILE" > "$local_tmp"
109
+ mv "$local_tmp" "$ENV_FILE"
110
+ echo -e "${GREEN}✅ Updated PRIMERSHEAR_EMAILS in .env${NC}"
111
+ else
112
+ echo "" >> "$ENV_FILE"
113
+ echo "PRIMERSHEAR_EMAILS=${PRIMERSHEAR_EMAILS}" >> "$ENV_FILE"
114
+ echo -e "${GREEN}✅ Appended PRIMERSHEAR_EMAILS to .env${NC}"
115
+ fi
116
+
117
+ if [ "$env_only" = "true" ]; then
118
+ echo -e "\n${GREEN}🎉 .env updated. Skipping Cloudflare deployment (--env-only).${NC}"
119
+ exit 0
120
+ fi
121
+
122
+ # ── Deploy to Cloudflare Pages ────────────────────────────────────────────────
123
+
124
+ if ! command -v wrangler > /dev/null 2>&1; then
125
+ echo -e "${RED}❌ wrangler is not installed or not in PATH${NC}"
126
+ exit 1
127
+ fi
128
+
129
+ source "$ENV_FILE"
130
+
131
+ PAGES_PROJECT_NAME=$(echo "$PAGES_PROJECT_NAME" | tr -d '\r')
132
+ if [ -z "$PAGES_PROJECT_NAME" ]; then
133
+ echo -e "${RED}❌ PAGES_PROJECT_NAME is missing from .env${NC}"
134
+ exit 1
135
+ fi
136
+
137
+ set_secret() {
138
+ local pages_env=$1
139
+ echo -e "${YELLOW} Setting PRIMERSHEAR_EMAILS for $pages_env...${NC}"
140
+ if [ "$pages_env" = "production" ]; then
141
+ printf '%s' "$PRIMERSHEAR_EMAILS" | wrangler pages secret put PRIMERSHEAR_EMAILS \
142
+ --project-name "$PAGES_PROJECT_NAME"
143
+ else
144
+ printf '%s' "$PRIMERSHEAR_EMAILS" | wrangler pages secret put PRIMERSHEAR_EMAILS \
145
+ --project-name "$PAGES_PROJECT_NAME" --env "$pages_env"
146
+ fi
147
+ }
148
+
149
+ if [ "$deploy_production" = "true" ]; then
150
+ set_secret "production"
151
+ echo -e "${GREEN}✅ PRIMERSHEAR_EMAILS deployed to production${NC}"
152
+ fi
153
+
154
+ if [ "$deploy_preview" = "true" ]; then
155
+ set_secret "preview"
156
+ echo -e "${GREEN}✅ PRIMERSHEAR_EMAILS deployed to preview${NC}"
157
+ fi
158
+
159
+ # Deploy Pages so the new secret takes effect immediately
160
+ echo -e "\n${YELLOW}🚀 Building and deploying Pages to activate new secret...${NC}"
161
+ if ! npm run deploy; then
162
+ echo -e "${RED}❌ Pages deployment failed${NC}"
163
+ exit 1
164
+ fi
165
+ echo -e "${GREEN}✅ Pages deployment complete${NC}"
166
+
167
+ echo -e "\n${GREEN}🎉 PrimerShear email list deployment complete!${NC}"