@striae-org/striae 5.5.0 → 5.5.2
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 +9 -1
- package/app/components/actions/export-audit-pdf.ts +2 -3
- package/app/components/sidebar/notes/class-details/class-details-modal.tsx +3 -3
- package/app/components/sidebar/notes/notes-editor-form.tsx +244 -12
- package/app/components/sidebar/notes/notes-editor-modal.tsx +181 -2
- package/app/components/sidebar/notes/notes.module.css +77 -0
- package/app/components/user/user.module.css +1 -1
- package/app/routes/auth/login.example.tsx +17 -5
- package/functions/api/_shared/registration-allowlist.ts +38 -0
- package/functions/api/auth/can-register.ts +59 -0
- package/functions/api/user/[[path]].ts +34 -0
- package/members.emails.example +11 -0
- package/package.json +12 -12
- package/scripts/deploy-all.sh +2 -2
- package/scripts/deploy-members-emails.sh +102 -0
- package/scripts/deploy-pages-secrets.sh +13 -70
- package/scripts/deploy-primershear-emails.sh +7 -73
- package/scripts/update-markdown-versions.cjs +58 -1
- package/worker-configuration.d.ts +2 -1
- package/workers/audit-worker/package.json +13 -18
- package/workers/audit-worker/wrangler.jsonc.example +1 -1
- package/workers/data-worker/package.json +13 -18
- package/workers/data-worker/wrangler.jsonc.example +1 -1
- package/workers/image-worker/package.json +13 -18
- package/workers/image-worker/wrangler.jsonc.example +1 -1
- package/workers/pdf-worker/package.json +14 -19
- package/workers/pdf-worker/src/audit-trail-report.ts +28 -6
- package/workers/pdf-worker/src/report-types.ts +1 -0
- package/workers/pdf-worker/wrangler.jsonc.example +1 -1
- package/workers/user-worker/package.json +13 -18
- package/workers/user-worker/wrangler.jsonc.example +1 -1
- package/wrangler.toml.example +1 -1
|
@@ -4,16 +4,7 @@
|
|
|
4
4
|
# PRIMERSHEAR EMAIL LIST DEPLOYMENT SCRIPT
|
|
5
5
|
# ============================================
|
|
6
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
|
|
7
|
+
# then deploys that secret directly to Cloudflare Pages (production).
|
|
17
8
|
|
|
18
9
|
set -e
|
|
19
10
|
set -o pipefail
|
|
@@ -33,43 +24,6 @@ cd "$PROJECT_ROOT"
|
|
|
33
24
|
|
|
34
25
|
trap 'echo -e "\n${RED}❌ deploy-primershear-emails.sh failed near line ${LINENO}${NC}"' ERR
|
|
35
26
|
|
|
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
27
|
# ── Read emails file ──────────────────────────────────────────────────────────
|
|
74
28
|
|
|
75
29
|
EMAILS_FILE="$PROJECT_ROOT/primershear.emails"
|
|
@@ -114,11 +68,6 @@ else
|
|
|
114
68
|
echo -e "${GREEN}✅ Appended PRIMERSHEAR_EMAILS to .env${NC}"
|
|
115
69
|
fi
|
|
116
70
|
|
|
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
71
|
# ── Deploy to Cloudflare Pages ────────────────────────────────────────────────
|
|
123
72
|
|
|
124
73
|
if ! command -v wrangler > /dev/null 2>&1; then
|
|
@@ -134,31 +83,16 @@ if [ -z "$PAGES_PROJECT_NAME" ]; then
|
|
|
134
83
|
exit 1
|
|
135
84
|
fi
|
|
136
85
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
|
86
|
+
echo -e "${YELLOW} Setting PRIMERSHEAR_EMAILS for production...${NC}"
|
|
87
|
+
printf '%s' "$PRIMERSHEAR_EMAILS" | wrangler pages secret put PRIMERSHEAR_EMAILS \
|
|
88
|
+
--project-name "$PAGES_PROJECT_NAME"
|
|
153
89
|
|
|
154
|
-
|
|
155
|
-
set_secret "preview"
|
|
156
|
-
echo -e "${GREEN}✅ PRIMERSHEAR_EMAILS deployed to preview${NC}"
|
|
157
|
-
fi
|
|
90
|
+
echo -e "${GREEN}✅ PRIMERSHEAR_EMAILS deployed to production${NC}"
|
|
158
91
|
|
|
159
92
|
# Deploy Pages so the new secret takes effect immediately
|
|
160
93
|
echo -e "\n${YELLOW}🚀 Building and deploying Pages to activate new secret...${NC}"
|
|
161
|
-
|
|
94
|
+
|
|
95
|
+
if ! npm run deploy-pages; then
|
|
162
96
|
echo -e "${RED}❌ Pages deployment failed${NC}"
|
|
163
97
|
exit 1
|
|
164
98
|
fi
|
|
@@ -7,6 +7,14 @@ const markdownFiles = [
|
|
|
7
7
|
// Add other markdown files that need version updates
|
|
8
8
|
];
|
|
9
9
|
|
|
10
|
+
const workerDirs = [
|
|
11
|
+
'workers/audit-worker',
|
|
12
|
+
'workers/data-worker',
|
|
13
|
+
'workers/image-worker',
|
|
14
|
+
'workers/pdf-worker',
|
|
15
|
+
'workers/user-worker',
|
|
16
|
+
];
|
|
17
|
+
|
|
10
18
|
function updateMarkdownVersions() {
|
|
11
19
|
console.log(`📝 Updating markdown files with version ${packageJson.version}...`);
|
|
12
20
|
|
|
@@ -31,8 +39,57 @@ function updateMarkdownVersions() {
|
|
|
31
39
|
console.error(`❌ Error updating ${filePath}:`, error.message);
|
|
32
40
|
}
|
|
33
41
|
});
|
|
42
|
+
|
|
43
|
+
console.log(`📦 Updating worker package.json files with version ${packageJson.version}...`);
|
|
44
|
+
|
|
45
|
+
workerDirs.forEach(workerDir => {
|
|
46
|
+
const pkgPath = path.join(__dirname, '..', workerDir, 'package.json');
|
|
47
|
+
const lockPath = path.join(__dirname, '..', workerDir, 'package-lock.json');
|
|
48
|
+
|
|
49
|
+
// --- Update package.json ---
|
|
50
|
+
if (!fs.existsSync(pkgPath)) {
|
|
51
|
+
console.log(`⚠️ Skipping ${workerDir}/package.json (file not found)`);
|
|
52
|
+
} else {
|
|
53
|
+
try {
|
|
54
|
+
const workerPkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
55
|
+
workerPkg.version = packageJson.version;
|
|
56
|
+
fs.writeFileSync(pkgPath, JSON.stringify(workerPkg, null, 2) + '\n');
|
|
57
|
+
console.log(`✅ Updated ${workerDir}/package.json`);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error(`❌ Error updating ${workerDir}/package.json:`, error.message);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// --- Update package-lock.json ---
|
|
64
|
+
// Lockfile v2/v3 stores the version in two places:
|
|
65
|
+
// - Top-level `version` field
|
|
66
|
+
// - `packages[""].version` (the self-referencing root entry)
|
|
67
|
+
// Both must match package.json to pass `npm ci` consistency checks.
|
|
68
|
+
if (!fs.existsSync(lockPath)) {
|
|
69
|
+
console.log(
|
|
70
|
+
`⚠️ No package-lock.json found in ${workerDir} — run \`npm install\` there to generate one.`
|
|
71
|
+
);
|
|
72
|
+
} else {
|
|
73
|
+
try {
|
|
74
|
+
const lockData = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
|
|
75
|
+
|
|
76
|
+
if ('version' in lockData) {
|
|
77
|
+
lockData.version = packageJson.version;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (lockData.packages && '' in lockData.packages) {
|
|
81
|
+
lockData.packages[''].version = packageJson.version;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
fs.writeFileSync(lockPath, JSON.stringify(lockData, null, 2) + '\n');
|
|
85
|
+
console.log(`✅ Updated ${workerDir}/package-lock.json`);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error(`❌ Error updating ${workerDir}/package-lock.json:`, error.message);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
34
91
|
|
|
35
|
-
console.log('🎉
|
|
92
|
+
console.log('🎉 Version update complete!');
|
|
36
93
|
}
|
|
37
94
|
|
|
38
95
|
// Run if called directly
|
|
@@ -58,6 +58,7 @@ declare namespace Cloudflare {
|
|
|
58
58
|
PDF_WORKER_AUTH: string;
|
|
59
59
|
BROWSER_API_TOKEN: string;
|
|
60
60
|
PRIMERSHEAR_EMAILS: string;
|
|
61
|
+
REGISTRATION_EMAILS: string;
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
interface Env extends Cloudflare.Env {}
|
|
@@ -65,7 +66,7 @@ type StringifyValues<EnvType extends Record<string, unknown>> = {
|
|
|
65
66
|
[Binding in keyof EnvType]: EnvType[Binding] extends string ? EnvType[Binding] : string;
|
|
66
67
|
};
|
|
67
68
|
declare namespace NodeJS {
|
|
68
|
-
interface ProcessEnv extends StringifyValues<Pick<Cloudflare.Env, "ACCOUNT_ID" | "USER_DB_AUTH" | "R2_KEY_SECRET" | "IMAGES_API_TOKEN" | "API_KEY" | "AUTH_DOMAIN" | "PROJECT_ID" | "STORAGE_BUCKET" | "MESSAGING_SENDER_ID" | "APP_ID" | "MEASUREMENT_ID" | "FIREBASE_SERVICE_ACCOUNT_EMAIL" | "FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY" | "USER_KV_ENCRYPTION_PRIVATE_KEY" | "USER_KV_ENCRYPTION_KEY_ID" | "USER_KV_ENCRYPTION_PUBLIC_KEY" | "USER_KV_WRITE_ENDPOINTS_ENABLED" | "USER_KV_ENCRYPTION_KEYS_JSON" | "USER_KV_ENCRYPTION_ACTIVE_KEY_ID" | "MANIFEST_SIGNING_PRIVATE_KEY" | "MANIFEST_SIGNING_KEY_ID" | "MANIFEST_SIGNING_PUBLIC_KEY" | "EXPORT_ENCRYPTION_PRIVATE_KEY" | "EXPORT_ENCRYPTION_KEY_ID" | "EXPORT_ENCRYPTION_PUBLIC_KEY" | "EXPORT_ENCRYPTION_KEYS_JSON" | "EXPORT_ENCRYPTION_ACTIVE_KEY_ID" | "DATA_AT_REST_ENCRYPTION_ENABLED" | "DATA_AT_REST_ENCRYPTION_PRIVATE_KEY" | "DATA_AT_REST_ENCRYPTION_KEY_ID" | "DATA_AT_REST_ENCRYPTION_PUBLIC_KEY" | "DATA_AT_REST_ENCRYPTION_KEYS_JSON" | "DATA_AT_REST_ENCRYPTION_ACTIVE_KEY_ID" | "PAGES_PROJECT_NAME" | "PAGES_CUSTOM_DOMAIN" | "USER_WORKER_NAME" | "USER_WORKER_DOMAIN" | "KV_STORE_ID" | "DATA_WORKER_NAME" | "DATA_BUCKET_NAME" | "FILES_BUCKET_NAME" | "DATA_WORKER_DOMAIN" | "AUDIT_WORKER_NAME" | "AUDIT_BUCKET_NAME" | "AUDIT_WORKER_DOMAIN" | "IMAGES_WORKER_NAME" | "IMAGES_WORKER_DOMAIN" | "IMAGE_SIGNED_URL_SECRET" | "IMAGE_SIGNED_URL_TTL_SECONDS" | "IMAGE_SIGNED_URL_BASE_URL" | "PDF_WORKER_NAME" | "PDF_WORKER_DOMAIN" | "PDF_WORKER_AUTH" | "BROWSER_API_TOKEN" | "PRIMERSHEAR_EMAILS">> {}
|
|
69
|
+
interface ProcessEnv extends StringifyValues<Pick<Cloudflare.Env, "ACCOUNT_ID" | "USER_DB_AUTH" | "R2_KEY_SECRET" | "IMAGES_API_TOKEN" | "API_KEY" | "AUTH_DOMAIN" | "PROJECT_ID" | "STORAGE_BUCKET" | "MESSAGING_SENDER_ID" | "APP_ID" | "MEASUREMENT_ID" | "FIREBASE_SERVICE_ACCOUNT_EMAIL" | "FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY" | "USER_KV_ENCRYPTION_PRIVATE_KEY" | "USER_KV_ENCRYPTION_KEY_ID" | "USER_KV_ENCRYPTION_PUBLIC_KEY" | "USER_KV_WRITE_ENDPOINTS_ENABLED" | "USER_KV_ENCRYPTION_KEYS_JSON" | "USER_KV_ENCRYPTION_ACTIVE_KEY_ID" | "MANIFEST_SIGNING_PRIVATE_KEY" | "MANIFEST_SIGNING_KEY_ID" | "MANIFEST_SIGNING_PUBLIC_KEY" | "EXPORT_ENCRYPTION_PRIVATE_KEY" | "EXPORT_ENCRYPTION_KEY_ID" | "EXPORT_ENCRYPTION_PUBLIC_KEY" | "EXPORT_ENCRYPTION_KEYS_JSON" | "EXPORT_ENCRYPTION_ACTIVE_KEY_ID" | "DATA_AT_REST_ENCRYPTION_ENABLED" | "DATA_AT_REST_ENCRYPTION_PRIVATE_KEY" | "DATA_AT_REST_ENCRYPTION_KEY_ID" | "DATA_AT_REST_ENCRYPTION_PUBLIC_KEY" | "DATA_AT_REST_ENCRYPTION_KEYS_JSON" | "DATA_AT_REST_ENCRYPTION_ACTIVE_KEY_ID" | "PAGES_PROJECT_NAME" | "PAGES_CUSTOM_DOMAIN" | "USER_WORKER_NAME" | "USER_WORKER_DOMAIN" | "KV_STORE_ID" | "DATA_WORKER_NAME" | "DATA_BUCKET_NAME" | "FILES_BUCKET_NAME" | "DATA_WORKER_DOMAIN" | "AUDIT_WORKER_NAME" | "AUDIT_BUCKET_NAME" | "AUDIT_WORKER_DOMAIN" | "IMAGES_WORKER_NAME" | "IMAGES_WORKER_DOMAIN" | "IMAGE_SIGNED_URL_SECRET" | "IMAGE_SIGNED_URL_TTL_SECONDS" | "IMAGE_SIGNED_URL_BASE_URL" | "PDF_WORKER_NAME" | "PDF_WORKER_DOMAIN" | "PDF_WORKER_AUTH" | "BROWSER_API_TOKEN" | "PRIMERSHEAR_EMAILS" | "REGISTRATION_EMAILS">> {}
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
// Begin runtime types
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"overrides": {
|
|
15
|
-
"undici": "7.24.1",
|
|
16
|
-
"yauzl": "3.2.1"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "audit-worker",
|
|
3
|
+
"version": "5.5.2",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"deploy": "wrangler deploy",
|
|
7
|
+
"dev": "wrangler dev",
|
|
8
|
+
"start": "wrangler dev"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"wrangler": "^4.81.1"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "data-worker",
|
|
3
|
-
"version": "
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"deploy": "wrangler deploy",
|
|
7
|
-
"dev": "wrangler dev",
|
|
8
|
-
"start": "wrangler dev"
|
|
9
|
-
},
|
|
10
|
-
"devDependencies": {
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"overrides": {
|
|
15
|
-
"undici": "7.24.1",
|
|
16
|
-
"yauzl": "3.2.1"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "data-worker",
|
|
3
|
+
"version": "5.5.2",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"deploy": "wrangler deploy",
|
|
7
|
+
"dev": "wrangler dev",
|
|
8
|
+
"start": "wrangler dev"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"wrangler": "^4.81.1"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"overrides": {
|
|
15
|
-
"undici": "7.24.1",
|
|
16
|
-
"yauzl": "3.2.1"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "image-worker",
|
|
3
|
+
"version": "5.5.2",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"deploy": "wrangler deploy",
|
|
7
|
+
"dev": "wrangler dev",
|
|
8
|
+
"start": "wrangler dev"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"wrangler": "^4.81.1"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"overrides": {
|
|
16
|
-
"undici": "7.24.1",
|
|
17
|
-
"yauzl": "3.2.1"
|
|
18
|
-
}
|
|
19
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pdf-worker",
|
|
3
|
+
"version": "5.5.2",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"generate:assets": "node scripts/generate-assets.js",
|
|
7
|
+
"deploy": "wrangler deploy",
|
|
8
|
+
"dev": "wrangler dev",
|
|
9
|
+
"start": "wrangler dev"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"wrangler": "^4.81.1"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -3,13 +3,34 @@ import { buildRepeatedChromePdfOptions, escapeHtml } from './report-layout';
|
|
|
3
3
|
|
|
4
4
|
const safeText = (value: unknown): string => escapeHtml(String(value ?? ''));
|
|
5
5
|
|
|
6
|
-
const formatTimestamp = (timestamp: string): string => {
|
|
6
|
+
const formatTimestamp = (timestamp: string, timezone?: string): string => {
|
|
7
7
|
const parsed = new Date(timestamp);
|
|
8
8
|
if (Number.isNaN(parsed.getTime())) {
|
|
9
9
|
return timestamp;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
if (!timezone) {
|
|
13
|
+
return parsed.toISOString();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
18
|
+
timeZone: timezone,
|
|
19
|
+
month: '2-digit',
|
|
20
|
+
day: '2-digit',
|
|
21
|
+
year: 'numeric',
|
|
22
|
+
hour: '2-digit',
|
|
23
|
+
minute: '2-digit',
|
|
24
|
+
second: '2-digit',
|
|
25
|
+
hour12: false,
|
|
26
|
+
timeZoneName: 'short'
|
|
27
|
+
}).formatToParts(parsed);
|
|
28
|
+
|
|
29
|
+
const get = (type: string): string => parts.find(p => p.type === type)?.value ?? '';
|
|
30
|
+
return `${get('month')}/${get('day')}/${get('year')} ${get('hour')}:${get('minute')}:${get('second')} ${get('timeZoneName')}`;
|
|
31
|
+
} catch {
|
|
32
|
+
return parsed.toISOString();
|
|
33
|
+
}
|
|
13
34
|
};
|
|
14
35
|
|
|
15
36
|
const renderEntryDetailsSummary = (entry: Record<string, unknown>): string => {
|
|
@@ -71,6 +92,7 @@ export const getAuditTrailPayload = (data: PDFGenerationData): AuditTrailReportP
|
|
|
71
92
|
export const renderAuditTrailReport = (data: PDFGenerationData): string => {
|
|
72
93
|
const payload = getAuditTrailPayload(data);
|
|
73
94
|
const entries = payload.entries || [];
|
|
95
|
+
const timezone = data.userTimezone;
|
|
74
96
|
|
|
75
97
|
const entrySections = entries.map((entry, index) => {
|
|
76
98
|
const entryRecord = entry as Record<string, unknown>;
|
|
@@ -84,7 +106,7 @@ export const renderAuditTrailReport = (data: PDFGenerationData): string => {
|
|
|
84
106
|
<section class="entry-section">
|
|
85
107
|
<h3 class="entry-title">Entry ${index + 1} of ${entries.length}</h3>
|
|
86
108
|
<div class="entry-core-grid">
|
|
87
|
-
<div><strong>Timestamp:</strong> ${safeText(formatTimestamp(timestamp))}</div>
|
|
109
|
+
<div><strong>Timestamp:</strong> ${safeText(formatTimestamp(timestamp, timezone))}</div>
|
|
88
110
|
<div><strong>Action:</strong> ${safeText(action)}</div>
|
|
89
111
|
<div><strong>Result:</strong> ${safeText(result)}</div>
|
|
90
112
|
<div><strong>User Email:</strong> ${safeText(userEmail)}</div>
|
|
@@ -195,9 +217,9 @@ export const renderAuditTrailReport = (data: PDFGenerationData): string => {
|
|
|
195
217
|
<h1>Case Audit Trail Report</h1>
|
|
196
218
|
<div class="summary-grid">
|
|
197
219
|
<div><strong>Case Number:</strong> ${safeText(payload.caseNumber)}</div>
|
|
198
|
-
<div><strong>Exported At:</strong> ${safeText(formatTimestamp(payload.exportedAt))}</div>
|
|
199
|
-
<div><strong>Range Start:</strong> ${safeText(formatTimestamp(payload.exportRangeStart))}</div>
|
|
200
|
-
<div><strong>Range End:</strong> ${safeText(formatTimestamp(payload.exportRangeEnd))}</div>
|
|
220
|
+
<div><strong>Exported At:</strong> ${safeText(formatTimestamp(payload.exportedAt, timezone))}</div>
|
|
221
|
+
<div><strong>Range Start:</strong> ${safeText(formatTimestamp(payload.exportRangeStart, timezone))}</div>
|
|
222
|
+
<div><strong>Range End:</strong> ${safeText(formatTimestamp(payload.exportRangeEnd, timezone))}</div>
|
|
201
223
|
<div><strong>Total Entries (All Parts):</strong> ${safeText(payload.totalEntries)}</div>
|
|
202
224
|
<div><strong>This Part:</strong> ${safeText(payload.chunkIndex)} of ${safeText(payload.totalChunks)}</div>
|
|
203
225
|
<div><strong>Entries in Part:</strong> ${safeText(entries.length)}</div>
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "user-worker",
|
|
3
|
-
"version": "
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"deploy": "wrangler deploy",
|
|
7
|
-
"dev": "wrangler dev",
|
|
8
|
-
"start": "wrangler dev"
|
|
9
|
-
},
|
|
10
|
-
"devDependencies": {
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"overrides": {
|
|
15
|
-
"undici": "7.24.1",
|
|
16
|
-
"yauzl": "3.2.1"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "user-worker",
|
|
3
|
+
"version": "5.5.2",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"deploy": "wrangler deploy",
|
|
7
|
+
"dev": "wrangler dev",
|
|
8
|
+
"start": "wrangler dev"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"wrangler": "^4.81.1"
|
|
12
|
+
}
|
|
13
|
+
}
|
package/wrangler.toml.example
CHANGED