@striae-org/striae 5.3.1 → 5.4.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 +3 -0
- package/app/components/actions/generate-pdf.ts +22 -0
- package/app/components/auth/auth.module.css +531 -0
- package/app/components/auth/mfa-enrollment.tsx +132 -79
- package/app/components/auth/mfa-totp-enrollment.tsx +231 -0
- package/app/components/auth/mfa-verification.tsx +155 -33
- package/app/components/{sidebar/cases/cases-modal.tsx → navbar/case-modals/all-cases-modal.tsx} +4 -4
- package/app/components/navbar/case-modals/archive-case-modal.tsx +9 -10
- package/app/components/navbar/case-modals/case-modal-shared.module.css +88 -0
- package/app/components/navbar/case-modals/delete-case-modal.tsx +9 -10
- package/app/components/navbar/case-modals/export-case-modal.tsx +9 -10
- package/app/components/navbar/case-modals/export-confirmations-modal.tsx +9 -10
- package/app/components/navbar/case-modals/open-case-modal.tsx +4 -4
- package/app/components/navbar/case-modals/rename-case-modal.tsx +9 -10
- package/app/components/navbar/navbar.tsx +1 -1
- package/app/components/sidebar/files/delete-files-modal.tsx +3 -3
- package/app/components/sidebar/files/files-modal.module.css +29 -0
- package/app/components/sidebar/notes/{class-details-fields.tsx → class-details/class-details-fields.tsx} +1 -1
- package/app/components/sidebar/notes/{class-details-modal.tsx → class-details/class-details-modal.tsx} +1 -1
- package/app/components/sidebar/notes/{class-details-sections.tsx → class-details/class-details-sections.tsx} +1 -1
- package/app/components/sidebar/notes/notes-editor-form.tsx +2 -2
- package/app/components/sidebar/notes/notes-editor-modal.tsx +6 -6
- package/app/components/sidebar/notes/notes.module.css +52 -0
- package/app/components/toolbar/toolbar-color-selector.tsx +8 -8
- package/app/components/toolbar/toolbar.module.css +181 -2
- package/app/components/user/delete-account.tsx +7 -7
- package/app/components/user/inactivity-warning.tsx +6 -6
- package/app/components/user/manage-profile.tsx +18 -1
- package/app/components/user/mfa-enrolled-factors.tsx +117 -0
- package/app/components/user/mfa-phone-update.tsx +8 -4
- package/app/components/user/mfa-totp-section.tsx +446 -0
- package/app/components/user/user.module.css +665 -0
- package/app/routes/striae/striae.tsx +1 -1
- package/app/services/audit/audit.service.ts +1 -1
- package/app/services/audit/builders/audit-event-builders-user-security.ts +4 -2
- package/app/services/firebase/errors.ts +2 -0
- package/app/utils/auth/mfa.ts +35 -1
- package/functions/api/image/[[path]].ts +19 -3
- package/package.json +16 -21
- package/scripts/deploy-all.sh +166 -0
- package/scripts/deploy-config/modules/env-utils.sh +322 -0
- package/scripts/deploy-config/modules/keys.sh +404 -0
- package/scripts/deploy-config/modules/prompt.sh +375 -0
- package/scripts/deploy-config/modules/scaffolding.sh +310 -0
- package/scripts/deploy-config/modules/validation.sh +354 -0
- package/scripts/deploy-config.sh +236 -0
- package/scripts/deploy-pages-secrets.sh +231 -0
- package/scripts/deploy-pages.sh +34 -0
- package/scripts/deploy-primershear-emails.sh +167 -0
- package/scripts/deploy-worker-secrets.sh +385 -0
- package/scripts/dev.cjs +23 -0
- package/scripts/enable-totp-mfa.mjs +57 -0
- package/scripts/install-workers.sh +87 -0
- package/scripts/run-eslint.cjs +43 -0
- package/scripts/update-compatibility-dates.cjs +124 -0
- package/scripts/update-markdown-versions.cjs +43 -0
- package/workers/audit-worker/package.json +1 -1
- package/workers/audit-worker/wrangler.jsonc.example +1 -1
- package/workers/data-worker/package.json +1 -1
- package/workers/data-worker/wrangler.jsonc.example +1 -1
- package/workers/image-worker/package.json +1 -1
- package/workers/image-worker/src/image-worker.example.ts +36 -2
- package/workers/image-worker/wrangler.jsonc.example +1 -1
- package/workers/pdf-worker/package.json +1 -1
- package/workers/pdf-worker/wrangler.jsonc.example +1 -1
- package/workers/user-worker/package.json +1 -1
- package/workers/user-worker/wrangler.jsonc.example +1 -1
- package/wrangler.toml.example +1 -1
- package/app/components/auth/mfa-enrollment.module.css +0 -276
- package/app/components/auth/mfa-verification.module.css +0 -259
- package/app/components/navbar/case-modals/archive-case-modal.module.css +0 -34
- package/app/components/navbar/case-modals/delete-case-modal.module.css +0 -9
- package/app/components/navbar/case-modals/export-case-modal.module.css +0 -27
- package/app/components/navbar/case-modals/export-confirmations-modal.module.css +0 -24
- package/app/components/navbar/case-modals/open-case-modal.module.css +0 -82
- package/app/components/navbar/case-modals/rename-case-modal.module.css +0 -9
- package/app/components/sidebar/files/delete-files-modal.module.css +0 -26
- package/app/components/sidebar/notes/notes-editor-modal.module.css +0 -49
- package/app/components/toolbar/toolbar-color-selector.module.css +0 -171
- package/app/components/user/delete-account.module.css +0 -277
- package/app/components/user/inactivity-warning.module.css +0 -148
- package/app/components/user/manage-profile.module.css +0 -192
- package/app/routes/auth/login.module.css +0 -523
- package/app/routes/auth/login.tsx +0 -705
- /package/app/components/{sidebar → navbar}/case-import/case-import.module.css +0 -0
- /package/app/components/{sidebar → navbar}/case-import/case-import.tsx +0 -0
- /package/app/components/{sidebar → navbar}/case-import/components/CasePreviewSection.tsx +0 -0
- /package/app/components/{sidebar → navbar}/case-import/components/ConfirmationDialog.tsx +0 -0
- /package/app/components/{sidebar → navbar}/case-import/components/ConfirmationPreviewSection.tsx +0 -0
- /package/app/components/{sidebar → navbar}/case-import/components/ExistingCaseSection.tsx +0 -0
- /package/app/components/{sidebar → navbar}/case-import/components/FileSelector.tsx +0 -0
- /package/app/components/{sidebar → navbar}/case-import/components/ProgressSection.tsx +0 -0
- /package/app/components/{sidebar → navbar}/case-import/hooks/useFilePreview.ts +0 -0
- /package/app/components/{sidebar → navbar}/case-import/hooks/useImportExecution.ts +0 -0
- /package/app/components/{sidebar → navbar}/case-import/hooks/useImportState.ts +0 -0
- /package/app/components/{sidebar → navbar}/case-import/index.ts +0 -0
- /package/app/components/{sidebar → navbar}/case-import/utils/file-validation.ts +0 -0
- /package/app/components/{sidebar/cases/cases-modal.module.css → navbar/case-modals/all-cases-modal.module.css} +0 -0
- /package/app/components/sidebar/notes/{class-details-shared.ts → class-details/class-details-shared.ts} +0 -0
- /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}"
|