@striae-org/striae 4.1.0 → 4.2.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.
- package/.env.example +8 -0
- package/LICENSE +1 -1
- package/app/components/actions/case-export/core-export.ts +14 -8
- package/app/components/actions/case-export/data-processing.ts +1 -0
- package/app/components/actions/case-export/download-handlers.ts +7 -0
- package/app/components/actions/case-export/metadata-helpers.ts +2 -1
- package/app/components/actions/case-import/confirmation-import.ts +12 -2
- package/app/components/actions/case-import/orchestrator.ts +78 -32
- package/app/components/actions/case-import/storage-operations.ts +97 -8
- package/app/components/actions/case-import/zip-processing.ts +159 -86
- package/app/components/actions/case-manage.ts +463 -8
- package/app/components/actions/confirm-export.ts +9 -2
- package/app/components/actions/image-manage.ts +77 -44
- package/app/components/audit/user-audit-viewer.tsx +19 -8
- package/app/components/audit/user-audit.module.css +21 -0
- package/app/components/audit/viewer/audit-entries-list.tsx +12 -2
- package/app/components/audit/viewer/audit-filters-panel.tsx +1 -0
- package/app/components/audit/viewer/audit-viewer-utils.ts +2 -0
- package/app/components/audit/viewer/use-audit-viewer-data.ts +24 -1
- package/app/components/audit/viewer/use-audit-viewer-export.ts +1 -1
- package/app/components/canvas/box-annotations/box-annotations.module.css +22 -18
- package/app/components/canvas/box-annotations/box-annotations.tsx +15 -0
- package/app/components/canvas/canvas.module.css +64 -54
- package/app/components/canvas/canvas.tsx +14 -16
- package/app/components/canvas/confirmation/confirmation.module.css +1 -0
- package/app/components/canvas/confirmation/confirmation.tsx +12 -14
- package/app/components/colors/colors.module.css +4 -3
- package/app/components/navbar/case-modals/archive-case-modal.module.css +110 -0
- package/app/components/navbar/case-modals/archive-case-modal.tsx +129 -0
- package/app/components/navbar/case-modals/open-case-modal.module.css +81 -0
- package/app/components/navbar/case-modals/open-case-modal.tsx +120 -0
- package/app/components/navbar/case-modals/rename-case-modal.module.css +81 -0
- package/app/components/navbar/case-modals/rename-case-modal.tsx +107 -0
- package/app/components/navbar/navbar.module.css +447 -0
- package/app/components/navbar/navbar.tsx +402 -0
- package/app/components/public-signing-key-modal/public-signing-key-modal.module.css +1 -0
- package/app/components/public-signing-key-modal/public-signing-key-modal.tsx +15 -16
- package/app/components/sidebar/case-export/case-export.module.css +1 -0
- package/app/components/sidebar/case-export/case-export.tsx +8 -46
- package/app/components/sidebar/case-import/case-import.module.css +23 -0
- package/app/components/sidebar/case-import/case-import.tsx +64 -16
- package/app/components/sidebar/case-import/components/CasePreviewSection.tsx +20 -1
- package/app/components/sidebar/case-import/components/ConfirmationDialog.tsx +15 -0
- package/app/components/sidebar/cases/case-sidebar.tsx +68 -588
- package/app/components/sidebar/cases/cases-modal.module.css +1 -0
- package/app/components/sidebar/cases/cases-modal.tsx +82 -43
- package/app/components/sidebar/cases/cases.module.css +82 -21
- package/app/components/sidebar/files/files-modal.module.css +1 -0
- package/app/components/sidebar/files/files-modal.tsx +49 -52
- package/app/components/sidebar/notes/addl-notes-modal.tsx +82 -0
- package/app/components/sidebar/notes/{notes-sidebar.tsx → notes-editor-form.tsx} +187 -138
- package/app/components/sidebar/notes/notes-editor-modal.module.css +49 -0
- package/app/components/sidebar/notes/notes-editor-modal.tsx +64 -0
- package/app/components/sidebar/notes/notes.module.css +170 -1
- package/app/components/sidebar/sidebar-container.tsx +16 -28
- package/app/components/sidebar/sidebar.module.css +5 -69
- package/app/components/sidebar/sidebar.tsx +27 -125
- package/app/components/sidebar/upload/image-upload-zone.module.css +13 -13
- package/app/components/user/inactivity-warning.module.css +1 -0
- package/app/components/user/inactivity-warning.tsx +15 -2
- package/app/components/user/manage-profile.tsx +23 -10
- package/app/{tailwind.css → global.css} +1 -3
- package/app/hooks/useOverlayDismiss.ts +54 -4
- package/app/root.tsx +1 -1
- package/app/routes/auth/login.tsx +785 -774
- package/app/routes/striae/striae.module.css +10 -3
- package/app/routes/striae/striae.tsx +475 -30
- package/app/services/audit/audit.service.ts +173 -27
- package/app/services/audit/builders/audit-event-builders-case-file.ts +43 -0
- package/app/services/audit/builders/audit-event-builders-workflow.ts +2 -0
- package/app/services/audit/builders/index.ts +1 -0
- package/app/types/audit.ts +4 -1
- package/app/types/case.ts +29 -0
- package/app/types/import.ts +3 -0
- package/app/utils/data/confirmation-summary/summary-core.ts +279 -0
- package/app/utils/data/data-operations.ts +17 -861
- package/app/utils/data/index.ts +11 -1
- package/app/utils/data/operations/batch-operations.ts +113 -0
- package/app/utils/data/operations/case-operations.ts +168 -0
- package/app/utils/data/operations/confirmation-summary-operations.ts +301 -0
- package/app/utils/data/operations/file-annotation-operations.ts +196 -0
- package/app/utils/data/operations/index.ts +7 -0
- package/app/utils/data/operations/signing-operations.ts +225 -0
- package/app/utils/data/operations/types.ts +42 -0
- package/app/utils/data/operations/validation-operations.ts +48 -0
- package/app/utils/data/permissions.ts +16 -1
- package/app/utils/forensics/audit-export-signature.ts +5 -1
- package/app/utils/forensics/confirmation-signature.ts +3 -0
- package/app/utils/forensics/export-verification.ts +426 -22
- package/functions/api/_shared/firebase-auth.ts +2 -7
- package/functions/api/image/[[path]].ts +20 -23
- package/functions/api/pdf/[[path]].ts +27 -8
- package/package.json +7 -12
- package/scripts/deploy-primershear-emails.sh +2 -1
- package/worker-configuration.d.ts +3 -3
- package/workers/audit-worker/package.json +1 -1
- package/workers/audit-worker/worker-configuration.d.ts +7448 -11323
- package/workers/audit-worker/wrangler.jsonc.example +1 -1
- package/workers/data-worker/package.json +1 -1
- package/workers/data-worker/worker-configuration.d.ts +7448 -11323
- 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 +16 -5
- package/workers/image-worker/worker-configuration.d.ts +7447 -11322
- package/workers/image-worker/wrangler.jsonc.example +1 -1
- package/workers/keys-worker/package.json +1 -1
- package/workers/keys-worker/worker-configuration.d.ts +7447 -11322
- package/workers/keys-worker/wrangler.jsonc.example +1 -1
- package/workers/pdf-worker/package.json +1 -1
- package/workers/pdf-worker/src/formats/format-striae.ts +9 -14
- package/workers/pdf-worker/src/pdf-worker.example.ts +37 -58
- package/workers/pdf-worker/src/report-types.ts +3 -3
- package/workers/pdf-worker/worker-configuration.d.ts +7448 -11323
- package/workers/pdf-worker/wrangler.jsonc.example +1 -1
- package/workers/user-worker/package.json +1 -1
- package/workers/user-worker/src/user-worker.example.ts +17 -0
- package/workers/user-worker/worker-configuration.d.ts +7448 -11323
- package/workers/user-worker/wrangler.jsonc.example +1 -1
- package/wrangler.toml.example +1 -1
- package/NOTICE +0 -13
- package/app/components/sidebar/notes/notes-modal.tsx +0 -53
- package/postcss.config.js +0 -6
- package/public/.well-known/keybase.txt +0 -56
- package/tailwind.config.ts +0 -22
|
@@ -63,12 +63,6 @@ export const renderReport: ReportRenderer = (data: PDFGenerationData): string =>
|
|
|
63
63
|
return luminance < 0.5;
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
// Use passed currentDate or generate fallback
|
|
67
|
-
const displayDate = currentDate || (() => {
|
|
68
|
-
const now = new Date();
|
|
69
|
-
return `${(now.getMonth() + 1).toString().padStart(2, '0')}/${now.getDate().toString().padStart(2, '0')}/${now.getFullYear()}`;
|
|
70
|
-
})();
|
|
71
|
-
|
|
72
66
|
return `
|
|
73
67
|
<!DOCTYPE html>
|
|
74
68
|
<html lang="en">
|
|
@@ -146,7 +140,7 @@ export const renderReport: ReportRenderer = (data: PDFGenerationData): string =>
|
|
|
146
140
|
.left-annotation,
|
|
147
141
|
.right-annotation {
|
|
148
142
|
position: absolute;
|
|
149
|
-
padding:
|
|
143
|
+
padding: 0.75rem 1rem;
|
|
150
144
|
background: rgba(0, 0, 0, 0.7);
|
|
151
145
|
border-radius: 6px;
|
|
152
146
|
backdrop-filter: blur(4px);
|
|
@@ -154,16 +148,16 @@ export const renderReport: ReportRenderer = (data: PDFGenerationData): string =>
|
|
|
154
148
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
155
149
|
}
|
|
156
150
|
.left-annotation {
|
|
157
|
-
top:
|
|
158
|
-
left:
|
|
151
|
+
top: 1rem;
|
|
152
|
+
left: 1rem;
|
|
159
153
|
}
|
|
160
154
|
.right-annotation {
|
|
161
|
-
top:
|
|
162
|
-
right:
|
|
155
|
+
top: 1rem;
|
|
156
|
+
right: 1rem;
|
|
163
157
|
}
|
|
164
158
|
.case-text {
|
|
165
159
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
166
|
-
font-size:
|
|
160
|
+
font-size: 1rem;
|
|
167
161
|
font-weight: 700;
|
|
168
162
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
|
169
163
|
white-space: nowrap;
|
|
@@ -242,8 +236,9 @@ export const renderReport: ReportRenderer = (data: PDFGenerationData): string =>
|
|
|
242
236
|
.confirmation-section {
|
|
243
237
|
margin-top: 20px;
|
|
244
238
|
display: flex;
|
|
245
|
-
justify-content:
|
|
239
|
+
justify-content: flex-start;
|
|
246
240
|
align-items: flex-start;
|
|
241
|
+
gap: 20px;
|
|
247
242
|
}
|
|
248
243
|
.confirmation-box {
|
|
249
244
|
background: #ffffff;
|
|
@@ -404,7 +399,7 @@ export const renderReport: ReportRenderer = (data: PDFGenerationData): string =>
|
|
|
404
399
|
<div class="content-wrapper">
|
|
405
400
|
<div class="header">
|
|
406
401
|
<div class="header-content">
|
|
407
|
-
<div class="date">${
|
|
402
|
+
<div class="date">${currentDate}</div>
|
|
408
403
|
${caseNumber ? `<div class="case-number">${caseNumber}</div>` : '<div class="case-number"></div>'}
|
|
409
404
|
</div>
|
|
410
405
|
</div>
|
|
@@ -3,13 +3,10 @@ import type { PDFGenerationData, PDFGenerationRequest, ReportModule } from './re
|
|
|
3
3
|
interface Env {
|
|
4
4
|
BROWSER: Fetcher;
|
|
5
5
|
PDF_WORKER_AUTH: string;
|
|
6
|
-
ACCOUNT_ID
|
|
7
|
-
|
|
8
|
-
BROWSER_API_TOKEN?: string;
|
|
9
|
-
API_TOKEN?: string;
|
|
6
|
+
ACCOUNT_ID: string;
|
|
7
|
+
BROWSER_API_TOKEN: string;
|
|
10
8
|
}
|
|
11
9
|
|
|
12
|
-
const DEFAULT_REPORT_FORMAT = 'striae';
|
|
13
10
|
const BROWSER_PDF_TIMEOUT_MS = 90_000;
|
|
14
11
|
const BROWSER_RENDERING_API_BASE = 'https://api.cloudflare.com/client/v4/accounts';
|
|
15
12
|
|
|
@@ -56,62 +53,47 @@ function jsonResponse(body: unknown, status: number): Response {
|
|
|
56
53
|
});
|
|
57
54
|
}
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
class MissingSecretError extends Error {
|
|
57
|
+
readonly secretKey: string;
|
|
61
58
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
constructor(key: string) {
|
|
60
|
+
super(`Worker is missing required secret: ${key}`);
|
|
61
|
+
this.name = 'MissingSecretError';
|
|
62
|
+
this.secretKey = key;
|
|
66
63
|
}
|
|
67
|
-
|
|
68
|
-
return '';
|
|
69
64
|
}
|
|
70
65
|
|
|
71
|
-
function
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (typeof candidate === 'string' && candidate.trim().length > 0) {
|
|
76
|
-
return candidate.trim();
|
|
77
|
-
}
|
|
66
|
+
function getRequiredSecret(value: string, name: string): string {
|
|
67
|
+
const normalized = value.trim();
|
|
68
|
+
if (!normalized) {
|
|
69
|
+
throw new MissingSecretError(name);
|
|
78
70
|
}
|
|
79
71
|
|
|
80
|
-
return
|
|
72
|
+
return normalized;
|
|
81
73
|
}
|
|
82
74
|
|
|
83
|
-
function
|
|
84
|
-
if (typeof
|
|
85
|
-
return DEFAULT_REPORT_FORMAT;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const normalized = format.trim().toLowerCase();
|
|
89
|
-
return normalized || DEFAULT_REPORT_FORMAT;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function resolveReportRequest(payload: unknown): { reportFormat: string; data: PDFGenerationData } {
|
|
93
|
-
if (!payload || typeof payload !== 'object') {
|
|
75
|
+
function resolveReportRequest(payload: unknown): PDFGenerationRequest {
|
|
76
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
94
77
|
throw new Error('Request body must be a JSON object');
|
|
95
78
|
}
|
|
96
79
|
|
|
97
80
|
const record = payload as Record<string, unknown>;
|
|
98
|
-
|
|
81
|
+
if (typeof record.reportFormat !== 'string' || record.reportFormat.trim().length === 0) {
|
|
82
|
+
throw new Error('Request body must include a non-empty reportFormat');
|
|
83
|
+
}
|
|
99
84
|
|
|
100
|
-
if (record.data
|
|
101
|
-
|
|
102
|
-
reportFormat,
|
|
103
|
-
data: record.data as PDFGenerationData,
|
|
104
|
-
};
|
|
85
|
+
if (!record.data || typeof record.data !== 'object' || Array.isArray(record.data)) {
|
|
86
|
+
throw new Error('Request body must include a data object');
|
|
105
87
|
}
|
|
106
88
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
89
|
+
const data = record.data as Record<string, unknown>;
|
|
90
|
+
if (typeof data.currentDate !== 'string' || data.currentDate.trim().length === 0) {
|
|
91
|
+
throw new Error('Request body data must include a non-empty currentDate');
|
|
92
|
+
}
|
|
111
93
|
|
|
112
94
|
return {
|
|
113
|
-
reportFormat,
|
|
114
|
-
data:
|
|
95
|
+
reportFormat: record.reportFormat.trim().toLowerCase(),
|
|
96
|
+
data: record.data as PDFGenerationData,
|
|
115
97
|
};
|
|
116
98
|
}
|
|
117
99
|
|
|
@@ -128,19 +110,8 @@ async function renderReport(reportFormat: string, data: PDFGenerationData): Prom
|
|
|
128
110
|
}
|
|
129
111
|
|
|
130
112
|
async function renderPdfViaRestEndpoint(env: Env, html: string): Promise<Response> {
|
|
131
|
-
const accountId =
|
|
132
|
-
const browserApiToken =
|
|
133
|
-
|
|
134
|
-
if (!accountId || !browserApiToken) {
|
|
135
|
-
return jsonResponse(
|
|
136
|
-
{
|
|
137
|
-
error: 'Missing required Browser Rendering credentials',
|
|
138
|
-
requiredSecrets: ['ACCOUNT_ID', 'BROWSER_API_TOKEN'],
|
|
139
|
-
note: 'Set ACCOUNT_ID and a Browser Rendering - Edit token (BROWSER_API_TOKEN) on this worker.',
|
|
140
|
-
},
|
|
141
|
-
502
|
|
142
|
-
);
|
|
143
|
-
}
|
|
113
|
+
const accountId = getRequiredSecret(env.ACCOUNT_ID, 'ACCOUNT_ID');
|
|
114
|
+
const browserApiToken = getRequiredSecret(env.BROWSER_API_TOKEN, 'BROWSER_API_TOKEN');
|
|
144
115
|
|
|
145
116
|
const endpoint = `${BROWSER_RENDERING_API_BASE}/${accountId}/browser-rendering/pdf`;
|
|
146
117
|
const requestBody = JSON.stringify({
|
|
@@ -217,12 +188,20 @@ export default {
|
|
|
217
188
|
|
|
218
189
|
if (request.method === 'POST') {
|
|
219
190
|
try {
|
|
220
|
-
const payload = await request.json() as
|
|
191
|
+
const payload = await request.json() as unknown;
|
|
221
192
|
const { reportFormat, data } = resolveReportRequest(payload);
|
|
222
193
|
const document = await renderReport(reportFormat, data);
|
|
223
194
|
|
|
224
195
|
return await renderPdfViaRestEndpoint(env, document);
|
|
225
196
|
} catch (error) {
|
|
197
|
+
if (error instanceof MissingSecretError) {
|
|
198
|
+
console.error(`[pdf-worker] Configuration error: ${error.message}`);
|
|
199
|
+
return jsonResponse(
|
|
200
|
+
{ error: 'Worker configuration error', missing_secret: error.secretKey },
|
|
201
|
+
502
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
226
205
|
if (isTimeoutError(error)) {
|
|
227
206
|
const timeoutMessage = error instanceof Error ? error.message : 'PDF generation timed out';
|
|
228
207
|
return jsonResponse({ error: timeoutMessage }, 504);
|
|
@@ -52,7 +52,7 @@ export interface PDFGenerationData {
|
|
|
52
52
|
caseNumber?: string;
|
|
53
53
|
annotationData?: AnnotationData;
|
|
54
54
|
activeAnnotations?: string[];
|
|
55
|
-
currentDate
|
|
55
|
+
currentDate: string;
|
|
56
56
|
notesUpdatedFormatted?: string;
|
|
57
57
|
userCompany?: string;
|
|
58
58
|
userFirstName?: string;
|
|
@@ -61,8 +61,8 @@ export interface PDFGenerationData {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export interface PDFGenerationRequest {
|
|
64
|
-
reportFormat
|
|
65
|
-
data
|
|
64
|
+
reportFormat: string;
|
|
65
|
+
data: PDFGenerationData;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export type ReportRenderer = (data: PDFGenerationData) => string;
|