@striae-org/striae 5.2.1 → 5.3.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.
Files changed (105) hide show
  1. package/.env.example +2 -10
  2. package/README.md +5 -46
  3. package/app/components/actions/case-export/core-export.ts +2 -174
  4. package/app/components/actions/case-export/download-handlers.ts +83 -750
  5. package/app/components/actions/case-export/index.ts +6 -30
  6. package/app/components/actions/case-export/metadata-helpers.ts +0 -78
  7. package/app/components/actions/case-export/types-constants.ts +0 -43
  8. package/app/components/actions/case-import/confirmation-import.ts +13 -14
  9. package/app/components/actions/case-import/zip-processing.ts +92 -12
  10. package/app/components/actions/generate-pdf.ts +3 -2
  11. package/app/components/audit/user-audit-viewer.tsx +0 -19
  12. package/app/components/audit/viewer/audit-viewer-header.tsx +0 -33
  13. package/app/components/navbar/case-modals/archive-case-modal.tsx +1 -1
  14. package/app/components/navbar/navbar.tsx +1 -1
  15. package/app/components/sidebar/case-import/case-import.module.css +35 -0
  16. package/app/components/sidebar/case-import/components/CasePreviewSection.tsx +59 -3
  17. package/app/components/sidebar/case-import/components/ConfirmationDialog.tsx +2 -4
  18. package/app/components/sidebar/case-import/components/ConfirmationPreviewSection.tsx +1 -1
  19. package/app/components/sidebar/notes/class-details-shared.ts +2 -2
  20. package/app/components/toast/toast.module.css +36 -0
  21. package/app/components/toast/toast.tsx +6 -2
  22. package/app/components/user/manage-profile.tsx +4 -3
  23. package/app/config-example/config.json +1 -2
  24. package/app/root.tsx +0 -7
  25. package/app/routes/_index.tsx +1 -1
  26. package/app/routes/auth/login.example.tsx +22 -103
  27. package/app/routes/auth/route.ts +1 -1
  28. package/app/routes/striae/striae.tsx +53 -59
  29. package/app/services/firebase/index.ts +0 -3
  30. package/app/types/export.ts +1 -2
  31. package/app/utils/auth/index.ts +0 -1
  32. package/app/utils/data/permissions.ts +3 -2
  33. package/package.json +9 -16
  34. package/public/_headers +0 -4
  35. package/public/_routes.json +0 -1
  36. package/worker-configuration.d.ts +20 -17
  37. package/workers/audit-worker/src/audit-worker.example.ts +9 -806
  38. package/workers/audit-worker/src/config.ts +7 -0
  39. package/workers/audit-worker/src/crypto/data-at-rest.ts +410 -0
  40. package/workers/audit-worker/src/handlers/audit-routes.ts +125 -0
  41. package/workers/audit-worker/src/storage/audit-storage.ts +99 -0
  42. package/workers/audit-worker/src/types.ts +56 -0
  43. package/workers/audit-worker/worker-configuration.d.ts +1 -1
  44. package/workers/audit-worker/wrangler.jsonc.example +1 -1
  45. package/workers/data-worker/src/config.ts +11 -0
  46. package/workers/data-worker/src/data-worker.example.ts +21 -942
  47. package/workers/data-worker/src/handlers/decrypt-export.ts +118 -0
  48. package/workers/data-worker/src/handlers/signing.ts +174 -0
  49. package/workers/data-worker/src/handlers/storage-routes.ts +129 -0
  50. package/workers/data-worker/src/registry/key-registry.ts +368 -0
  51. package/workers/data-worker/src/types.ts +46 -0
  52. package/workers/data-worker/worker-configuration.d.ts +1 -1
  53. package/workers/data-worker/wrangler.jsonc.example +1 -1
  54. package/workers/image-worker/worker-configuration.d.ts +1 -1
  55. package/workers/image-worker/wrangler.jsonc.example +1 -1
  56. package/workers/pdf-worker/worker-configuration.d.ts +2 -3
  57. package/workers/pdf-worker/wrangler.jsonc.example +1 -1
  58. package/workers/user-worker/src/auth.ts +30 -0
  59. package/workers/user-worker/src/cleanup/account-deletion.ts +337 -0
  60. package/workers/user-worker/src/config.ts +4 -0
  61. package/workers/user-worker/src/encryption-utils.ts +25 -0
  62. package/workers/user-worker/src/firebase/admin.ts +152 -0
  63. package/workers/user-worker/src/handlers/user-routes.ts +242 -0
  64. package/workers/user-worker/src/registry/user-kv.ts +172 -0
  65. package/workers/user-worker/src/storage/user-records.ts +34 -0
  66. package/workers/user-worker/src/types.ts +106 -0
  67. package/workers/user-worker/src/user-worker.example.ts +18 -964
  68. package/workers/user-worker/worker-configuration.d.ts +4 -2
  69. package/workers/user-worker/wrangler.jsonc.example +12 -1
  70. package/wrangler.toml.example +1 -1
  71. package/app/components/actions/case-export/data-processing.ts +0 -223
  72. package/app/components/sidebar/case-export/case-export.module.css +0 -418
  73. package/app/components/sidebar/case-export/case-export.tsx +0 -310
  74. package/app/types/exceljs-bare.d.ts +0 -9
  75. package/app/utils/auth/auth.ts +0 -11
  76. package/public/.well-known/security.txt +0 -6
  77. package/public/favicon.ico +0 -0
  78. package/public/icon-256.png +0 -0
  79. package/public/icon-512.png +0 -0
  80. package/public/manifest.json +0 -39
  81. package/public/shortcut.png +0 -0
  82. package/public/social-image.png +0 -0
  83. package/public/vendor/exceljs.LICENSE +0 -22
  84. package/public/vendor/exceljs.bare.min.js +0 -45
  85. package/scripts/deploy-all.sh +0 -166
  86. package/scripts/deploy-config/modules/env-utils.sh +0 -322
  87. package/scripts/deploy-config/modules/keys.sh +0 -404
  88. package/scripts/deploy-config/modules/prompt.sh +0 -372
  89. package/scripts/deploy-config/modules/scaffolding.sh +0 -344
  90. package/scripts/deploy-config/modules/validation.sh +0 -365
  91. package/scripts/deploy-config.sh +0 -236
  92. package/scripts/deploy-pages-secrets.sh +0 -231
  93. package/scripts/deploy-pages.sh +0 -34
  94. package/scripts/deploy-primershear-emails.sh +0 -167
  95. package/scripts/deploy-worker-secrets.sh +0 -374
  96. package/scripts/dev.cjs +0 -23
  97. package/scripts/install-workers.sh +0 -88
  98. package/scripts/run-eslint.cjs +0 -43
  99. package/scripts/update-compatibility-dates.cjs +0 -124
  100. package/scripts/update-markdown-versions.cjs +0 -43
  101. package/workers/keys-worker/package.json +0 -18
  102. package/workers/keys-worker/src/keys.example.ts +0 -67
  103. package/workers/keys-worker/src/keys.ts +0 -67
  104. package/workers/keys-worker/worker-configuration.d.ts +0 -7447
  105. package/workers/keys-worker/wrangler.jsonc.example +0 -15
package/.env.example CHANGED
@@ -29,8 +29,7 @@ MEASUREMENT_ID=your_firebase_measurement_id_here
29
29
  # ===============================
30
30
  # FIREBASE SERVICE ACCOUNT CONFIGURATION
31
31
  # ===============================
32
- # **PULLED FROM ADMIN-SERVICE.JSON FILE ONLY**
33
- PROJECT_ID=your_firebase_project_id_here
32
+ # Shared PROJECT_ID above is also sourced from app/config/admin-service.json by the deploy scripts.
34
33
  FIREBASE_SERVICE_ACCOUNT_EMAIL=your_firebase_service_account_email_here
35
34
  FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY=your_firebase_service_account_private_key_here
36
35
 
@@ -81,17 +80,10 @@ DATA_AT_REST_ENCRYPTION_ACTIVE_KEY_ID=
81
80
  PAGES_PROJECT_NAME=your_pages_project_name_here
82
81
  PAGES_CUSTOM_DOMAIN=your_custom_domain_here
83
82
 
84
- # ================================
85
- # KEYS WORKER ENVIRONMENT VARIABLES
86
- # ================================
87
- # Worker domains can be entered manually or auto-generated as a 10-character subdomain of PAGES_CUSTOM_DOMAIN during scripts/deploy-config.sh.
88
- KEYS_WORKER_NAME=your_keys_worker_name_here
89
- KEYS_WORKER_DOMAIN=your_keys_worker_domain_here
90
- KEYS_AUTH=your_custom_keys_auth_token_here
91
-
92
83
  # ================================
93
84
  # USER WORKER ENVIRONMENT VARIABLES
94
85
  # ================================
86
+ # Worker domains can be entered manually or auto-generated as a shared subdomain during scripts/deploy-config.sh.
95
87
  USER_WORKER_NAME=your_user_worker_name_here
96
88
  USER_WORKER_DOMAIN=your_user_worker_domain_here
97
89
  KV_STORE_ID=your_kv_store_id_here
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Striae is a cloud-native forensic annotation application for firearms identification, built with React Router and Cloudflare Workers.
4
4
 
5
- This npm package publishes the Striae application source and deployment scaffolding for teams that run their own Striae environment.
5
+ This npm package publishes the Striae application source for teams that run/develop their own Striae environment.
6
6
 
7
7
  ## Live Project
8
8
 
@@ -21,53 +21,11 @@ This npm package publishes the Striae application source and deployment scaffold
21
21
  - Not a small client SDK.
22
22
  - Not a zero-config, ready-to-run desktop app.
23
23
 
24
- ## npm Package, Installation, and Full Deployment
25
-
26
- **Striae Package Links**
24
+ ## Striae Package Links
27
25
 
28
26
  - npmjs: [https://www.npmjs.com/package/@striae-org/striae](https://www.npmjs.com/package/@striae-org/striae)
29
27
  - GitHub Packages: [https://github.com/orgs/striae-org/packages/npm/package/striae](https://github.com/orgs/striae-org/packages/npm/package/striae)
30
28
 
31
- 1) Install the latest package:
32
-
33
- ```bash
34
- npm i @striae-org/striae
35
- ```
36
-
37
- 2) Copy the package scaffold into the project root
38
-
39
- ```bash
40
- cp -R node_modules/@striae-org/striae/. .
41
- ```
42
-
43
- 3) Reinstall using Striae's own package.json (includes dev deps like wrangler/react-router)
44
-
45
- ```bash
46
- rm -rf node_modules package-lock.json
47
- npm install
48
- ```
49
-
50
- 4) Prepare Firebase admin credentials (required before deploy-config can pass)
51
-
52
- ```bash
53
- mkdir -p app/config
54
- cp -f app/config-example/admin-service.json app/config/admin-service.json
55
- ```
56
-
57
- 5) Replace `app/config/admin-service.json` with your actual Firebase service account JSON
58
-
59
- 6) Authenticate Cloudflare CLI
60
-
61
- ```bash
62
- npx wrangler login
63
- ```
64
-
65
- 7) Run guided config + full deployment
66
-
67
- ```bash
68
- npm run deploy:all
69
- ```
70
-
71
29
  ## NPM Package Content Policy
72
30
 
73
31
  This package intentionally includes only non-sensitive defaults and runtime source needed for setup.
@@ -75,9 +33,10 @@ This package intentionally includes only non-sensitive defaults and runtime sour
75
33
  Included:
76
34
 
77
35
  - `app/` source (with `app/config-example/`)
78
- - `functions/`, `public/`, `scripts/`
36
+ - `functions/`, `public/`
79
37
  - Worker package manifests
80
- - Worker source files except runtime entry files (`workers/*/src/*.ts` and excluding `workers/*/src/*worker.ts`)
38
+ - Worker source files needed by the example workers, including nested helper modules, while excluding production worker entry files (`workers/*/src/**/*.ts` excluding `workers/*/src/**/*worker.ts`)
39
+ - PDF worker example support files limited to `workers/pdf-worker/src/assets/generated-assets.example.ts` and `workers/pdf-worker/src/formats/format-striae.ts` (no extra PDF image assets or custom formats)
81
40
  - Worker example Wrangler configs (`workers/*/wrangler.jsonc.example`)
82
41
  - Project-level example and build config (`.env.example`, `wrangler.toml.example`, `tsconfig.json`, etc.)
83
42
 
@@ -1,183 +1,11 @@
1
1
  import type { User } from 'firebase/auth';
2
- import { type AnnotationData, type CaseExportData, type AllCasesExportData, type ExportOptions } from '~/types';
2
+ import { type AnnotationData, type CaseExportData, type ExportOptions } from '~/types';
3
3
  import { getCaseData } from '~/utils/data';
4
4
  import { fetchFiles } from '../image-manage';
5
5
  import { getNotes } from '../notes-manage';
6
- import { validateCaseNumber, listCases } from '../case-manage';
6
+ import { validateCaseNumber } from '../case-manage';
7
7
  import { getUserExportMetadata } from './metadata-helpers';
8
8
 
9
- /**
10
- * Export all cases for a user
11
- */
12
- export async function exportAllCases(
13
- user: User,
14
- options: ExportOptions = {},
15
- onProgress?: (current: number, total: number, caseName: string) => void
16
- ): Promise<AllCasesExportData> {
17
- // NOTE: startTime tracking moved to download handlers
18
-
19
- try {
20
- // NOTE: Audit workflow management moved to download handlers
21
-
22
- const {
23
- includeMetadata = true
24
- } = options;
25
-
26
- // Get user export metadata
27
- const userMetadata = await getUserExportMetadata(user);
28
-
29
- // Get list of all cases for the user
30
- const caseNumbers = await listCases(user);
31
-
32
- if (!caseNumbers || caseNumbers.length === 0) {
33
- throw new Error('No cases found for user');
34
- }
35
-
36
- const exportedCases: CaseExportData[] = [];
37
- let totalFiles = 0;
38
- let totalAnnotations = 0;
39
- let totalConfirmations = 0;
40
- let totalConfirmationsRequested = 0;
41
- let casesWithFiles = 0;
42
- let casesWithAnnotations = 0;
43
- let casesWithoutFiles = 0;
44
- let lastModified: string | undefined;
45
- let earliestAnnotationDate: string | undefined;
46
- let latestAnnotationDate: string | undefined;
47
-
48
- // Export each case
49
- for (let i = 0; i < caseNumbers.length; i++) {
50
- const caseNumber = caseNumbers[i];
51
-
52
- // Report progress
53
- if (onProgress) {
54
- onProgress(i + 1, caseNumbers.length, caseNumber);
55
- }
56
-
57
- try {
58
- const caseExport = await exportCaseData(user, caseNumber, options);
59
- exportedCases.push(caseExport);
60
-
61
- // Update totals
62
- totalFiles += caseExport.metadata.totalFiles;
63
-
64
- if (caseExport.metadata.totalFiles > 0) {
65
- casesWithFiles++;
66
- } else {
67
- casesWithoutFiles++;
68
- }
69
-
70
- // Count annotations and confirmations
71
- const caseAnnotations = caseExport.files.filter(f => f.hasAnnotations).length;
72
- if (caseAnnotations > 0) {
73
- casesWithAnnotations++;
74
- totalAnnotations += caseAnnotations;
75
- }
76
-
77
- // Count confirmations
78
- if (caseExport.summary?.filesWithConfirmations) {
79
- totalConfirmations += caseExport.summary.filesWithConfirmations;
80
- }
81
- if (caseExport.summary?.filesWithConfirmationsRequested) {
82
- totalConfirmationsRequested += caseExport.summary.filesWithConfirmationsRequested;
83
- }
84
-
85
- // Track latest modification
86
- if (caseExport.summary?.lastModified) {
87
- if (!lastModified || caseExport.summary.lastModified > lastModified) {
88
- lastModified = caseExport.summary.lastModified;
89
- }
90
- }
91
-
92
- // Track annotation date range across all cases
93
- if (caseExport.summary?.earliestAnnotationDate) {
94
- if (!earliestAnnotationDate || caseExport.summary.earliestAnnotationDate < earliestAnnotationDate) {
95
- earliestAnnotationDate = caseExport.summary.earliestAnnotationDate;
96
- }
97
- }
98
- if (caseExport.summary?.latestAnnotationDate) {
99
- if (!latestAnnotationDate || caseExport.summary.latestAnnotationDate > latestAnnotationDate) {
100
- latestAnnotationDate = caseExport.summary.latestAnnotationDate;
101
- }
102
- }
103
-
104
- } catch (error) {
105
- // Get case creation date even for failed exports
106
- let caseCreatedDate = new Date().toISOString(); // fallback
107
- try {
108
- const caseData = await getCaseData(user, caseNumber);
109
- if (caseData?.createdAt) {
110
- caseCreatedDate = caseData.createdAt;
111
- }
112
- } catch {
113
- // Use fallback date if case lookup fails
114
- }
115
-
116
- // Create a placeholder entry for failed exports
117
- exportedCases.push({
118
- metadata: {
119
- caseNumber,
120
- caseCreatedDate,
121
- exportDate: new Date().toISOString(),
122
- ...userMetadata,
123
- striaeExportSchemaVersion: '1.0',
124
- totalFiles: 0
125
- },
126
- files: [],
127
- summary: {
128
- filesWithAnnotations: 0,
129
- filesWithoutAnnotations: 0,
130
- totalBoxAnnotations: 0,
131
- exportError: error instanceof Error ? error.message : 'Unknown error'
132
- }
133
- });
134
- casesWithoutFiles++;
135
- }
136
- }
137
-
138
- const allCasesExport: AllCasesExportData = {
139
- metadata: {
140
- exportDate: new Date().toISOString(),
141
- ...userMetadata,
142
- striaeExportSchemaVersion: '1.0',
143
- totalCases: caseNumbers.length,
144
- totalFiles,
145
- totalAnnotations,
146
- totalConfirmations,
147
- totalConfirmationsRequested
148
- },
149
- cases: exportedCases
150
- };
151
-
152
- if (includeMetadata) {
153
- allCasesExport.summary = {
154
- casesWithFiles,
155
- casesWithAnnotations,
156
- casesWithoutFiles,
157
- lastModified,
158
- earliestAnnotationDate,
159
- latestAnnotationDate
160
- };
161
- }
162
-
163
- // Report completion
164
- if (onProgress) {
165
- onProgress(caseNumbers.length, caseNumbers.length, 'Export completed!');
166
- }
167
-
168
- // NOTE: Audit logging moved to download handlers where actual filename and format are known
169
-
170
- return allCasesExport;
171
-
172
- } catch (error) {
173
- console.error('Export all cases failed:', error);
174
-
175
- // NOTE: Audit logging for failures moved to download handlers
176
-
177
- throw error;
178
- }
179
- }
180
-
181
9
  /**
182
10
  * Export case data with files and annotations
183
11
  */