@striae-org/striae 6.1.7 → 6.1.8
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/README.md +1 -2
- package/package.json +144 -137
- package/scripts/deploy-config/modules/scaffolding.sh +0 -68
- package/scripts/deploy-config/modules/validation.sh +1 -12
- package/tsconfig.json +3 -0
- package/workers/audit-worker/package.json +1 -1
- package/workers/audit-worker/src/{audit-worker.example.ts → audit-worker.ts} +1 -12
- package/workers/data-worker/package.json +2 -1
- package/workers/data-worker/src/{data-worker.example.ts → data-worker.ts} +1 -12
- package/workers/image-worker/package.json +1 -1
- package/workers/image-worker/src/handlers/serve-image.ts +1 -3
- package/workers/image-worker/src/{image-worker.example.ts → image-worker.ts} +2 -15
- package/workers/image-worker/src/router.ts +2 -3
- package/workers/pdf-worker/package.json +1 -1
- package/workers/pdf-worker/src/{pdf-worker.example.ts → pdf-worker.ts} +1 -15
- package/workers/user-worker/package.json +1 -1
- package/workers/user-worker/src/handlers/user-routes.ts +25 -39
- package/workers/user-worker/src/{user-worker.example.ts → user-worker.ts} +14 -27
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ Included:
|
|
|
36
36
|
- `app/` source (with `app/config-example/`)
|
|
37
37
|
- `functions/`, `public/`
|
|
38
38
|
- Worker package manifests
|
|
39
|
-
- Worker source files needed by the
|
|
39
|
+
- Worker source files needed by the workers, including nested helper modules
|
|
40
40
|
- 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)
|
|
41
41
|
- Worker example Wrangler configs (`workers/*/wrangler.jsonc.example`)
|
|
42
42
|
- Project-level example and build config (`.env.example`, `wrangler.toml.example`, `tsconfig.json`, etc.)
|
|
@@ -60,6 +60,5 @@ See `LICENSE`.
|
|
|
60
60
|
|
|
61
61
|
## Support
|
|
62
62
|
|
|
63
|
-
- Striae Community: [https://community.striae.org](https://community.striae.org)
|
|
64
63
|
- Support page: [https://www.striae.org/support](https://www.striae.org/support)
|
|
65
64
|
- Contact: [info@striae.org](mailto:info@striae.org)
|
package/package.json
CHANGED
|
@@ -1,138 +1,145 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@striae-org/striae",
|
|
3
|
-
"version": "6.1.
|
|
4
|
-
"private": false,
|
|
5
|
-
"description": "Striae is a specialized, cloud-native platform designed to streamline forensic firearms identification by providing an intuitive environment for digital comparison image annotation, authenticated confirmations, and automated report generation.",
|
|
6
|
-
"license": "Apache-2.0",
|
|
7
|
-
"homepage": "https://github.com/striae-org/striae/wiki",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://github.com/striae-org/striae.git"
|
|
11
|
-
},
|
|
12
|
-
"funding": {
|
|
13
|
-
"type": "github",
|
|
14
|
-
"url": "https://github.com/sponsors/striae-org"
|
|
15
|
-
},
|
|
16
|
-
"bugs": {
|
|
17
|
-
"url": "https://github.com/striae-org/striae/issues"
|
|
18
|
-
},
|
|
19
|
-
"keywords": [
|
|
20
|
-
"forensics",
|
|
21
|
-
"firearms",
|
|
22
|
-
"annotation",
|
|
23
|
-
"react",
|
|
24
|
-
"cloudflare-workers",
|
|
25
|
-
"authenticated",
|
|
26
|
-
"confirmations",
|
|
27
|
-
"chain-of-custody",
|
|
28
|
-
"audit-trail"
|
|
29
|
-
],
|
|
30
|
-
"publishConfig": {
|
|
31
|
-
"access": "public"
|
|
32
|
-
},
|
|
33
|
-
"files": [
|
|
34
|
-
"app/",
|
|
35
|
-
"!app/config",
|
|
36
|
-
"react-router.config.ts",
|
|
37
|
-
"load-context.ts",
|
|
38
|
-
"scripts/",
|
|
39
|
-
"functions/",
|
|
40
|
-
"public/",
|
|
41
|
-
"workers/",
|
|
42
|
-
"shared/",
|
|
43
|
-
"!workers/*/.wrangler",
|
|
44
|
-
"!workers/*/package-lock.json",
|
|
45
|
-
"!workers/*/worker-configuration.d.ts",
|
|
46
|
-
"!workers/*/wrangler.jsonc",
|
|
47
|
-
"!workers
|
|
48
|
-
"
|
|
49
|
-
"workers/pdf-worker/src/
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
".
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"clean": "
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"publish:npm": "npm publish --access public --registry=https://registry.npmjs.org --@striae-org:registry=https://registry.npmjs.org",
|
|
71
|
-
"publish:
|
|
72
|
-
"publish:github": "npm publish --registry=https://npm.pkg.github.com --@striae-org:registry=https://npm.pkg.github.com",
|
|
73
|
-
"publish:
|
|
74
|
-
"publish:all": "npm run publish:npm && npm run publish:github",
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"deploy-
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"deploy-
|
|
94
|
-
"deploy-
|
|
95
|
-
"deploy-
|
|
96
|
-
"deploy-
|
|
97
|
-
"deploy-
|
|
98
|
-
"deploy-
|
|
99
|
-
"deploy-workers:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"@
|
|
117
|
-
"@
|
|
118
|
-
"@
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"eslint-plugin
|
|
123
|
-
"eslint
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
"
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
"
|
|
136
|
-
|
|
137
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@striae-org/striae",
|
|
3
|
+
"version": "6.1.8",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Striae is a specialized, cloud-native platform designed to streamline forensic firearms identification by providing an intuitive environment for digital comparison image annotation, authenticated confirmations, and automated report generation.",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"homepage": "https://github.com/striae-org/striae/wiki",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/striae-org/striae.git"
|
|
11
|
+
},
|
|
12
|
+
"funding": {
|
|
13
|
+
"type": "github",
|
|
14
|
+
"url": "https://github.com/sponsors/striae-org"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/striae-org/striae/issues"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"forensics",
|
|
21
|
+
"firearms",
|
|
22
|
+
"annotation",
|
|
23
|
+
"react",
|
|
24
|
+
"cloudflare-workers",
|
|
25
|
+
"authenticated",
|
|
26
|
+
"confirmations",
|
|
27
|
+
"chain-of-custody",
|
|
28
|
+
"audit-trail"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"app/",
|
|
35
|
+
"!app/config",
|
|
36
|
+
"react-router.config.ts",
|
|
37
|
+
"load-context.ts",
|
|
38
|
+
"scripts/",
|
|
39
|
+
"functions/",
|
|
40
|
+
"public/",
|
|
41
|
+
"workers/",
|
|
42
|
+
"shared/",
|
|
43
|
+
"!workers/*/.wrangler",
|
|
44
|
+
"!workers/*/package-lock.json",
|
|
45
|
+
"!workers/*/worker-configuration.d.ts",
|
|
46
|
+
"!workers/*/wrangler.jsonc",
|
|
47
|
+
"!workers/pdf-worker/src/assets/**/*",
|
|
48
|
+
"workers/pdf-worker/src/assets/generated-assets.example.ts",
|
|
49
|
+
"!workers/pdf-worker/src/formats/**/*",
|
|
50
|
+
"workers/pdf-worker/src/formats/format-striae.ts",
|
|
51
|
+
".env.example",
|
|
52
|
+
"firebase.json",
|
|
53
|
+
"tsconfig.json",
|
|
54
|
+
"vite.config.ts",
|
|
55
|
+
"/worker-configuration.d.ts",
|
|
56
|
+
"wrangler.toml.example",
|
|
57
|
+
"LICENSE"
|
|
58
|
+
],
|
|
59
|
+
"sideEffects": false,
|
|
60
|
+
"type": "module",
|
|
61
|
+
"scripts": {
|
|
62
|
+
"deploy:all": "bash ./scripts/deploy-all.sh",
|
|
63
|
+
"emulators": "firebase emulators:start --only auth",
|
|
64
|
+
"dev": "node ./scripts/dev.cjs && react-router dev",
|
|
65
|
+
"build": "node ./scripts/dev.cjs && react-router build",
|
|
66
|
+
"clean": "rm -rf build node_modules/.cache .cache",
|
|
67
|
+
"clean:build": "npm run clean && npm run build",
|
|
68
|
+
"deploy": "npm run build && wrangler pages deploy",
|
|
69
|
+
"publish:npm": "npm publish --access public --registry=https://registry.npmjs.org --@striae-org:registry=https://registry.npmjs.org",
|
|
70
|
+
"publish:npm:dry-run": "npm publish --dry-run --access public --registry=https://registry.npmjs.org --@striae-org:registry=https://registry.npmjs.org",
|
|
71
|
+
"publish:github": "npm publish --registry=https://npm.pkg.github.com --@striae-org:registry=https://npm.pkg.github.com",
|
|
72
|
+
"publish:github:dry-run": "npm publish --dry-run --registry=https://npm.pkg.github.com --@striae-org:registry=https://npm.pkg.github.com",
|
|
73
|
+
"publish:all": "npm run publish:npm && npm run publish:github",
|
|
74
|
+
"publish:all:dry-run": "npm run publish:npm:dry-run && npm run publish:github:dry-run",
|
|
75
|
+
"lint": "node ./scripts/run-eslint.cjs",
|
|
76
|
+
"start": "node ./scripts/dev.cjs && wrangler pages dev",
|
|
77
|
+
"typecheck": "react-router typegen && tsc",
|
|
78
|
+
"typegen": "wrangler types",
|
|
79
|
+
"preview": "npm run build && wrangler pages dev",
|
|
80
|
+
"cf-typegen": "wrangler types",
|
|
81
|
+
"test": "npm run test:app && npm run test:workers:data",
|
|
82
|
+
"test:app": "vitest run --config tests/app/vitest.config.ts",
|
|
83
|
+
"test:workers:data": "vitest run --config tests/workers/data/vitest.config.mjs",
|
|
84
|
+
"test:watch": "vitest --config tests/app/vitest.config.ts",
|
|
85
|
+
"test:coverage": "vitest run --config tests/app/vitest.config.ts --coverage",
|
|
86
|
+
"enable-totp-mfa": "node ./scripts/enable-totp-mfa.mjs",
|
|
87
|
+
"unenroll-totp-mfa": "node ./scripts/unenroll-totp-mfa.mjs",
|
|
88
|
+
"update-versions": "node ./scripts/update-markdown-versions.cjs",
|
|
89
|
+
"update-compatibility-dates": "node ./scripts/update-compatibility-dates.cjs",
|
|
90
|
+
"deploy-config": "bash ./scripts/deploy-config.sh",
|
|
91
|
+
"update-env": "bash ./scripts/deploy-config.sh --update-env",
|
|
92
|
+
"install-workers": "bash ./scripts/install-workers.sh",
|
|
93
|
+
"deploy-workers": "npm run deploy-workers:audit && npm run deploy-workers:data && npm run deploy-workers:image && npm run deploy-workers:pdf && npm run deploy-workers:user",
|
|
94
|
+
"deploy-workers:secrets": "bash ./scripts/deploy-worker-secrets.sh",
|
|
95
|
+
"deploy-pages:secrets": "bash ./scripts/deploy-pages-secrets.sh",
|
|
96
|
+
"deploy-pages": "bash ./scripts/deploy-pages.sh",
|
|
97
|
+
"deploy-primershear": "bash ./scripts/deploy-primershear-emails.sh",
|
|
98
|
+
"deploy-members": "bash ./scripts/deploy-members-emails.sh",
|
|
99
|
+
"deploy-workers:audit": "cd workers/audit-worker && npm run deploy",
|
|
100
|
+
"deploy-workers:data": "cd workers/data-worker && npm run deploy",
|
|
101
|
+
"deploy-workers:image": "cd workers/image-worker && npm run deploy",
|
|
102
|
+
"deploy-workers:pdf": "cd workers/pdf-worker && npm run deploy",
|
|
103
|
+
"deploy-workers:user": "cd workers/user-worker && npm run deploy"
|
|
104
|
+
},
|
|
105
|
+
"dependencies": {
|
|
106
|
+
"@react-router/cloudflare": "^7.14.1",
|
|
107
|
+
"firebase": "^12.12.1",
|
|
108
|
+
"isbot": "^5.1.39",
|
|
109
|
+
"jszip": "^3.10.1",
|
|
110
|
+
"qrcode": "^1.5.4",
|
|
111
|
+
"react": "^19.2.5",
|
|
112
|
+
"react-dom": "^19.2.5",
|
|
113
|
+
"react-router": "^7.14.1"
|
|
114
|
+
},
|
|
115
|
+
"devDependencies": {
|
|
116
|
+
"@cloudflare/vitest-pool-workers": "^0.14.8",
|
|
117
|
+
"@react-router/dev": "^7.14.1",
|
|
118
|
+
"@react-router/fs-routes": "^7.14.1",
|
|
119
|
+
"@types/qrcode": "^1.5.6",
|
|
120
|
+
"@types/react": "^19.2.14",
|
|
121
|
+
"@types/react-dom": "^19.2.3",
|
|
122
|
+
"@typescript-eslint/eslint-plugin": "^8.59.0",
|
|
123
|
+
"@typescript-eslint/parser": "^8.59.0",
|
|
124
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
125
|
+
"eslint": "^9.39.4",
|
|
126
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
127
|
+
"eslint-plugin-import": "^2.32.0",
|
|
128
|
+
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
129
|
+
"eslint-plugin-react": "^7.37.5",
|
|
130
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
131
|
+
"firebase-admin": "^13.8.0",
|
|
132
|
+
"modern-normalize": "^3.0.1",
|
|
133
|
+
"typescript": "^6.0.3",
|
|
134
|
+
"vite": "^8.0.9",
|
|
135
|
+
"vitest": "^4.1.4",
|
|
136
|
+
"wrangler": "^4.84.0"
|
|
137
|
+
},
|
|
138
|
+
"overrides": {
|
|
139
|
+
"@tootallnate/once": "3.0.1"
|
|
140
|
+
},
|
|
141
|
+
"engines": {
|
|
142
|
+
"node": ">=20.19.0"
|
|
143
|
+
},
|
|
144
|
+
"packageManager": "npm@11.12.0"
|
|
138
145
|
}
|
|
@@ -109,44 +109,6 @@ copy_example_configs() {
|
|
|
109
109
|
# Return to project root
|
|
110
110
|
cd ../..
|
|
111
111
|
|
|
112
|
-
# Copy worker source template files
|
|
113
|
-
echo -e "${YELLOW} Copying worker source template files...${NC}"
|
|
114
|
-
|
|
115
|
-
if [ -f "workers/user-worker/src/user-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/user-worker/src/user-worker.ts" ]; }; then
|
|
116
|
-
cp workers/user-worker/src/user-worker.example.ts workers/user-worker/src/user-worker.ts
|
|
117
|
-
echo -e "${GREEN} ✅ user-worker: user-worker.ts created from example${NC}"
|
|
118
|
-
elif [ -f "workers/user-worker/src/user-worker.ts" ]; then
|
|
119
|
-
echo -e "${YELLOW} ⚠️ user-worker: user-worker.ts already exists, skipping copy${NC}"
|
|
120
|
-
fi
|
|
121
|
-
|
|
122
|
-
if [ -f "workers/data-worker/src/data-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/data-worker/src/data-worker.ts" ]; }; then
|
|
123
|
-
cp workers/data-worker/src/data-worker.example.ts workers/data-worker/src/data-worker.ts
|
|
124
|
-
echo -e "${GREEN} ✅ data-worker: data-worker.ts created from example${NC}"
|
|
125
|
-
elif [ -f "workers/data-worker/src/data-worker.ts" ]; then
|
|
126
|
-
echo -e "${YELLOW} ⚠️ data-worker: data-worker.ts already exists, skipping copy${NC}"
|
|
127
|
-
fi
|
|
128
|
-
|
|
129
|
-
if [ -f "workers/audit-worker/src/audit-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/audit-worker/src/audit-worker.ts" ]; }; then
|
|
130
|
-
cp workers/audit-worker/src/audit-worker.example.ts workers/audit-worker/src/audit-worker.ts
|
|
131
|
-
echo -e "${GREEN} ✅ audit-worker: audit-worker.ts created from example${NC}"
|
|
132
|
-
elif [ -f "workers/audit-worker/src/audit-worker.ts" ]; then
|
|
133
|
-
echo -e "${YELLOW} ⚠️ audit-worker: audit-worker.ts already exists, skipping copy${NC}"
|
|
134
|
-
fi
|
|
135
|
-
|
|
136
|
-
if [ -f "workers/image-worker/src/image-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/image-worker/src/image-worker.ts" ]; }; then
|
|
137
|
-
cp workers/image-worker/src/image-worker.example.ts workers/image-worker/src/image-worker.ts
|
|
138
|
-
echo -e "${GREEN} ✅ image-worker: image-worker.ts created from example${NC}"
|
|
139
|
-
elif [ -f "workers/image-worker/src/image-worker.ts" ]; then
|
|
140
|
-
echo -e "${YELLOW} ⚠️ image-worker: image-worker.ts already exists, skipping copy${NC}"
|
|
141
|
-
fi
|
|
142
|
-
|
|
143
|
-
if [ -f "workers/pdf-worker/src/pdf-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/pdf-worker/src/pdf-worker.ts" ]; }; then
|
|
144
|
-
cp workers/pdf-worker/src/pdf-worker.example.ts workers/pdf-worker/src/pdf-worker.ts
|
|
145
|
-
echo -e "${GREEN} ✅ pdf-worker: pdf-worker.ts created from example${NC}"
|
|
146
|
-
elif [ -f "workers/pdf-worker/src/pdf-worker.ts" ]; then
|
|
147
|
-
echo -e "${YELLOW} ⚠️ pdf-worker: pdf-worker.ts already exists, skipping copy${NC}"
|
|
148
|
-
fi
|
|
149
|
-
|
|
150
112
|
# Copy main wrangler.toml from example
|
|
151
113
|
if [ -f "wrangler.toml.example" ] && { [ "$update_env" = "true" ] || [ ! -f "wrangler.toml" ]; }; then
|
|
152
114
|
cp wrangler.toml.example wrangler.toml
|
|
@@ -187,12 +149,6 @@ update_wrangler_configs() {
|
|
|
187
149
|
echo -e "${GREEN} ✅ audit-worker configuration updated${NC}"
|
|
188
150
|
fi
|
|
189
151
|
|
|
190
|
-
if [ -f "workers/audit-worker/src/audit-worker.ts" ]; then
|
|
191
|
-
echo -e "${YELLOW} Updating audit-worker source placeholders...${NC}"
|
|
192
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/audit-worker/src/audit-worker.ts
|
|
193
|
-
echo -e "${GREEN} ✅ audit-worker source placeholders updated${NC}"
|
|
194
|
-
fi
|
|
195
|
-
|
|
196
152
|
if [ -f "workers/data-worker/wrangler.jsonc" ]; then
|
|
197
153
|
echo -e "${YELLOW} Updating data-worker/wrangler.jsonc...${NC}"
|
|
198
154
|
sed -i "s/\"DATA_WORKER_NAME\"/\"$DATA_WORKER_NAME\"/g" workers/data-worker/wrangler.jsonc
|
|
@@ -201,12 +157,6 @@ update_wrangler_configs() {
|
|
|
201
157
|
echo -e "${GREEN} ✅ data-worker configuration updated${NC}"
|
|
202
158
|
fi
|
|
203
159
|
|
|
204
|
-
if [ -f "workers/data-worker/src/data-worker.ts" ]; then
|
|
205
|
-
echo -e "${YELLOW} Updating data-worker source placeholders...${NC}"
|
|
206
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/data-worker/src/data-worker.ts
|
|
207
|
-
echo -e "${GREEN} ✅ data-worker source placeholders updated${NC}"
|
|
208
|
-
fi
|
|
209
|
-
|
|
210
160
|
if [ -f "workers/image-worker/wrangler.jsonc" ]; then
|
|
211
161
|
echo -e "${YELLOW} Updating image-worker/wrangler.jsonc...${NC}"
|
|
212
162
|
sed -i "s/\"IMAGES_WORKER_NAME\"/\"$IMAGES_WORKER_NAME\"/g" workers/image-worker/wrangler.jsonc
|
|
@@ -215,12 +165,6 @@ update_wrangler_configs() {
|
|
|
215
165
|
echo -e "${GREEN} ✅ image-worker configuration updated${NC}"
|
|
216
166
|
fi
|
|
217
167
|
|
|
218
|
-
if [ -f "workers/image-worker/src/image-worker.ts" ]; then
|
|
219
|
-
echo -e "${YELLOW} Updating image-worker source placeholders...${NC}"
|
|
220
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/image-worker/src/image-worker.ts
|
|
221
|
-
echo -e "${GREEN} ✅ image-worker source placeholders updated${NC}"
|
|
222
|
-
fi
|
|
223
|
-
|
|
224
168
|
if [ -f "workers/pdf-worker/wrangler.jsonc" ]; then
|
|
225
169
|
echo -e "${YELLOW} Updating pdf-worker/wrangler.jsonc...${NC}"
|
|
226
170
|
sed -i "s/\"PDF_WORKER_NAME\"/\"$PDF_WORKER_NAME\"/g" workers/pdf-worker/wrangler.jsonc
|
|
@@ -228,12 +172,6 @@ update_wrangler_configs() {
|
|
|
228
172
|
echo -e "${GREEN} ✅ pdf-worker configuration updated${NC}"
|
|
229
173
|
fi
|
|
230
174
|
|
|
231
|
-
if [ -f "workers/pdf-worker/src/pdf-worker.ts" ]; then
|
|
232
|
-
echo -e "${YELLOW} Updating pdf-worker source placeholders...${NC}"
|
|
233
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/pdf-worker/src/pdf-worker.ts
|
|
234
|
-
echo -e "${GREEN} ✅ pdf-worker source placeholders updated${NC}"
|
|
235
|
-
fi
|
|
236
|
-
|
|
237
175
|
if [ -f "workers/user-worker/wrangler.jsonc" ]; then
|
|
238
176
|
echo -e "${YELLOW} Updating user-worker/wrangler.jsonc...${NC}"
|
|
239
177
|
sed -i "s/\"USER_WORKER_NAME\"/\"$USER_WORKER_NAME\"/g" workers/user-worker/wrangler.jsonc
|
|
@@ -244,12 +182,6 @@ update_wrangler_configs() {
|
|
|
244
182
|
echo -e "${GREEN} ✅ user-worker configuration updated${NC}"
|
|
245
183
|
fi
|
|
246
184
|
|
|
247
|
-
if [ -f "workers/user-worker/src/user-worker.ts" ]; then
|
|
248
|
-
echo -e "${YELLOW} Updating user-worker source placeholders...${NC}"
|
|
249
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/user-worker/src/user-worker.ts
|
|
250
|
-
echo -e "${GREEN} ✅ user-worker source placeholders updated${NC}"
|
|
251
|
-
fi
|
|
252
|
-
|
|
253
185
|
if [ -f "wrangler.toml" ]; then
|
|
254
186
|
echo -e "${YELLOW} Updating wrangler.toml...${NC}"
|
|
255
187
|
sed -i "s/\"PAGES_PROJECT_NAME\"/\"$PAGES_PROJECT_NAME\"/g" wrangler.toml
|
|
@@ -312,14 +312,8 @@ validate_generated_configs() {
|
|
|
312
312
|
assert_contains_literal "app/config/firebase.ts" "$APP_ID" "APP_ID missing in app/config/firebase.ts"
|
|
313
313
|
assert_contains_literal "app/config/firebase.ts" "$MEASUREMENT_ID" "MEASUREMENT_ID missing in app/config/firebase.ts"
|
|
314
314
|
|
|
315
|
-
assert_contains_literal "workers/audit-worker/src/audit-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in audit-worker source"
|
|
316
|
-
assert_contains_literal "workers/data-worker/src/data-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in data-worker source"
|
|
317
|
-
assert_contains_literal "workers/image-worker/src/image-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in image-worker source"
|
|
318
|
-
assert_contains_literal "workers/pdf-worker/src/pdf-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in pdf-worker source"
|
|
319
|
-
assert_contains_literal "workers/user-worker/src/user-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in user-worker source"
|
|
320
|
-
|
|
321
315
|
local placeholder_pattern
|
|
322
|
-
placeholder_pattern="(\"(ACCOUNT_ID|PAGES_PROJECT_NAME|PAGES_CUSTOM_DOMAIN|USER_WORKER_NAME|DATA_WORKER_NAME|AUDIT_WORKER_NAME|IMAGES_WORKER_NAME|PDF_WORKER_NAME|USER_WORKER_DOMAIN|DATA_WORKER_DOMAIN|AUDIT_WORKER_DOMAIN|IMAGES_WORKER_DOMAIN|PDF_WORKER_DOMAIN|DATA_BUCKET_NAME|AUDIT_BUCKET_NAME|FILES_BUCKET_NAME|KV_STORE_ID|MANIFEST_SIGNING_KEY_ID|MANIFEST_SIGNING_PUBLIC_KEY|EXPORT_ENCRYPTION_KEY_ID|EXPORT_ENCRYPTION_PUBLIC_KEY|YOUR_FIREBASE_API_KEY|YOUR_FIREBASE_AUTH_DOMAIN|YOUR_FIREBASE_PROJECT_ID|YOUR_FIREBASE_STORAGE_BUCKET|YOUR_FIREBASE_MESSAGING_SENDER_ID|YOUR_FIREBASE_APP_ID|YOUR_FIREBASE_MEASUREMENT_ID)\"
|
|
316
|
+
placeholder_pattern="(\"(ACCOUNT_ID|PAGES_PROJECT_NAME|PAGES_CUSTOM_DOMAIN|USER_WORKER_NAME|DATA_WORKER_NAME|AUDIT_WORKER_NAME|IMAGES_WORKER_NAME|PDF_WORKER_NAME|USER_WORKER_DOMAIN|DATA_WORKER_DOMAIN|AUDIT_WORKER_DOMAIN|IMAGES_WORKER_DOMAIN|PDF_WORKER_DOMAIN|DATA_BUCKET_NAME|AUDIT_BUCKET_NAME|FILES_BUCKET_NAME|KV_STORE_ID|MANIFEST_SIGNING_KEY_ID|MANIFEST_SIGNING_PUBLIC_KEY|EXPORT_ENCRYPTION_KEY_ID|EXPORT_ENCRYPTION_PUBLIC_KEY|YOUR_FIREBASE_API_KEY|YOUR_FIREBASE_AUTH_DOMAIN|YOUR_FIREBASE_PROJECT_ID|YOUR_FIREBASE_STORAGE_BUCKET|YOUR_FIREBASE_MESSAGING_SENDER_ID|YOUR_FIREBASE_APP_ID|YOUR_FIREBASE_MEASUREMENT_ID)\")"
|
|
323
317
|
|
|
324
318
|
local files_to_scan=(
|
|
325
319
|
"wrangler.toml"
|
|
@@ -328,11 +322,6 @@ validate_generated_configs() {
|
|
|
328
322
|
"workers/image-worker/wrangler.jsonc"
|
|
329
323
|
"workers/pdf-worker/wrangler.jsonc"
|
|
330
324
|
"workers/user-worker/wrangler.jsonc"
|
|
331
|
-
"workers/audit-worker/src/audit-worker.ts"
|
|
332
|
-
"workers/data-worker/src/data-worker.ts"
|
|
333
|
-
"workers/image-worker/src/image-worker.ts"
|
|
334
|
-
"workers/pdf-worker/src/pdf-worker.ts"
|
|
335
|
-
"workers/user-worker/src/user-worker.ts"
|
|
336
325
|
"app/config/config.json"
|
|
337
326
|
"app/config/firebase.ts"
|
|
338
327
|
)
|
package/tsconfig.json
CHANGED
|
@@ -2,24 +2,13 @@ import { hasValidHeader } from './config';
|
|
|
2
2
|
import { handleAuditRequest } from './handlers/audit-routes';
|
|
3
3
|
import type { CreateResponse, Env } from './types';
|
|
4
4
|
|
|
5
|
-
const corsHeaders: Record<string, string> = {
|
|
6
|
-
'Access-Control-Allow-Origin': 'PAGES_CUSTOM_DOMAIN',
|
|
7
|
-
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
8
|
-
'Access-Control-Allow-Headers': 'Content-Type, X-Custom-Auth-Key',
|
|
9
|
-
'Content-Type': 'application/json'
|
|
10
|
-
};
|
|
11
|
-
|
|
12
5
|
const createWorkerResponse: CreateResponse = (data, status: number = 200): Response => new Response(
|
|
13
6
|
JSON.stringify(data),
|
|
14
|
-
{ status, headers:
|
|
7
|
+
{ status, headers: { 'Content-Type': 'application/json' } }
|
|
15
8
|
);
|
|
16
9
|
|
|
17
10
|
export default {
|
|
18
11
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
19
|
-
if (request.method === 'OPTIONS') {
|
|
20
|
-
return new Response(null, { headers: corsHeaders });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
12
|
if (!hasValidHeader(request, env)) {
|
|
24
13
|
return createWorkerResponse({ error: 'Forbidden' }, 403);
|
|
25
14
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-worker",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.8",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"deploy": "wrangler deploy",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"start": "wrangler dev"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
+
"@cloudflare/vitest-pool-workers": "^0.14.8",
|
|
11
12
|
"wrangler": "^4.84.0"
|
|
12
13
|
}
|
|
13
14
|
}
|
|
@@ -14,24 +14,13 @@ import {
|
|
|
14
14
|
import { handleStorageRequest } from './handlers/storage-routes';
|
|
15
15
|
import type { CreateResponse, Env } from './types';
|
|
16
16
|
|
|
17
|
-
const corsHeaders: Record<string, string> = {
|
|
18
|
-
'Access-Control-Allow-Origin': 'PAGES_CUSTOM_DOMAIN',
|
|
19
|
-
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
|
20
|
-
'Access-Control-Allow-Headers': 'Content-Type, X-Custom-Auth-Key',
|
|
21
|
-
'Content-Type': 'application/json'
|
|
22
|
-
};
|
|
23
|
-
|
|
24
17
|
const createWorkerResponse: CreateResponse = (data, status: number = 200): Response => new Response(
|
|
25
18
|
JSON.stringify(data),
|
|
26
|
-
{ status, headers:
|
|
19
|
+
{ status, headers: { 'Content-Type': 'application/json' } }
|
|
27
20
|
);
|
|
28
21
|
|
|
29
22
|
export default {
|
|
30
23
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
31
|
-
if (request.method === 'OPTIONS') {
|
|
32
|
-
return new Response(null, { headers: corsHeaders });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
24
|
if (!hasValidHeader(request, env)) {
|
|
36
25
|
return createWorkerResponse({ error: 'Forbidden' }, 403);
|
|
37
26
|
}
|
|
@@ -12,8 +12,7 @@ export async function handleImageServing(
|
|
|
12
12
|
request: Request,
|
|
13
13
|
env: Env,
|
|
14
14
|
fileId: string,
|
|
15
|
-
createJsonResponse: CreateImageWorkerResponse
|
|
16
|
-
corsHeaders: Record<string, string>
|
|
15
|
+
createJsonResponse: CreateImageWorkerResponse
|
|
17
16
|
): Promise<Response> {
|
|
18
17
|
const requestUrl = new URL(request.url);
|
|
19
18
|
const hasSignedToken = requestUrl.searchParams.has('st');
|
|
@@ -56,7 +55,6 @@ export async function handleImageServing(
|
|
|
56
55
|
return new Response(plaintext, {
|
|
57
56
|
status: 200,
|
|
58
57
|
headers: {
|
|
59
|
-
...corsHeaders,
|
|
60
58
|
'Cache-Control': 'no-store',
|
|
61
59
|
'Content-Type': contentType,
|
|
62
60
|
'Content-Disposition': contentDisposition
|
|
@@ -1,31 +1,18 @@
|
|
|
1
1
|
import { routeImageWorkerRequest } from './router';
|
|
2
2
|
import type { APIResponse, Env } from './types';
|
|
3
3
|
|
|
4
|
-
const corsHeaders: Record<string, string> = {
|
|
5
|
-
'Access-Control-Allow-Origin': 'PAGES_CUSTOM_DOMAIN',
|
|
6
|
-
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
|
|
7
|
-
'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Custom-Auth-Key'
|
|
8
|
-
};
|
|
9
|
-
|
|
10
4
|
const createJsonResponse = (data: APIResponse, status: number = 200): Response => new Response(
|
|
11
5
|
JSON.stringify(data),
|
|
12
6
|
{
|
|
13
7
|
status,
|
|
14
|
-
headers: {
|
|
15
|
-
...corsHeaders,
|
|
16
|
-
'Content-Type': 'application/json'
|
|
17
|
-
}
|
|
8
|
+
headers: { 'Content-Type': 'application/json' }
|
|
18
9
|
}
|
|
19
10
|
);
|
|
20
11
|
|
|
21
12
|
export default {
|
|
22
13
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
23
|
-
if (request.method === 'OPTIONS') {
|
|
24
|
-
return new Response(null, { headers: corsHeaders });
|
|
25
|
-
}
|
|
26
|
-
|
|
27
14
|
try {
|
|
28
|
-
return await routeImageWorkerRequest(request, env, createJsonResponse
|
|
15
|
+
return await routeImageWorkerRequest(request, env, createJsonResponse);
|
|
29
16
|
} catch (error) {
|
|
30
17
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
31
18
|
return createJsonResponse({ error: errorMessage }, 500);
|
|
@@ -8,8 +8,7 @@ import { parsePathSegments } from './utils/path-utils';
|
|
|
8
8
|
export async function routeImageWorkerRequest(
|
|
9
9
|
request: Request,
|
|
10
10
|
env: Env,
|
|
11
|
-
createJsonResponse: CreateImageWorkerResponse
|
|
12
|
-
corsHeaders: Record<string, string>
|
|
11
|
+
createJsonResponse: CreateImageWorkerResponse
|
|
13
12
|
): Promise<Response> {
|
|
14
13
|
const requestUrl = new URL(request.url);
|
|
15
14
|
const pathSegments = parsePathSegments(requestUrl.pathname);
|
|
@@ -36,7 +35,7 @@ export async function routeImageWorkerRequest(
|
|
|
36
35
|
return createJsonResponse({ error: 'Image ID is required' }, 400);
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
return handleImageServing(request, env, fileId, createJsonResponse
|
|
38
|
+
return handleImageServing(request, env, fileId, createJsonResponse);
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
case 'DELETE': {
|
|
@@ -40,12 +40,6 @@ const reportModuleLoaders: Record<string, () => Promise<ReportModule>> = {
|
|
|
40
40
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
const corsHeaders: Record<string, string> = {
|
|
44
|
-
'Access-Control-Allow-Origin': 'PAGES_CUSTOM_DOMAIN',
|
|
45
|
-
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
46
|
-
'Access-Control-Allow-Headers': 'Content-Type, X-Custom-Auth-Key',
|
|
47
|
-
};
|
|
48
|
-
|
|
49
43
|
const hasValidHeader = (request: Request, env: Env): boolean =>
|
|
50
44
|
request.headers.get('X-Custom-Auth-Key') === env.PDF_WORKER_AUTH;
|
|
51
45
|
|
|
@@ -60,7 +54,7 @@ function isTimeoutError(error: unknown): boolean {
|
|
|
60
54
|
function jsonResponse(body: unknown, status: number): Response {
|
|
61
55
|
return new Response(JSON.stringify(body), {
|
|
62
56
|
status,
|
|
63
|
-
headers: {
|
|
57
|
+
headers: { 'content-type': 'application/json' },
|
|
64
58
|
});
|
|
65
59
|
}
|
|
66
60
|
|
|
@@ -190,10 +184,6 @@ async function renderPdfViaRestEndpoint(env: Env, html: string, pdfOptions: Repo
|
|
|
190
184
|
responseHeaders.set('cache-control', 'no-store');
|
|
191
185
|
}
|
|
192
186
|
|
|
193
|
-
for (const [headerName, headerValue] of Object.entries(corsHeaders)) {
|
|
194
|
-
responseHeaders.set(headerName, headerValue);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
187
|
return new Response(endpointResponse.body, {
|
|
198
188
|
status: endpointResponse.status,
|
|
199
189
|
statusText: endpointResponse.statusText,
|
|
@@ -203,10 +193,6 @@ async function renderPdfViaRestEndpoint(env: Env, html: string, pdfOptions: Repo
|
|
|
203
193
|
|
|
204
194
|
export default {
|
|
205
195
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
206
|
-
if (request.method === 'OPTIONS') {
|
|
207
|
-
return new Response(null, { headers: corsHeaders });
|
|
208
|
-
}
|
|
209
|
-
|
|
210
196
|
if (!hasValidHeader(request, env)) {
|
|
211
197
|
return jsonResponse({ error: 'Forbidden' }, 403);
|
|
212
198
|
}
|
|
@@ -5,56 +5,47 @@ import type {
|
|
|
5
5
|
AccountDeletionProgressEvent,
|
|
6
6
|
DeleteCasesRequest,
|
|
7
7
|
Env,
|
|
8
|
-
ResponseHeaders,
|
|
9
8
|
UserData,
|
|
10
9
|
UserRequestData
|
|
11
10
|
} from '../types';
|
|
12
11
|
|
|
13
|
-
function createJsonResponse(data: unknown,
|
|
12
|
+
function createJsonResponse(data: unknown, status: number = 200): Response {
|
|
14
13
|
return new Response(JSON.stringify(data), {
|
|
15
14
|
status,
|
|
16
|
-
headers: {
|
|
17
|
-
...headers,
|
|
18
|
-
'Content-Type': 'application/json; charset=utf-8'
|
|
19
|
-
}
|
|
15
|
+
headers: { 'Content-Type': 'application/json; charset=utf-8' }
|
|
20
16
|
});
|
|
21
17
|
}
|
|
22
18
|
|
|
23
|
-
function createTextResponse(message: string,
|
|
19
|
+
function createTextResponse(message: string, status: number): Response {
|
|
24
20
|
return new Response(message, {
|
|
25
21
|
status,
|
|
26
|
-
headers: {
|
|
27
|
-
...headers,
|
|
28
|
-
'Content-Type': 'text/plain; charset=utf-8'
|
|
29
|
-
}
|
|
22
|
+
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
|
|
30
23
|
});
|
|
31
24
|
}
|
|
32
25
|
|
|
33
26
|
export async function handleGetUser(
|
|
34
27
|
env: Env,
|
|
35
|
-
userUid: string
|
|
36
|
-
corsHeaders: ResponseHeaders
|
|
28
|
+
userUid: string
|
|
37
29
|
): Promise<Response> {
|
|
38
30
|
try {
|
|
39
31
|
const userData = await readUserRecord(env, userUid);
|
|
40
32
|
if (userData === null) {
|
|
41
|
-
return createTextResponse('User not found',
|
|
33
|
+
return createTextResponse('User not found', 404);
|
|
42
34
|
}
|
|
43
35
|
|
|
44
|
-
return createJsonResponse(userData
|
|
36
|
+
return createJsonResponse(userData);
|
|
45
37
|
} catch (error) {
|
|
46
38
|
const errorMessage = error instanceof Error ? error.message : 'Unknown user data read error';
|
|
47
39
|
console.error('Failed to get user data:', { uid: userUid, reason: errorMessage });
|
|
48
40
|
|
|
49
|
-
return createTextResponse('Failed to get user data',
|
|
41
|
+
return createTextResponse('Failed to get user data', 500);
|
|
50
42
|
}
|
|
51
43
|
}
|
|
52
44
|
|
|
53
45
|
export async function handleAddUser(
|
|
54
46
|
request: Request,
|
|
55
47
|
env: Env,
|
|
56
|
-
userUid: string
|
|
57
|
-
corsHeaders: ResponseHeaders
|
|
48
|
+
userUid: string
|
|
58
49
|
): Promise<Response> {
|
|
59
50
|
try {
|
|
60
51
|
const requestData: UserRequestData = await request.json();
|
|
@@ -96,16 +87,15 @@ export async function handleAddUser(
|
|
|
96
87
|
|
|
97
88
|
await writeUserRecord(env, userUid, userData);
|
|
98
89
|
|
|
99
|
-
return createJsonResponse(userData,
|
|
90
|
+
return createJsonResponse(userData, existingUser !== null ? 200 : 201);
|
|
100
91
|
} catch {
|
|
101
|
-
return createTextResponse('Failed to save user data',
|
|
92
|
+
return createTextResponse('Failed to save user data', 500);
|
|
102
93
|
}
|
|
103
94
|
}
|
|
104
95
|
|
|
105
96
|
export async function handleDeleteUser(
|
|
106
97
|
env: Env,
|
|
107
|
-
userUid: string
|
|
108
|
-
corsHeaders: ResponseHeaders
|
|
98
|
+
userUid: string
|
|
109
99
|
): Promise<Response> {
|
|
110
100
|
try {
|
|
111
101
|
const result = await executeUserDeletion(env, userUid);
|
|
@@ -113,29 +103,27 @@ export async function handleDeleteUser(
|
|
|
113
103
|
return createJsonResponse({
|
|
114
104
|
success: result.success,
|
|
115
105
|
message: result.message
|
|
116
|
-
}
|
|
106
|
+
});
|
|
117
107
|
} catch (error) {
|
|
118
108
|
console.error('Delete user error:', error);
|
|
119
109
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
120
110
|
|
|
121
111
|
if (errorMessage === 'User not found') {
|
|
122
|
-
return createTextResponse('User not found',
|
|
112
|
+
return createTextResponse('User not found', 404);
|
|
123
113
|
}
|
|
124
114
|
|
|
125
115
|
return createJsonResponse({
|
|
126
116
|
success: false,
|
|
127
117
|
message: 'Failed to delete user account'
|
|
128
|
-
},
|
|
118
|
+
}, 500);
|
|
129
119
|
}
|
|
130
120
|
}
|
|
131
121
|
|
|
132
122
|
export function handleDeleteUserWithProgress(
|
|
133
123
|
env: Env,
|
|
134
|
-
userUid: string
|
|
135
|
-
corsHeaders: ResponseHeaders
|
|
124
|
+
userUid: string
|
|
136
125
|
): Response {
|
|
137
|
-
const sseHeaders
|
|
138
|
-
...corsHeaders,
|
|
126
|
+
const sseHeaders = {
|
|
139
127
|
'Content-Type': 'text/event-stream; charset=utf-8',
|
|
140
128
|
'Cache-Control': 'no-cache, no-transform',
|
|
141
129
|
Connection: 'keep-alive'
|
|
@@ -182,14 +170,13 @@ export function handleDeleteUserWithProgress(
|
|
|
182
170
|
export async function handleAddCases(
|
|
183
171
|
request: Request,
|
|
184
172
|
env: Env,
|
|
185
|
-
userUid: string
|
|
186
|
-
corsHeaders: ResponseHeaders
|
|
173
|
+
userUid: string
|
|
187
174
|
): Promise<Response> {
|
|
188
175
|
try {
|
|
189
176
|
const { cases = [] }: AddCasesRequest = await request.json();
|
|
190
177
|
const userData = await readUserRecord(env, userUid);
|
|
191
178
|
if (!userData) {
|
|
192
|
-
return createTextResponse('User not found',
|
|
179
|
+
return createTextResponse('User not found', 404);
|
|
193
180
|
}
|
|
194
181
|
|
|
195
182
|
const existingCases = userData.cases || [];
|
|
@@ -201,31 +188,30 @@ export async function handleAddCases(
|
|
|
201
188
|
userData.updatedAt = new Date().toISOString();
|
|
202
189
|
await writeUserRecord(env, userUid, userData);
|
|
203
190
|
|
|
204
|
-
return createJsonResponse(userData
|
|
191
|
+
return createJsonResponse(userData);
|
|
205
192
|
} catch {
|
|
206
|
-
return createTextResponse('Failed to add cases',
|
|
193
|
+
return createTextResponse('Failed to add cases', 500);
|
|
207
194
|
}
|
|
208
195
|
}
|
|
209
196
|
|
|
210
197
|
export async function handleDeleteCases(
|
|
211
198
|
request: Request,
|
|
212
199
|
env: Env,
|
|
213
|
-
userUid: string
|
|
214
|
-
corsHeaders: ResponseHeaders
|
|
200
|
+
userUid: string
|
|
215
201
|
): Promise<Response> {
|
|
216
202
|
try {
|
|
217
203
|
const { casesToDelete }: DeleteCasesRequest = await request.json();
|
|
218
204
|
const userData = await readUserRecord(env, userUid);
|
|
219
205
|
if (!userData) {
|
|
220
|
-
return createTextResponse('User not found',
|
|
206
|
+
return createTextResponse('User not found', 404);
|
|
221
207
|
}
|
|
222
208
|
|
|
223
209
|
userData.cases = userData.cases.filter((caseItem) => !casesToDelete.includes(caseItem.caseNumber));
|
|
224
210
|
userData.updatedAt = new Date().toISOString();
|
|
225
211
|
await writeUserRecord(env, userUid, userData);
|
|
226
212
|
|
|
227
|
-
return createJsonResponse(userData
|
|
213
|
+
return createJsonResponse(userData);
|
|
228
214
|
} catch {
|
|
229
|
-
return createTextResponse('Failed to delete cases',
|
|
215
|
+
return createTextResponse('Failed to delete cases', 500);
|
|
230
216
|
}
|
|
231
217
|
}
|
|
@@ -10,28 +10,15 @@ import {
|
|
|
10
10
|
} from './handlers/user-routes';
|
|
11
11
|
import type { Env } from './types';
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
'Access-Control-Allow-Origin': 'PAGES_CUSTOM_DOMAIN',
|
|
15
|
-
'Access-Control-Allow-Methods': 'GET, PUT, DELETE, OPTIONS',
|
|
16
|
-
'Access-Control-Allow-Headers': 'Content-Type, X-Custom-Auth-Key'
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
function createTextResponse(message: string, status: number, headers: Record<string, string>): Response {
|
|
13
|
+
function createTextResponse(message: string, status: number): Response {
|
|
20
14
|
return new Response(message, {
|
|
21
15
|
status,
|
|
22
|
-
headers: {
|
|
23
|
-
...headers,
|
|
24
|
-
'Content-Type': 'text/plain; charset=utf-8'
|
|
25
|
-
}
|
|
16
|
+
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
|
|
26
17
|
});
|
|
27
18
|
}
|
|
28
19
|
|
|
29
20
|
export default {
|
|
30
21
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
31
|
-
if (request.method === 'OPTIONS') {
|
|
32
|
-
return new Response(null, { headers: corsHeaders });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
22
|
try {
|
|
36
23
|
await authenticate(request, env);
|
|
37
24
|
|
|
@@ -48,15 +35,15 @@ export default {
|
|
|
48
35
|
const isCasesEndpoint = parts[2] === USER_CASES_SEGMENT;
|
|
49
36
|
|
|
50
37
|
if (!userUid) {
|
|
51
|
-
return createTextResponse('Not Found', 404
|
|
38
|
+
return createTextResponse('Not Found', 404);
|
|
52
39
|
}
|
|
53
40
|
|
|
54
41
|
// Handle regular cases endpoint
|
|
55
42
|
if (isCasesEndpoint) {
|
|
56
43
|
switch (request.method) {
|
|
57
|
-
case 'PUT': return handleAddCases(request, env, userUid
|
|
58
|
-
case 'DELETE': return handleDeleteCases(request, env, userUid
|
|
59
|
-
default: return createTextResponse('Method not allowed', 405
|
|
44
|
+
case 'PUT': return handleAddCases(request, env, userUid);
|
|
45
|
+
case 'DELETE': return handleDeleteCases(request, env, userUid);
|
|
46
|
+
default: return createTextResponse('Method not allowed', 405);
|
|
60
47
|
}
|
|
61
48
|
}
|
|
62
49
|
|
|
@@ -65,24 +52,24 @@ export default {
|
|
|
65
52
|
const streamProgress = url.searchParams.get('stream') === 'true' || acceptsEventStream;
|
|
66
53
|
|
|
67
54
|
switch (request.method) {
|
|
68
|
-
case 'GET': return handleGetUser(env, userUid
|
|
69
|
-
case 'PUT': return handleAddUser(request, env, userUid
|
|
55
|
+
case 'GET': return handleGetUser(env, userUid);
|
|
56
|
+
case 'PUT': return handleAddUser(request, env, userUid);
|
|
70
57
|
case 'DELETE': return streamProgress
|
|
71
|
-
? handleDeleteUserWithProgress(env, userUid
|
|
72
|
-
: handleDeleteUser(env, userUid
|
|
73
|
-
default: return createTextResponse('Method not allowed', 405
|
|
58
|
+
? handleDeleteUserWithProgress(env, userUid)
|
|
59
|
+
: handleDeleteUser(env, userUid);
|
|
60
|
+
default: return createTextResponse('Method not allowed', 405);
|
|
74
61
|
}
|
|
75
62
|
} catch (error) {
|
|
76
63
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
77
64
|
if (errorMessage === 'Unauthorized') {
|
|
78
|
-
return createTextResponse('Forbidden', 403
|
|
65
|
+
return createTextResponse('Forbidden', 403);
|
|
79
66
|
}
|
|
80
67
|
|
|
81
68
|
if (errorMessage === 'User KV encryption is not fully configured') {
|
|
82
|
-
return createTextResponse(errorMessage, 500
|
|
69
|
+
return createTextResponse(errorMessage, 500);
|
|
83
70
|
}
|
|
84
71
|
|
|
85
|
-
return createTextResponse('Internal Server Error', 500
|
|
72
|
+
return createTextResponse('Internal Server Error', 500);
|
|
86
73
|
}
|
|
87
74
|
}
|
|
88
75
|
};
|