@striae-org/striae 3.0.4

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 (223) hide show
  1. package/.env.example +100 -0
  2. package/LICENSE +190 -0
  3. package/NOTICE +18 -0
  4. package/README.md +133 -0
  5. package/app/components/actions/case-export/core-export.ts +328 -0
  6. package/app/components/actions/case-export/data-processing.ts +167 -0
  7. package/app/components/actions/case-export/download-handlers.ts +900 -0
  8. package/app/components/actions/case-export/index.ts +41 -0
  9. package/app/components/actions/case-export/metadata-helpers.ts +107 -0
  10. package/app/components/actions/case-export/types-constants.ts +56 -0
  11. package/app/components/actions/case-export/validation-utils.ts +25 -0
  12. package/app/components/actions/case-export.ts +4 -0
  13. package/app/components/actions/case-import/annotation-import.ts +35 -0
  14. package/app/components/actions/case-import/confirmation-import.ts +363 -0
  15. package/app/components/actions/case-import/image-operations.ts +61 -0
  16. package/app/components/actions/case-import/index.ts +39 -0
  17. package/app/components/actions/case-import/orchestrator.ts +420 -0
  18. package/app/components/actions/case-import/storage-operations.ts +270 -0
  19. package/app/components/actions/case-import/validation.ts +189 -0
  20. package/app/components/actions/case-import/zip-processing.ts +413 -0
  21. package/app/components/actions/case-manage.ts +524 -0
  22. package/app/components/actions/case-review.ts +4 -0
  23. package/app/components/actions/confirm-export.ts +351 -0
  24. package/app/components/actions/generate-pdf.ts +210 -0
  25. package/app/components/actions/image-manage.ts +385 -0
  26. package/app/components/actions/notes-manage.ts +33 -0
  27. package/app/components/actions/signout.module.css +15 -0
  28. package/app/components/actions/signout.tsx +50 -0
  29. package/app/components/audit/user-audit-viewer.tsx +975 -0
  30. package/app/components/audit/user-audit.module.css +568 -0
  31. package/app/components/auth/auth-provider.tsx +78 -0
  32. package/app/components/auth/mfa-enrollment.module.css +268 -0
  33. package/app/components/auth/mfa-enrollment.tsx +398 -0
  34. package/app/components/auth/mfa-verification.module.css +251 -0
  35. package/app/components/auth/mfa-verification.tsx +295 -0
  36. package/app/components/button/button.module.css +63 -0
  37. package/app/components/button/button.tsx +46 -0
  38. package/app/components/canvas/box-annotations/box-annotations.module.css +170 -0
  39. package/app/components/canvas/box-annotations/box-annotations.tsx +634 -0
  40. package/app/components/canvas/canvas.module.css +314 -0
  41. package/app/components/canvas/canvas.tsx +449 -0
  42. package/app/components/canvas/confirmation/confirmation.module.css +187 -0
  43. package/app/components/canvas/confirmation/confirmation.tsx +214 -0
  44. package/app/components/colors/colors.module.css +59 -0
  45. package/app/components/colors/colors.tsx +68 -0
  46. package/app/components/form/base-form.tsx +21 -0
  47. package/app/components/form/form-button.tsx +28 -0
  48. package/app/components/form/form-field.tsx +53 -0
  49. package/app/components/form/form-message.tsx +17 -0
  50. package/app/components/form/form-toggle.tsx +23 -0
  51. package/app/components/form/form.module.css +427 -0
  52. package/app/components/form/index.ts +6 -0
  53. package/app/components/icon/icon.module.css +3 -0
  54. package/app/components/icon/icon.tsx +27 -0
  55. package/app/components/icon/icons.svg +102 -0
  56. package/app/components/icon/manifest.json +110 -0
  57. package/app/components/sidebar/case-export/case-export.module.css +386 -0
  58. package/app/components/sidebar/case-export/case-export.tsx +317 -0
  59. package/app/components/sidebar/case-import/case-import.module.css +626 -0
  60. package/app/components/sidebar/case-import/case-import.tsx +404 -0
  61. package/app/components/sidebar/case-import/components/CasePreviewSection.tsx +72 -0
  62. package/app/components/sidebar/case-import/components/ConfirmationDialog.tsx +72 -0
  63. package/app/components/sidebar/case-import/components/ConfirmationPreviewSection.tsx +71 -0
  64. package/app/components/sidebar/case-import/components/ExistingCaseSection.tsx +40 -0
  65. package/app/components/sidebar/case-import/components/FileSelector.tsx +161 -0
  66. package/app/components/sidebar/case-import/components/ProgressSection.tsx +46 -0
  67. package/app/components/sidebar/case-import/hooks/useFilePreview.ts +101 -0
  68. package/app/components/sidebar/case-import/hooks/useImportExecution.ts +152 -0
  69. package/app/components/sidebar/case-import/hooks/useImportState.ts +88 -0
  70. package/app/components/sidebar/case-import/index.ts +18 -0
  71. package/app/components/sidebar/case-import/utils/file-validation.ts +43 -0
  72. package/app/components/sidebar/cases/case-sidebar.tsx +827 -0
  73. package/app/components/sidebar/cases/cases-modal.module.css +166 -0
  74. package/app/components/sidebar/cases/cases-modal.tsx +201 -0
  75. package/app/components/sidebar/cases/cases.module.css +713 -0
  76. package/app/components/sidebar/files/files-modal.module.css +209 -0
  77. package/app/components/sidebar/files/files-modal.tsx +239 -0
  78. package/app/components/sidebar/hash/hash-utility.module.css +366 -0
  79. package/app/components/sidebar/hash/hash-utility.tsx +982 -0
  80. package/app/components/sidebar/notes/notes-modal.tsx +51 -0
  81. package/app/components/sidebar/notes/notes-sidebar.tsx +491 -0
  82. package/app/components/sidebar/notes/notes.module.css +360 -0
  83. package/app/components/sidebar/sidebar-container.tsx +149 -0
  84. package/app/components/sidebar/sidebar.module.css +321 -0
  85. package/app/components/sidebar/sidebar.tsx +215 -0
  86. package/app/components/sidebar/upload/image-upload-zone.module.css +123 -0
  87. package/app/components/sidebar/upload/image-upload-zone.tsx +330 -0
  88. package/app/components/theme-provider/theme-provider.tsx +131 -0
  89. package/app/components/theme-provider/theme.ts +155 -0
  90. package/app/components/toast/toast.module.css +137 -0
  91. package/app/components/toast/toast.tsx +56 -0
  92. package/app/components/toolbar/toolbar-color-selector.module.css +171 -0
  93. package/app/components/toolbar/toolbar-color-selector.tsx +129 -0
  94. package/app/components/toolbar/toolbar.module.css +42 -0
  95. package/app/components/toolbar/toolbar.tsx +167 -0
  96. package/app/components/user/delete-account.module.css +274 -0
  97. package/app/components/user/delete-account.tsx +471 -0
  98. package/app/components/user/inactivity-warning.module.css +145 -0
  99. package/app/components/user/inactivity-warning.tsx +84 -0
  100. package/app/components/user/manage-profile.module.css +190 -0
  101. package/app/components/user/manage-profile.tsx +253 -0
  102. package/app/components/user/mfa-phone-update.tsx +739 -0
  103. package/app/config-example/admin-service.json +13 -0
  104. package/app/config-example/config.json +17 -0
  105. package/app/config-example/firebase.ts +21 -0
  106. package/app/config-example/inactivity.ts +13 -0
  107. package/app/config-example/meta-config.json +6 -0
  108. package/app/contexts/auth.context.ts +12 -0
  109. package/app/entry.client.tsx +12 -0
  110. package/app/entry.server.tsx +44 -0
  111. package/app/hooks/useInactivityTimeout.ts +110 -0
  112. package/app/root.tsx +170 -0
  113. package/app/routes/_index.tsx +16 -0
  114. package/app/routes/auth/emailActionHandler.module.css +232 -0
  115. package/app/routes/auth/emailActionHandler.tsx +405 -0
  116. package/app/routes/auth/emailVerification.tsx +120 -0
  117. package/app/routes/auth/login.module.css +523 -0
  118. package/app/routes/auth/login.tsx +654 -0
  119. package/app/routes/auth/passwordReset.module.css +274 -0
  120. package/app/routes/auth/passwordReset.tsx +154 -0
  121. package/app/routes/auth/route.ts +16 -0
  122. package/app/routes/mobile-prevented/mobilePrevented.module.css +47 -0
  123. package/app/routes/mobile-prevented/mobilePrevented.tsx +26 -0
  124. package/app/routes/mobile-prevented/route.ts +14 -0
  125. package/app/routes/striae/striae.module.css +30 -0
  126. package/app/routes/striae/striae.tsx +417 -0
  127. package/app/services/audit-export.service.ts +755 -0
  128. package/app/services/audit.service.ts +1454 -0
  129. package/app/services/firebase-errors.ts +106 -0
  130. package/app/services/firebase.ts +15 -0
  131. package/app/styles/legal-pages.module.css +113 -0
  132. package/app/styles/root.module.css +146 -0
  133. package/app/tailwind.css +225 -0
  134. package/app/types/annotations.ts +45 -0
  135. package/app/types/audit.ts +301 -0
  136. package/app/types/case.ts +90 -0
  137. package/app/types/export.ts +8 -0
  138. package/app/types/file.ts +30 -0
  139. package/app/types/import.ts +107 -0
  140. package/app/types/index.ts +24 -0
  141. package/app/types/user.ts +38 -0
  142. package/app/utils/SHA256.ts +461 -0
  143. package/app/utils/annotation-timestamp.ts +25 -0
  144. package/app/utils/audit-export-signature.ts +117 -0
  145. package/app/utils/auth-action-settings.ts +48 -0
  146. package/app/utils/auth.ts +34 -0
  147. package/app/utils/batch-operations.ts +135 -0
  148. package/app/utils/confirmation-signature.ts +193 -0
  149. package/app/utils/data-operations.ts +871 -0
  150. package/app/utils/device-detection.ts +5 -0
  151. package/app/utils/html-sanitizer.ts +80 -0
  152. package/app/utils/id-generator.ts +36 -0
  153. package/app/utils/meta.ts +48 -0
  154. package/app/utils/mfa-phone.ts +97 -0
  155. package/app/utils/mfa.ts +79 -0
  156. package/app/utils/password-policy.ts +28 -0
  157. package/app/utils/permissions.ts +562 -0
  158. package/app/utils/signature-utils.ts +160 -0
  159. package/app/utils/style.ts +83 -0
  160. package/app/utils/version.ts +5 -0
  161. package/firebase.json +11 -0
  162. package/functions/[[path]].ts +10 -0
  163. package/package.json +138 -0
  164. package/postcss.config.js +6 -0
  165. package/public/.well-known/publickey.info@striae.org.asc +17 -0
  166. package/public/.well-known/security.txt +7 -0
  167. package/public/_headers +28 -0
  168. package/public/_routes.json +13 -0
  169. package/public/assets/striae.jpg +0 -0
  170. package/public/clear.jpg +0 -0
  171. package/public/favicon.ico +0 -0
  172. package/public/favicon.svg +9 -0
  173. package/public/icon-256.png +0 -0
  174. package/public/icon-512.png +0 -0
  175. package/public/logo-dark.png +0 -0
  176. package/public/manifest.json +25 -0
  177. package/public/oin-badge.png +0 -0
  178. package/public/shortcut.png +0 -0
  179. package/public/social-image.png +0 -0
  180. package/public/striae-ascii.txt +10 -0
  181. package/scripts/deploy-all.sh +100 -0
  182. package/scripts/deploy-config.sh +940 -0
  183. package/scripts/deploy-pages.sh +34 -0
  184. package/scripts/deploy-worker-secrets.sh +215 -0
  185. package/scripts/dev.cjs +23 -0
  186. package/scripts/install-workers.sh +88 -0
  187. package/scripts/run-eslint.cjs +35 -0
  188. package/scripts/update-compatibility-dates.cjs +124 -0
  189. package/scripts/update-markdown-versions.cjs +43 -0
  190. package/tailwind.config.ts +22 -0
  191. package/tsconfig.json +33 -0
  192. package/vite.config.ts +35 -0
  193. package/worker-configuration.d.ts +7490 -0
  194. package/workers/audit-worker/package.json +17 -0
  195. package/workers/audit-worker/src/audit-worker.example.ts +195 -0
  196. package/workers/audit-worker/worker-configuration.d.ts +7448 -0
  197. package/workers/audit-worker/wrangler.jsonc.example +29 -0
  198. package/workers/data-worker/package.json +17 -0
  199. package/workers/data-worker/src/data-worker.example.ts +267 -0
  200. package/workers/data-worker/src/signature-utils.ts +79 -0
  201. package/workers/data-worker/src/signing-payload-utils.ts +290 -0
  202. package/workers/data-worker/worker-configuration.d.ts +7448 -0
  203. package/workers/data-worker/wrangler.jsonc.example +30 -0
  204. package/workers/image-worker/package.json +17 -0
  205. package/workers/image-worker/src/image-worker.example.ts +180 -0
  206. package/workers/image-worker/worker-configuration.d.ts +7447 -0
  207. package/workers/image-worker/wrangler.jsonc.example +22 -0
  208. package/workers/keys-worker/package.json +17 -0
  209. package/workers/keys-worker/src/keys.example.ts +66 -0
  210. package/workers/keys-worker/src/keys.ts +66 -0
  211. package/workers/keys-worker/worker-configuration.d.ts +7447 -0
  212. package/workers/keys-worker/wrangler.jsonc.example +22 -0
  213. package/workers/pdf-worker/package.json +17 -0
  214. package/workers/pdf-worker/src/format-striae.ts +534 -0
  215. package/workers/pdf-worker/src/pdf-worker.example.ts +119 -0
  216. package/workers/pdf-worker/src/report-types.ts +69 -0
  217. package/workers/pdf-worker/worker-configuration.d.ts +7448 -0
  218. package/workers/pdf-worker/wrangler.jsonc.example +26 -0
  219. package/workers/user-worker/package.json +17 -0
  220. package/workers/user-worker/src/user-worker.example.ts +636 -0
  221. package/workers/user-worker/worker-configuration.d.ts +7448 -0
  222. package/workers/user-worker/wrangler.jsonc.example +29 -0
  223. package/wrangler.toml.example +8 -0
@@ -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. Deploy Pages secrets: npm run deploy-pages:secrets"
31
+ echo " 2. Configure custom domain (optional)"
32
+ echo " 3. Test your application"
33
+
34
+ echo -e "\n${GREEN}✨ Pages deployment complete!${NC}"
@@ -0,0 +1,215 @@
1
+ #!/bin/bash
2
+
3
+ # ======================================
4
+ # STRIAE WORKER SECRETS DEPLOYMENT SCRIPT
5
+ # ======================================
6
+ # This script deploys environment variables/secrets to Cloudflare Workers
7
+ # Run this AFTER workers are deployed to avoid deployment errors
8
+
9
+ set -e
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 Worker Secrets Deployment Script${NC}"
19
+ echo "=========================================="
20
+
21
+ # Check if .env file exists
22
+ if [ ! -f ".env" ]; then
23
+ echo -e "${RED}❌ Error: .env file not found!${NC}"
24
+ echo "Please copy .env.example to .env and fill in your values."
25
+ exit 1
26
+ fi
27
+
28
+ # Source the .env file
29
+ echo -e "${YELLOW}📖 Loading environment variables from .env...${NC}"
30
+ source .env
31
+
32
+ is_admin_service_placeholder() {
33
+ local value="$1"
34
+ local normalized=$(echo "$value" | tr '[:upper:]' '[:lower:]')
35
+
36
+ [[ -z "$normalized" || "$normalized" == your-* || "$normalized" == *"your_private_key"* ]]
37
+ }
38
+
39
+ load_required_admin_service_credentials() {
40
+ local admin_service_path="app/config/admin-service.json"
41
+
42
+ if [ ! -f "$admin_service_path" ]; then
43
+ echo -e "${RED}❌ Error: Required Firebase admin service file not found: $admin_service_path${NC}"
44
+ echo -e "${YELLOW} Create app/config/admin-service.json before deploying worker secrets.${NC}"
45
+ exit 1
46
+ fi
47
+
48
+ local service_project_id
49
+ local service_client_email
50
+ local service_private_key
51
+
52
+ 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
53
+ echo -e "${RED}❌ Error: Could not parse project_id from $admin_service_path${NC}"
54
+ exit 1
55
+ fi
56
+
57
+ if ! service_client_email=$(node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(data.client_email || '');" "$admin_service_path"); then
58
+ echo -e "${RED}❌ Error: Could not parse client_email from $admin_service_path${NC}"
59
+ exit 1
60
+ fi
61
+
62
+ if ! service_private_key=$(node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(data.private_key || '');" "$admin_service_path"); then
63
+ echo -e "${RED}❌ Error: Could not parse private_key from $admin_service_path${NC}"
64
+ exit 1
65
+ fi
66
+
67
+ local normalized_private_key="${service_private_key//$'\r'/}"
68
+ normalized_private_key="${normalized_private_key//$'\n'/\\n}"
69
+
70
+ if is_admin_service_placeholder "$service_project_id"; then
71
+ echo -e "${RED}❌ Error: project_id in $admin_service_path is missing or placeholder${NC}"
72
+ exit 1
73
+ fi
74
+
75
+ if is_admin_service_placeholder "$service_client_email" || [[ "$service_client_email" != *".gserviceaccount.com"* ]]; then
76
+ echo -e "${RED}❌ Error: client_email in $admin_service_path is invalid${NC}"
77
+ exit 1
78
+ fi
79
+
80
+ if is_admin_service_placeholder "$normalized_private_key" || [[ "$normalized_private_key" != *"-----BEGIN PRIVATE KEY-----"* ]] || [[ "$normalized_private_key" != *"-----END PRIVATE KEY-----"* ]]; then
81
+ echo -e "${RED}❌ Error: private_key in $admin_service_path is invalid${NC}"
82
+ exit 1
83
+ fi
84
+
85
+ PROJECT_ID="$service_project_id"
86
+ FIREBASE_SERVICE_ACCOUNT_EMAIL="$service_client_email"
87
+ FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY="$normalized_private_key"
88
+
89
+ export PROJECT_ID
90
+ export FIREBASE_SERVICE_ACCOUNT_EMAIL
91
+ export FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY
92
+
93
+ echo -e "${GREEN}✅ Loaded Firebase service account credentials from $admin_service_path${NC}"
94
+ }
95
+
96
+ load_required_admin_service_credentials
97
+
98
+ # Function to set worker secrets
99
+ set_worker_secrets() {
100
+ local worker_name=$1
101
+ local worker_path=$2
102
+ shift 2
103
+ local secrets=("$@")
104
+
105
+ echo -e "\n${BLUE}🔧 Setting secrets for $worker_name...${NC}"
106
+
107
+ # Check if worker has a wrangler configuration file
108
+ if [ ! -f "$worker_path/wrangler.jsonc" ] && [ ! -f "$worker_path/wrangler.toml" ]; then
109
+ echo -e "${RED}❌ Error: No wrangler configuration found for $worker_name${NC}"
110
+ echo -e "${YELLOW} Please copy wrangler.jsonc.example to wrangler.jsonc and configure it first.${NC}"
111
+ return 1
112
+ fi
113
+
114
+ # Change to worker directory
115
+ pushd "$worker_path" > /dev/null
116
+
117
+ # Get the worker name from the configuration file
118
+ local config_worker_name
119
+ if [ -f "wrangler.jsonc" ]; then
120
+ config_worker_name=$(grep -o '"name"[[:space:]]*:[[:space:]]*"[^"]*"' wrangler.jsonc | sed 's/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
121
+ elif [ -f "wrangler.toml" ]; then
122
+ config_worker_name=$(grep '^name[[:space:]]*=' wrangler.toml | sed 's/.*=[[:space:]]*["\x27]\([^"\x27]*\)["\x27].*/\1/')
123
+ fi
124
+
125
+ if [ -z "$config_worker_name" ]; then
126
+ echo -e "${RED}❌ Error: Could not determine worker name from configuration${NC}"
127
+ popd > /dev/null
128
+ return 1
129
+ fi
130
+
131
+ echo -e "${YELLOW} Using worker name: $config_worker_name${NC}"
132
+
133
+ for secret in "${secrets[@]}"; do
134
+ echo -e "${YELLOW} Setting $secret...${NC}"
135
+ if ! echo "${!secret}" | wrangler secret put "$secret" --name "$config_worker_name"; then
136
+ echo -e "${RED}❌ Failed to set $secret for $worker_name${NC}"
137
+ popd > /dev/null
138
+ return 1
139
+ fi
140
+ done
141
+
142
+ echo -e "${GREEN}✅ $worker_name secrets configured${NC}"
143
+ popd > /dev/null
144
+ }
145
+
146
+ # Deploy secrets to each worker
147
+ echo -e "\n${BLUE}🔐 Deploying secrets to workers...${NC}"
148
+
149
+ # Check if workers are configured
150
+ echo -e "${YELLOW}🔍 Checking worker configurations...${NC}"
151
+ workers_configured=0
152
+ total_workers=6
153
+
154
+ for worker_dir in workers/*/; do
155
+ if [ -f "$worker_dir/wrangler.jsonc" ] || [ -f "$worker_dir/wrangler.toml" ]; then
156
+ workers_configured=$((workers_configured + 1))
157
+ fi
158
+ done
159
+
160
+ if [ $workers_configured -eq 0 ]; then
161
+ echo -e "${RED}❌ No workers are configured!${NC}"
162
+ echo -e "${YELLOW} Please copy wrangler.jsonc.example to wrangler.jsonc in each worker directory and configure them.${NC}"
163
+ echo -e "${YELLOW} Then run this script again.${NC}"
164
+ exit 1
165
+ elif [ $workers_configured -lt $total_workers ]; then
166
+ echo -e "${YELLOW}⚠️ Warning: Only $workers_configured of $total_workers workers are configured.${NC}"
167
+ echo -e "${YELLOW} Some workers may not have their secrets deployed.${NC}"
168
+ fi
169
+
170
+ # Audit Worker
171
+ if ! set_worker_secrets "Audit Worker" "workers/audit-worker" \
172
+ "R2_KEY_SECRET"; then
173
+ echo -e "${YELLOW}⚠️ Skipping Audit Worker (not configured)${NC}"
174
+ fi
175
+
176
+ # Keys Worker
177
+ if ! set_worker_secrets "Keys Worker" "workers/keys-worker" \
178
+ "KEYS_AUTH" "USER_DB_AUTH" "R2_KEY_SECRET" "ACCOUNT_HASH" "IMAGES_API_TOKEN"; then
179
+ echo -e "${YELLOW}⚠️ Skipping Keys Worker (not configured)${NC}"
180
+ fi
181
+
182
+ # User Worker
183
+ if ! set_worker_secrets "User Worker" "workers/user-worker" \
184
+ "USER_DB_AUTH" "R2_KEY_SECRET" "IMAGES_API_TOKEN" "PROJECT_ID" "FIREBASE_SERVICE_ACCOUNT_EMAIL" "FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY"; then
185
+ echo -e "${YELLOW}⚠️ Skipping User Worker (not configured)${NC}"
186
+ fi
187
+
188
+ # Data Worker
189
+ if ! set_worker_secrets "Data Worker" "workers/data-worker" \
190
+ "R2_KEY_SECRET" "MANIFEST_SIGNING_PRIVATE_KEY" "MANIFEST_SIGNING_KEY_ID"; then
191
+ echo -e "${YELLOW}⚠️ Skipping Data Worker (not configured)${NC}"
192
+ fi
193
+
194
+ # Images Worker
195
+ if ! set_worker_secrets "Images Worker" "workers/image-worker" \
196
+ "ACCOUNT_ID" "API_TOKEN" "HMAC_KEY"; then
197
+ echo -e "${YELLOW}⚠️ Skipping Images Worker (not configured)${NC}"
198
+ fi
199
+
200
+ # PDF Worker (no secrets needed)
201
+ echo -e "\n${BLUE}📄 PDF Worker: No environment variables needed${NC}"
202
+
203
+ echo -e "\n${GREEN}🎉 Worker secrets deployment completed!${NC}"
204
+
205
+ echo -e "\n${YELLOW}⚠️ WORKER CONFIGURATION REMINDERS:${NC}"
206
+ echo " - Copy wrangler.jsonc.example to wrangler.jsonc in each worker directory"
207
+ echo " - Configure KV namespace ID in workers/user-worker/wrangler.jsonc"
208
+ echo " - Configure R2 bucket name in workers/data-worker/wrangler.jsonc"
209
+ echo " - Configure R2 bucket name in workers/audit-worker/wrangler.jsonc"
210
+ echo " - Update ACCOUNT_ID and custom domains in all worker configurations"
211
+
212
+ echo -e "\n${BLUE}📝 For manual deployment, use these commands:${NC}"
213
+ echo " cd workers/[worker-name]"
214
+ echo " wrangler secret put VARIABLE_NAME --name [worker-name]"
215
+ echo -e "\n${GREEN}✨ Worker secrets deployment complete!${NC}"
@@ -0,0 +1,23 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { updateMarkdownVersions } = require('./update-markdown-versions.cjs');
4
+ const { updateCompatibilityDates } = require('./update-compatibility-dates.cjs');
5
+
6
+ // Read the ASCII art file from the filesystem
7
+ const asciiArtPath = path.join(__dirname, '..', 'public', 'striae-ascii.txt');
8
+ let asciiArt;
9
+ try {
10
+ asciiArt = fs.readFileSync(asciiArtPath, 'utf8');
11
+ } catch (err) {
12
+ console.warn(`Warning: Unable to read ASCII art file at ${asciiArtPath}.\n${err.message}`);
13
+ asciiArt = "(ASCII art unavailable)\n";
14
+ }
15
+
16
+ // Pop a lil' logo in the terminal
17
+ console.info(asciiArt);
18
+
19
+ // Update markdown files with current version
20
+ updateMarkdownVersions();
21
+
22
+ // Update compatibility dates to current date
23
+ updateCompatibilityDates();
@@ -0,0 +1,88 @@
1
+ #!/bin/bash
2
+
3
+ # ======================================
4
+ # STRIAE WORKERS NPM INSTALL SCRIPT
5
+ # ======================================
6
+ # This script installs npm dependencies for all Striae workers:
7
+ # 1. audit-worker
8
+ # 2. data-worker
9
+ # 3. image-worker
10
+ # 4. keys-worker
11
+ # 5. pdf-worker
12
+ # 6. user-worker
13
+
14
+ # Colors for output
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ BLUE='\033[0;34m'
19
+ PURPLE='\033[0;35m'
20
+ NC='\033[0m' # No Color
21
+
22
+ echo -e "${BLUE}📦 Striae Workers NPM Install Script${NC}"
23
+ echo "========================================"
24
+ echo ""
25
+
26
+ # Get the script directory and project root
27
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
29
+ WORKERS_DIR="$PROJECT_ROOT/workers"
30
+
31
+ # Check if workers directory exists
32
+ if [ ! -d "$WORKERS_DIR" ]; then
33
+ echo -e "${RED}❌ Error: Workers directory not found at $WORKERS_DIR${NC}"
34
+ exit 1
35
+ fi
36
+
37
+ # List of workers
38
+ WORKERS=("audit-worker" "data-worker" "image-worker" "keys-worker" "pdf-worker" "user-worker")
39
+
40
+ echo -e "${PURPLE}Installing npm dependencies for all workers...${NC}"
41
+ echo ""
42
+
43
+ # Counter for progress
44
+ total=${#WORKERS[@]}
45
+ current=0
46
+
47
+ # Install dependencies for each worker
48
+ for worker in "${WORKERS[@]}"; do
49
+ current=$((current + 1))
50
+ worker_path="$WORKERS_DIR/$worker"
51
+
52
+ echo -e "${YELLOW}[$current/$total] Installing dependencies for $worker...${NC}"
53
+
54
+ # Check if worker directory exists
55
+ if [ ! -d "$worker_path" ]; then
56
+ echo -e "${RED}❌ Warning: Worker directory not found: $worker_path${NC}"
57
+ continue
58
+ fi
59
+
60
+ # Check if package.json exists
61
+ if [ ! -f "$worker_path/package.json" ]; then
62
+ echo -e "${RED}❌ Warning: package.json not found in $worker_path${NC}"
63
+ continue
64
+ fi
65
+
66
+ # Change to worker directory and install dependencies
67
+ cd "$worker_path"
68
+
69
+ echo " Running npm install in $worker_path..."
70
+ if npm install; then
71
+ echo -e "${GREEN}✅ Successfully installed dependencies for $worker${NC}"
72
+ else
73
+ echo -e "${RED}❌ Failed to install dependencies for $worker${NC}"
74
+ exit 1
75
+ fi
76
+
77
+ echo ""
78
+ done
79
+
80
+ # Return to original directory
81
+ cd "$PROJECT_ROOT"
82
+
83
+ echo -e "${GREEN}🎉 All worker dependencies installed successfully!${NC}"
84
+ echo ""
85
+ echo -e "${BLUE}Summary:${NC}"
86
+ echo "- Installed dependencies for $total workers"
87
+ echo "- All workers are ready for development/deployment"
88
+ echo ""
@@ -0,0 +1,35 @@
1
+ const { spawnSync } = require('node:child_process');
2
+ const path = require('node:path');
3
+
4
+ const eslintApiPath = require.resolve('eslint');
5
+ const eslintCliPath = path.resolve(path.dirname(eslintApiPath), '..', 'bin', 'eslint.js');
6
+
7
+ const defaultArgs = [
8
+ '--ignore-path',
9
+ '.gitignore',
10
+ '--cache',
11
+ '--cache-location',
12
+ './node_modules/.cache/eslint',
13
+ '.',
14
+ ];
15
+
16
+ const passthroughArgs = process.argv.slice(2);
17
+ const eslintArgs = passthroughArgs.length > 0 ? passthroughArgs : defaultArgs;
18
+
19
+ const result = spawnSync(process.execPath, [eslintCliPath, ...eslintArgs], {
20
+ stdio: 'inherit',
21
+ env: {
22
+ ...process.env,
23
+ ESLINT_USE_FLAT_CONFIG: 'false',
24
+ },
25
+ });
26
+
27
+ if (typeof result.status === 'number') {
28
+ process.exit(result.status);
29
+ }
30
+
31
+ if (result.error) {
32
+ console.error(result.error);
33
+ }
34
+
35
+ process.exit(1);
@@ -0,0 +1,124 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
5
+
6
+ function getCurrentDate() {
7
+ const now = new Date();
8
+ const year = now.getFullYear();
9
+ const month = String(now.getMonth() + 1).padStart(2, '0');
10
+ const day = String(now.getDate()).padStart(2, '0');
11
+ return `${year}-${month}-${day}`;
12
+ }
13
+
14
+ function replaceTomlCompatibilityDate(content, date) {
15
+ return content.replace(
16
+ /(compatibility_date\s*=\s*")\d{4}-\d{2}-\d{2}(")/,
17
+ `$1${date}$2`
18
+ );
19
+ }
20
+
21
+ function replaceJsoncCompatibilityDate(content, date) {
22
+ return content.replace(
23
+ /("compatibility_date"\s*:\s*")\d{4}-\d{2}-\d{2}(",?)/,
24
+ `$1${date}$2`
25
+ );
26
+ }
27
+
28
+ function updateFile(filePath, date, replacer) {
29
+ if (!fs.existsSync(filePath)) {
30
+ return { filePath, status: 'missing' };
31
+ }
32
+
33
+ const original = fs.readFileSync(filePath, 'utf8');
34
+ const updated = replacer(original, date);
35
+
36
+ if (original === updated) {
37
+ return { filePath, status: 'unchanged' };
38
+ }
39
+
40
+ fs.writeFileSync(filePath, updated, 'utf8');
41
+ return { filePath, status: 'updated' };
42
+ }
43
+
44
+ function updateCompatibilityDates(date = getCurrentDate()) {
45
+ if (!DATE_PATTERN.test(date)) {
46
+ throw new Error(`Invalid date format: ${date}. Use YYYY-MM-DD.`);
47
+ }
48
+
49
+ const rootDir = path.resolve(__dirname, '..');
50
+ const workersDir = path.join(rootDir, 'workers');
51
+
52
+ const results = [];
53
+
54
+ results.push(
55
+ updateFile(
56
+ path.join(rootDir, 'wrangler.toml'),
57
+ date,
58
+ replaceTomlCompatibilityDate
59
+ )
60
+ );
61
+
62
+ results.push(
63
+ updateFile(
64
+ path.join(rootDir, 'wrangler.toml.example'),
65
+ date,
66
+ replaceTomlCompatibilityDate
67
+ )
68
+ );
69
+
70
+ if (fs.existsSync(workersDir)) {
71
+ const workerDirs = fs
72
+ .readdirSync(workersDir, { withFileTypes: true })
73
+ .filter((entry) => entry.isDirectory())
74
+ .map((entry) => entry.name);
75
+
76
+ for (const workerDir of workerDirs) {
77
+ const workerPath = path.join(workersDir, workerDir);
78
+ results.push(
79
+ updateFile(
80
+ path.join(workerPath, 'wrangler.jsonc.example'),
81
+ date,
82
+ replaceJsoncCompatibilityDate
83
+ )
84
+ );
85
+ results.push(
86
+ updateFile(
87
+ path.join(workerPath, 'wrangler.jsonc'),
88
+ date,
89
+ replaceJsoncCompatibilityDate
90
+ )
91
+ );
92
+ }
93
+ }
94
+
95
+ const updatedCount = results.filter((result) => result.status === 'updated').length;
96
+ const unchangedCount = results.filter((result) => result.status === 'unchanged').length;
97
+ const missingCount = results.filter((result) => result.status === 'missing').length;
98
+
99
+ console.log(`Updated compatibility dates to ${date}`);
100
+ console.log(`- Updated: ${updatedCount}`);
101
+ console.log(`- Unchanged: ${unchangedCount}`);
102
+ console.log(`- Missing: ${missingCount}`);
103
+
104
+ for (const result of results) {
105
+ if (result.status !== 'updated') {
106
+ console.log(` ${result.status.toUpperCase()}: ${path.relative(rootDir, result.filePath)}`);
107
+ }
108
+ }
109
+
110
+ return results;
111
+ }
112
+
113
+ if (require.main === module) {
114
+ const dateArg = process.argv[2] || getCurrentDate();
115
+
116
+ try {
117
+ updateCompatibilityDates(dateArg);
118
+ } catch (error) {
119
+ console.error(error.message);
120
+ process.exit(1);
121
+ }
122
+ }
123
+
124
+ module.exports = { updateCompatibilityDates };
@@ -0,0 +1,43 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const packageJson = require('../package.json');
4
+
5
+ const markdownFiles = [
6
+ '.github/SECURITY.md',
7
+ // Add other markdown files that need version updates
8
+ ];
9
+
10
+ function updateMarkdownVersions() {
11
+ console.log(`📝 Updating markdown files with version ${packageJson.version}...`);
12
+
13
+ markdownFiles.forEach(filePath => {
14
+ const fullPath = path.join(__dirname, '..', filePath);
15
+
16
+ if (!fs.existsSync(fullPath)) {
17
+ console.log(`⚠️ Skipping ${filePath} (file not found)`);
18
+ return;
19
+ }
20
+
21
+ try {
22
+ let content = fs.readFileSync(fullPath, 'utf8');
23
+
24
+ // Replace version placeholders
25
+ content = content.replace(/{{VERSION}}/g, packageJson.version);
26
+ content = content.replace(/v\d+\.\d+\.\d+(-\w+)?/g, `v${packageJson.version}`);
27
+
28
+ fs.writeFileSync(fullPath, content);
29
+ console.log(`✅ Updated ${filePath}`);
30
+ } catch (error) {
31
+ console.error(`❌ Error updating ${filePath}:`, error.message);
32
+ }
33
+ });
34
+
35
+ console.log('🎉 Markdown version update complete!');
36
+ }
37
+
38
+ // Run if called directly
39
+ if (require.main === module) {
40
+ updateMarkdownVersions();
41
+ }
42
+
43
+ module.exports = { updateMarkdownVersions };
@@ -0,0 +1,22 @@
1
+ import type { Config } from "tailwindcss";
2
+
3
+ export default {
4
+ content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"],
5
+ theme: {
6
+ extend: {
7
+ fontFamily: {
8
+ sans: [
9
+ "Inter",
10
+ "ui-sans-serif",
11
+ "system-ui",
12
+ "sans-serif",
13
+ "Apple Color Emoji",
14
+ "Segoe UI Emoji",
15
+ "Segoe UI Symbol",
16
+ "Noto Color Emoji",
17
+ ],
18
+ },
19
+ },
20
+ },
21
+ plugins: [],
22
+ } satisfies Config;
package/tsconfig.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "include": [
3
+ "**/*.ts",
4
+ "**/*.tsx",
5
+ "**/.server/**/*.ts",
6
+ "**/.server/**/*.tsx",
7
+ "**/.client/**/*.ts",
8
+ "**/.client/**/*.tsx"
9
+ ],
10
+ "compilerOptions": {
11
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
12
+ "types": [
13
+ "@remix-run/cloudflare",
14
+ "vite/client"
15
+ ],
16
+ "isolatedModules": true,
17
+ "esModuleInterop": true,
18
+ "jsx": "react-jsx",
19
+ "module": "ESNext",
20
+ "moduleResolution": "Bundler",
21
+ "resolveJsonModule": true,
22
+ "target": "ES2022",
23
+ "strict": true,
24
+ "allowJs": true,
25
+ "skipLibCheck": true,
26
+ "forceConsistentCasingInFileNames": true,
27
+ "paths": {
28
+ "~/*": ["./app/*"]
29
+ },
30
+
31
+ "noEmit": true
32
+ }
33
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,35 @@
1
+ import {
2
+ vitePlugin as remix,
3
+ cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
4
+ } from "@remix-run/dev";
5
+ import { defineConfig } from "vite";
6
+ import tsconfigPaths from "vite-tsconfig-paths";
7
+
8
+ declare module "@remix-run/cloudflare" {
9
+ interface Future {
10
+ v3_singleFetch: true;
11
+ }
12
+ }
13
+
14
+ export default defineConfig({
15
+ server: {
16
+ port: 7777,
17
+ },
18
+ build: {
19
+ chunkSizeWarningLimit: 500,
20
+ minify: true,
21
+ },
22
+ plugins: [
23
+ remixCloudflareDevProxy(),
24
+ remix({
25
+ future: {
26
+ v3_fetcherPersist: true,
27
+ v3_relativeSplatPath: true,
28
+ v3_throwAbortReason: true,
29
+ v3_singleFetch: true,
30
+ v3_lazyRouteDiscovery: true,
31
+ },
32
+ }),
33
+ tsconfigPaths()
34
+ ],
35
+ });