@preventive/triage 1.0.0-alpha.3 → 1.0.0-alpha.30
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/LICENSE-APACHE +202 -0
- package/api/reap.ts +17 -0
- package/cli.js +6 -0
- package/client/finding-link.js +305 -0
- package/client/linked-findings.d.ts +1 -0
- package/client/linked-findings.js +111 -0
- package/common/bundle-commit.d.ts +1 -0
- package/common/bundle-commit.js +4 -0
- package/common/bundle-metadata.d.ts +10 -0
- package/common/bundle-metadata.js +182 -0
- package/common/bundle-reasons.d.ts +2 -0
- package/common/bundle-reasons.js +21 -0
- package/common/bundle-source-links.d.ts +5 -0
- package/common/bundle-source-links.js +82 -0
- package/common/bundle-sources.d.ts +3 -0
- package/common/bundle-sources.js +284 -0
- package/common/bundle-stats.js +41 -0
- package/common/bundle-tabs.js +1 -0
- package/common/code-language.js +51 -0
- package/common/default-scan-models.ts +30 -0
- package/common/finding-id.js +47 -0
- package/common/github-issue-labels.d.ts +1 -0
- package/common/github-issue-labels.js +11 -0
- package/common/github-pr.ts +56 -0
- package/common/managed/comments.ts +34 -0
- package/common/managed/permissions.ts +35 -0
- package/common/managed/report-content.ts +42 -0
- package/common/managed/report-filter.ts +108 -0
- package/common/managed/roles.ts +28 -0
- package/common/managed/routes.d.ts +2 -0
- package/common/managed/routes.js +124 -0
- package/common/managed/scan-models.ts +6 -0
- package/common/managed/triage.ts +83 -0
- package/common/save-error-reason.ts +20 -7
- package/common/scan-server.ts +13 -0
- package/common/server-info.ts +35 -0
- package/common/utf8.d.ts +3 -0
- package/common/utf8.js +45 -0
- package/out/brotli-fallback.js +3 -3
- package/out/client-managed-import.js +81 -0
- package/out/client-managed.js +167 -0
- package/out/client-sync.js +16 -13
- package/out/github-issue-authorized.html +3 -0
- package/out/github-issue-authorized.js +1 -0
- package/out/graph.js +30 -4
- package/out/index.html +55 -8
- package/out/prism.js +2 -2
- package/out/stasis.svg +20 -0
- package/out/terminal.js +273 -39
- package/out/view.css +1 -1
- package/out/view.js +259 -63
- package/package.json +205 -57
- package/server-common/database-config.ts +16 -0
- package/server-common/initialize.ts +18 -0
- package/server-common/npm-advisories.ts +101 -0
- package/{server → server-common}/origin.ts +5 -5
- package/server-common/reap.ts +48 -0
- package/server-common/scan-config.ts +19 -0
- package/server-common/standalone.ts +29 -0
- package/server-common/storage-crypto.ts +182 -0
- package/server-common/storage-log.ts +38 -0
- package/server-common/vercel-blob.ts +102 -0
- package/server-e2e/app.ts +486 -0
- package/{server → server-e2e}/auth.ts +5 -1
- package/{server → server-e2e}/bus-receiver.ts +2 -1
- package/{server → server-e2e}/cli.js +9 -4
- package/{server → server-e2e}/config.ts +56 -35
- package/{server → server-e2e}/db-neon.ts +2 -2
- package/{server → server-e2e}/db-revision-sql.ts +1 -1
- package/{server → server-e2e}/db-stmt.ts +2 -2
- package/{server → server-e2e}/db.ts +7 -7
- package/{server → server-e2e}/http.ts +110 -12
- package/{server → server-e2e}/hub.ts +40 -9
- package/server-e2e/index.ts +17 -0
- package/server-e2e/lifecycle.ts +95 -0
- package/{server → server-e2e}/neon-driver.ts +2 -2
- package/{server → server-e2e}/npm-proxy.ts +11 -144
- package/{server → server-e2e}/objstore/blob-fs.ts +2 -2
- package/{server → server-e2e}/objstore/blob-vercel.ts +13 -117
- package/{server → server-e2e}/objstore/blob.ts +9 -2
- package/server-e2e/objstore/fetch-mint-guard.ts +74 -0
- package/{server → server-e2e}/objstore/handlers.ts +9 -8
- package/{server → server-e2e}/objstore/init.ts +35 -18
- package/{server → server-e2e}/objstore/reaper.ts +31 -11
- package/server-e2e/objstore/rest-deny.ts +28 -0
- package/server-e2e/objstore/rest-mint.ts +224 -0
- package/{server → server-e2e}/objstore/rest.ts +58 -33
- package/{server → server-e2e}/objstore/sign.ts +105 -0
- package/{server → server-e2e}/objstore/store-neon.ts +6 -10
- package/{server → server-e2e}/objstore/store.ts +7 -7
- package/{server → server-e2e}/objstore/tokens.ts +1 -1
- package/{server → server-e2e}/pubsub.ts +12 -9
- package/{server → server-e2e}/sign.ts +4 -4
- package/{server → server-e2e}/sse-server.ts +102 -68
- package/{server → server-e2e}/sse-session.ts +28 -8
- package/{server → server-e2e}/static.ts +31 -21
- package/server-e2e/sync-handlers.ts +408 -0
- package/{server → server-e2e}/util.ts +9 -0
- package/{server → server-e2e}/ws-server.ts +20 -9
- package/server-managed/activity.ts +231 -0
- package/server-managed/avatar-store.ts +12 -0
- package/server-managed/blob-store.ts +17 -0
- package/server-managed/brotli.ts +10 -0
- package/server-managed/bundle-advisories.ts +53 -0
- package/server-managed/bundle-advisory-inventory.ts +75 -0
- package/server-managed/bundle-build-diagnostics.d.ts +10 -0
- package/server-managed/bundle-build-diagnostics.js +23 -0
- package/server-managed/bundle-build-leases.ts +41 -0
- package/server-managed/bundle-build-worker.js +54 -0
- package/server-managed/bundle-build.ts +168 -0
- package/server-managed/bundle-cache.ts +166 -0
- package/server-managed/bundle-catalog.ts +29 -0
- package/server-managed/bundle-store.ts +24 -0
- package/server-managed/bundle-summary-cache.ts +116 -0
- package/server-managed/bundle.ts +104 -0
- package/server-managed/cache-storage.ts +19 -0
- package/server-managed/cli.js +21 -0
- package/server-managed/combined.ts +46 -0
- package/server-managed/comments.ts +151 -0
- package/server-managed/config.ts +149 -0
- package/server-managed/content-access.ts +15 -0
- package/server-managed/crypto.ts +25 -0
- package/server-managed/db-methods.ts +1517 -0
- package/server-managed/db-neon.ts +277 -0
- package/server-managed/db-schema.ts +206 -0
- package/server-managed/db-table-names.ts +22 -0
- package/server-managed/db.ts +120 -0
- package/server-managed/github-app.ts +385 -0
- package/server-managed/github-errors.ts +49 -0
- package/server-managed/github-issue-oauth.ts +48 -0
- package/server-managed/github-issues.ts +152 -0
- package/server-managed/github-metadata.ts +98 -0
- package/server-managed/github-oauth.ts +199 -0
- package/server-managed/github-pulls.ts +227 -0
- package/server-managed/http-response.ts +18 -0
- package/server-managed/http.ts +2350 -0
- package/server-managed/import-triage.ts +51 -0
- package/server-managed/index.ts +175 -0
- package/server-managed/managed-issues.ts +47 -0
- package/server-managed/management-catalog.ts +45 -0
- package/server-managed/management.ts +86 -0
- package/server-managed/object-storage-disk.ts +144 -0
- package/server-managed/object-storage-vercel.ts +60 -0
- package/server-managed/object-storage.ts +71 -0
- package/server-managed/package-entry-points.ts +51 -0
- package/server-managed/public-workspace.ts +146 -0
- package/server-managed/repo-path.ts +21 -0
- package/server-managed/report-migration.ts +35 -0
- package/server-managed/report-query.ts +10 -0
- package/server-managed/report-response.ts +16 -0
- package/server-managed/report-sources.ts +166 -0
- package/server-managed/repository-browser.ts +139 -0
- package/server-managed/repository-discovery.ts +82 -0
- package/server-managed/repository-policy.ts +27 -0
- package/server-managed/revisions.ts +35 -0
- package/server-managed/session.ts +78 -0
- package/server-managed/slugs.ts +38 -0
- package/server-managed/solidity-entry-points.ts +69 -0
- package/server-managed/sql-postgres.ts +31 -0
- package/server-managed/sql.ts +72 -0
- package/server-managed/static.ts +28 -0
- package/server-managed/storage-command.ts +16 -0
- package/server-managed/storage-db.ts +175 -0
- package/server-managed/storage-encryption.ts +211 -0
- package/server-managed/storage-maintenance.ts +223 -0
- package/server-managed/storage-payload.ts +72 -0
- package/server-managed/storage-stores.ts +81 -0
- package/server-managed/storage.ts +58 -0
- package/server-managed/team-catalog.ts +7 -0
- package/server-managed/team-feed.ts +173 -0
- package/server-managed/team-reports.ts +219 -0
- package/server-managed/triage-response.ts +16 -0
- package/server-managed/uploads.ts +65 -0
- package/server-managed/workspace-shares.ts +162 -0
- package/server.ts +50 -0
- package/server/index.ts +0 -477
- package/server/lifecycle.ts +0 -204
- package/server/sync-handlers.ts +0 -320
- /package/{LICENSE → LICENSE-MIT} +0 -0
- /package/{server → server-e2e}/config.example.json +0 -0
- /package/{server → server-e2e}/objstore/fs.ts +0 -0
- /package/{server → server-e2e}/peer.ts +0 -0
- /package/{server → server-e2e}/validation.ts +0 -0
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@preventive/triage",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.30",
|
|
4
4
|
"description": "Client & relay server for triaging of automated reports",
|
|
5
|
-
"license": "MIT",
|
|
5
|
+
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Nikita Skovoroda",
|
|
8
8
|
"email": "chalkerx@gmail.com",
|
|
@@ -29,63 +29,198 @@
|
|
|
29
29
|
"#client/sync-host.js": "./client/sync-host.js"
|
|
30
30
|
},
|
|
31
31
|
"exports": {
|
|
32
|
-
"./
|
|
32
|
+
"./reap": "./api/reap.ts",
|
|
33
|
+
"./server": "./server.ts",
|
|
34
|
+
"./server-e2e": "./server-e2e/index.ts",
|
|
35
|
+
"./bundle-build-worker": "./server-managed/bundle-build-worker.js",
|
|
33
36
|
"./strip-types-loader": "./strip-types-loader.js",
|
|
34
37
|
"./package.json": "./package.json"
|
|
35
38
|
},
|
|
36
39
|
"bin": {
|
|
37
|
-
"triage-server": "
|
|
40
|
+
"triage-server": "cli.js",
|
|
41
|
+
"triage-e2e-server": "server-e2e/cli.js",
|
|
42
|
+
"triage-managed-server": "server-managed/cli.js"
|
|
38
43
|
},
|
|
39
44
|
"files": [
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"server
|
|
45
|
-
"server/
|
|
46
|
-
"server/
|
|
47
|
-
"server/
|
|
48
|
-
"server/
|
|
49
|
-
"server/
|
|
50
|
-
"server/
|
|
51
|
-
"server/
|
|
52
|
-
"server/
|
|
53
|
-
"server/
|
|
54
|
-
"server/
|
|
55
|
-
"server/
|
|
56
|
-
"server/
|
|
57
|
-
"server/
|
|
58
|
-
"server/
|
|
59
|
-
"server/
|
|
60
|
-
"server/objstore/
|
|
61
|
-
"server/objstore/
|
|
62
|
-
"server/objstore/
|
|
63
|
-
"server/objstore/
|
|
64
|
-
"server/objstore/
|
|
65
|
-
"server/objstore/
|
|
66
|
-
"server/
|
|
67
|
-
"server/
|
|
68
|
-
"server/
|
|
69
|
-
"server/
|
|
70
|
-
"server/
|
|
71
|
-
"server/
|
|
72
|
-
"server/
|
|
73
|
-
"server/
|
|
74
|
-
"server/
|
|
75
|
-
"server/
|
|
76
|
-
"server/
|
|
77
|
-
"server/
|
|
45
|
+
"LICENSE-APACHE",
|
|
46
|
+
"LICENSE-MIT",
|
|
47
|
+
"api/reap.ts",
|
|
48
|
+
"cli.js",
|
|
49
|
+
"server.ts",
|
|
50
|
+
"server-e2e/app.ts",
|
|
51
|
+
"server-e2e/auth.ts",
|
|
52
|
+
"server-e2e/bus-receiver.ts",
|
|
53
|
+
"server-e2e/cli.js",
|
|
54
|
+
"server-e2e/config.ts",
|
|
55
|
+
"server-e2e/db-neon.ts",
|
|
56
|
+
"server-e2e/db-revision-sql.ts",
|
|
57
|
+
"server-e2e/db-stmt.ts",
|
|
58
|
+
"server-e2e/db.ts",
|
|
59
|
+
"server-e2e/http.ts",
|
|
60
|
+
"server-e2e/hub.ts",
|
|
61
|
+
"server-e2e/index.ts",
|
|
62
|
+
"server-e2e/lifecycle.ts",
|
|
63
|
+
"server-e2e/neon-driver.ts",
|
|
64
|
+
"server-e2e/npm-proxy.ts",
|
|
65
|
+
"server-e2e/objstore/blob-fs.ts",
|
|
66
|
+
"server-e2e/objstore/blob-vercel.ts",
|
|
67
|
+
"server-e2e/objstore/blob.ts",
|
|
68
|
+
"server-e2e/objstore/fetch-mint-guard.ts",
|
|
69
|
+
"server-e2e/objstore/fs.ts",
|
|
70
|
+
"server-e2e/objstore/handlers.ts",
|
|
71
|
+
"server-e2e/objstore/init.ts",
|
|
72
|
+
"server-e2e/objstore/reaper.ts",
|
|
73
|
+
"server-e2e/objstore/rest-deny.ts",
|
|
74
|
+
"server-e2e/objstore/rest-mint.ts",
|
|
75
|
+
"server-e2e/objstore/rest.ts",
|
|
76
|
+
"server-e2e/objstore/sign.ts",
|
|
77
|
+
"server-e2e/objstore/store-neon.ts",
|
|
78
|
+
"server-e2e/objstore/store.ts",
|
|
79
|
+
"server-e2e/objstore/tokens.ts",
|
|
80
|
+
"server-e2e/peer.ts",
|
|
81
|
+
"server-e2e/pubsub.ts",
|
|
82
|
+
"server-e2e/sign.ts",
|
|
83
|
+
"server-e2e/sse-server.ts",
|
|
84
|
+
"server-e2e/sse-session.ts",
|
|
85
|
+
"server-e2e/static.ts",
|
|
86
|
+
"server-e2e/sync-handlers.ts",
|
|
87
|
+
"server-e2e/util.ts",
|
|
88
|
+
"server-e2e/validation.ts",
|
|
89
|
+
"server-e2e/ws-server.ts",
|
|
90
|
+
"server-e2e/config.example.json",
|
|
91
|
+
"server-managed/activity.ts",
|
|
92
|
+
"server-managed/avatar-store.ts",
|
|
93
|
+
"server-managed/blob-store.ts",
|
|
94
|
+
"server-managed/brotli.ts",
|
|
95
|
+
"server-managed/bundle-advisories.ts",
|
|
96
|
+
"server-managed/bundle-advisory-inventory.ts",
|
|
97
|
+
"server-managed/bundle-cache.ts",
|
|
98
|
+
"server-managed/bundle-build.ts",
|
|
99
|
+
"server-managed/bundle-build-leases.ts",
|
|
100
|
+
"server-managed/bundle-build-worker.js",
|
|
101
|
+
"server-managed/bundle-build-diagnostics.js",
|
|
102
|
+
"server-managed/bundle-build-diagnostics.d.ts",
|
|
103
|
+
"server-managed/bundle-catalog.ts",
|
|
104
|
+
"server-managed/bundle-store.ts",
|
|
105
|
+
"server-managed/bundle-summary-cache.ts",
|
|
106
|
+
"server-managed/bundle.ts",
|
|
107
|
+
"server-managed/cache-storage.ts",
|
|
108
|
+
"server-managed/cli.js",
|
|
109
|
+
"server-managed/combined.ts",
|
|
110
|
+
"server-managed/comments.ts",
|
|
111
|
+
"server-managed/config.ts",
|
|
112
|
+
"server-managed/content-access.ts",
|
|
113
|
+
"server-managed/crypto.ts",
|
|
114
|
+
"server-managed/db-methods.ts",
|
|
115
|
+
"server-managed/db-neon.ts",
|
|
116
|
+
"server-managed/db-schema.ts",
|
|
117
|
+
"server-managed/db-table-names.ts",
|
|
118
|
+
"server-managed/db.ts",
|
|
119
|
+
"server-managed/github-app.ts",
|
|
120
|
+
"server-managed/github-errors.ts",
|
|
121
|
+
"server-managed/github-metadata.ts",
|
|
122
|
+
"server-managed/github-issue-oauth.ts",
|
|
123
|
+
"server-managed/github-issues.ts",
|
|
124
|
+
"server-managed/github-oauth.ts",
|
|
125
|
+
"server-managed/github-pulls.ts",
|
|
126
|
+
"server-managed/http-response.ts",
|
|
127
|
+
"server-managed/http.ts",
|
|
128
|
+
"server-managed/import-triage.ts",
|
|
129
|
+
"server-managed/managed-issues.ts",
|
|
130
|
+
"server-managed/management.ts",
|
|
131
|
+
"server-managed/management-catalog.ts",
|
|
132
|
+
"server-managed/object-storage.ts",
|
|
133
|
+
"server-managed/object-storage-disk.ts",
|
|
134
|
+
"server-managed/object-storage-vercel.ts",
|
|
135
|
+
"server-managed/index.ts",
|
|
136
|
+
"server-managed/package-entry-points.ts",
|
|
137
|
+
"server-managed/public-workspace.ts",
|
|
138
|
+
"server-managed/repo-path.ts",
|
|
139
|
+
"server-managed/report-migration.ts",
|
|
140
|
+
"server-managed/report-query.ts",
|
|
141
|
+
"server-managed/report-response.ts",
|
|
142
|
+
"server-managed/report-sources.ts",
|
|
143
|
+
"server-managed/revisions.ts",
|
|
144
|
+
"server-managed/repository-browser.ts",
|
|
145
|
+
"server-managed/repository-discovery.ts",
|
|
146
|
+
"server-managed/repository-policy.ts",
|
|
147
|
+
"server-managed/session.ts",
|
|
148
|
+
"server-managed/slugs.ts",
|
|
149
|
+
"server-managed/solidity-entry-points.ts",
|
|
150
|
+
"server-managed/sql-postgres.ts",
|
|
151
|
+
"server-managed/sql.ts",
|
|
152
|
+
"server-managed/static.ts",
|
|
153
|
+
"server-managed/storage.ts",
|
|
154
|
+
"server-managed/storage-command.ts",
|
|
155
|
+
"server-managed/storage-db.ts",
|
|
156
|
+
"server-managed/storage-encryption.ts",
|
|
157
|
+
"server-managed/storage-maintenance.ts",
|
|
158
|
+
"server-managed/storage-payload.ts",
|
|
159
|
+
"server-managed/storage-stores.ts",
|
|
160
|
+
"server-managed/team-catalog.ts",
|
|
161
|
+
"server-managed/team-feed.ts",
|
|
162
|
+
"server-managed/team-reports.ts",
|
|
163
|
+
"server-managed/triage-response.ts",
|
|
164
|
+
"server-managed/uploads.ts",
|
|
165
|
+
"server-managed/workspace-shares.ts",
|
|
166
|
+
"server-common/database-config.ts",
|
|
167
|
+
"server-common/initialize.ts",
|
|
168
|
+
"server-common/reap.ts",
|
|
169
|
+
"server-common/npm-advisories.ts",
|
|
170
|
+
"server-common/origin.ts",
|
|
171
|
+
"server-common/standalone.ts",
|
|
172
|
+
"server-common/storage-log.ts",
|
|
173
|
+
"server-common/storage-crypto.ts",
|
|
174
|
+
"server-common/vercel-blob.ts",
|
|
175
|
+
"server-common/scan-config.ts",
|
|
176
|
+
"common/bundle-commit.d.ts",
|
|
177
|
+
"common/bundle-commit.js",
|
|
178
|
+
"common/bundle-metadata.d.ts",
|
|
179
|
+
"common/bundle-metadata.js",
|
|
180
|
+
"common/bundle-reasons.d.ts",
|
|
181
|
+
"common/bundle-reasons.js",
|
|
182
|
+
"common/bundle-sources.d.ts",
|
|
183
|
+
"common/bundle-sources.js",
|
|
184
|
+
"common/bundle-source-links.d.ts",
|
|
185
|
+
"common/bundle-source-links.js",
|
|
186
|
+
"common/bundle-stats.js",
|
|
187
|
+
"common/bundle-tabs.js",
|
|
188
|
+
"common/code-language.js",
|
|
189
|
+
"common/default-scan-models.ts",
|
|
190
|
+
"common/finding-id.js",
|
|
191
|
+
"common/github-pr.ts",
|
|
192
|
+
"common/github-issue-labels.js",
|
|
193
|
+
"common/github-issue-labels.d.ts",
|
|
194
|
+
"common/managed/comments.ts",
|
|
195
|
+
"common/managed/permissions.ts",
|
|
196
|
+
"common/managed/report-content.ts",
|
|
197
|
+
"common/managed/report-filter.ts",
|
|
198
|
+
"common/managed/roles.ts",
|
|
199
|
+
"common/managed/routes.d.ts",
|
|
200
|
+
"common/managed/routes.js",
|
|
201
|
+
"common/managed/scan-models.ts",
|
|
202
|
+
"common/managed/triage.ts",
|
|
78
203
|
"common/save-error-reason.ts",
|
|
204
|
+
"common/server-info.ts",
|
|
205
|
+
"common/scan-server.ts",
|
|
79
206
|
"common/utf8.d.ts",
|
|
80
207
|
"common/utf8.js",
|
|
208
|
+
"client/finding-link.js",
|
|
209
|
+
"client/linked-findings.d.ts",
|
|
210
|
+
"client/linked-findings.js",
|
|
81
211
|
"out/brotli-fallback.js",
|
|
212
|
+
"out/client-managed.js",
|
|
213
|
+
"out/client-managed-import.js",
|
|
82
214
|
"out/client-sync.js",
|
|
83
215
|
"out/graph.js",
|
|
216
|
+
"out/github-issue-authorized.html",
|
|
217
|
+
"out/github-issue-authorized.js",
|
|
84
218
|
"out/icon-maskable.svg",
|
|
85
219
|
"out/icon.svg",
|
|
86
220
|
"out/index.html",
|
|
87
221
|
"out/manifest.webmanifest",
|
|
88
222
|
"out/prism.js",
|
|
223
|
+
"out/stasis.svg",
|
|
89
224
|
"out/terminal.js",
|
|
90
225
|
"out/view.css",
|
|
91
226
|
"out/view.html",
|
|
@@ -94,40 +229,50 @@
|
|
|
94
229
|
],
|
|
95
230
|
"scripts": {
|
|
96
231
|
"lint": "node --run lint:js && node --run lint:css && node --run lint:ts",
|
|
97
|
-
"lint:js": "oxlint -c .oxlintrc.json --ignore-pattern=ui/logs.js ./tests/ ./common/ ./server/ ./client/ ./ui/",
|
|
232
|
+
"lint:js": "oxlint -c .oxlintrc.json --ignore-pattern=ui/logs.js ./cli.js ./server.ts ./tests/ ./common/ ./server-common/ ./server-e2e/ ./server-managed/ ./client/ ./ui/ ./api/",
|
|
98
233
|
"lint:css": "stylelint 'ui/**/*.css'",
|
|
99
234
|
"lint:ts": "tsc --noEmit",
|
|
100
235
|
"prepack": "node --run build",
|
|
101
236
|
"build": "node build.js build",
|
|
102
237
|
"serve": "node build.js serve",
|
|
103
|
-
"server": "node server
|
|
104
|
-
"
|
|
238
|
+
"server": "node --run server-e2e --",
|
|
239
|
+
"server-e2e": "node server-e2e/index.ts",
|
|
240
|
+
"server-managed": "node server-managed/index.ts",
|
|
241
|
+
"server-managed-test": "node server-managed/test-server.ts",
|
|
242
|
+
"test": "node --js-base-64 --import=./tests/_resource-loader.js --experimental-test-module-mocks --test-timeout=120000 --test ./tests/*.test.js"
|
|
105
243
|
},
|
|
106
244
|
"devDependencies": {
|
|
107
|
-
"@electric-sql/pglite": "^0.
|
|
108
|
-
"@
|
|
109
|
-
"@
|
|
110
|
-
"@preventive/
|
|
245
|
+
"@electric-sql/pglite": "^0.5.5",
|
|
246
|
+
"@noble/ciphers": "^2.3.0",
|
|
247
|
+
"@preventive/diff": "^1.0.0",
|
|
248
|
+
"@preventive/lockfile": "1.0.0-alpha.5",
|
|
249
|
+
"@preventive/terminal": "2.0.0-beta.1",
|
|
111
250
|
"@rray/frontend": "^1.0.0",
|
|
112
|
-
"@stylistic/stylelint-plugin": "^5.
|
|
113
|
-
"@types/node": "^
|
|
251
|
+
"@stylistic/stylelint-plugin": "^5.3.0",
|
|
252
|
+
"@types/node": "^26.2.0",
|
|
114
253
|
"@types/ws": "^8.18.1",
|
|
254
|
+
"@vercel/functions": "^3.9.11",
|
|
115
255
|
"brotli": "^1.3.3",
|
|
116
|
-
"esbuild": "^0.
|
|
117
|
-
"lit": "^3.3.
|
|
256
|
+
"esbuild": "^0.28.2",
|
|
257
|
+
"lit": "^3.3.3",
|
|
118
258
|
"minify-html-literals": "^1.3.5",
|
|
119
|
-
"oxlint": "^1.
|
|
259
|
+
"oxlint": "^1.79.0",
|
|
120
260
|
"prismjs": "^1.30.0",
|
|
121
|
-
"stylelint": "^17.
|
|
261
|
+
"stylelint": "^17.14.1",
|
|
122
262
|
"stylelint-config-recommended": "^18.0.0",
|
|
123
|
-
"typescript": "^
|
|
263
|
+
"typescript": "^7.0.2"
|
|
124
264
|
},
|
|
125
265
|
"dependencies": {
|
|
266
|
+
"@exodus/stasis": "1.0.0-beta.5",
|
|
267
|
+
"@exodus/stasis-core": "1.0.0-beta.5",
|
|
268
|
+
"@preventive/report": "1.0.0-alpha.4",
|
|
269
|
+
"@preventive/upstream": "1.0.0-alpha.4",
|
|
126
270
|
"ws": "^8.20.1"
|
|
127
271
|
},
|
|
128
272
|
"peerDependencies": {
|
|
129
273
|
"@neondatabase/serverless": "^1.0.2",
|
|
130
|
-
"@vercel/blob": "^2.3.3"
|
|
274
|
+
"@vercel/blob": "^2.3.3",
|
|
275
|
+
"@vercel/functions": "^3.9.11"
|
|
131
276
|
},
|
|
132
277
|
"peerDependenciesMeta": {
|
|
133
278
|
"@neondatabase/serverless": {
|
|
@@ -135,6 +280,9 @@
|
|
|
135
280
|
},
|
|
136
281
|
"@vercel/blob": {
|
|
137
282
|
"optional": true
|
|
283
|
+
},
|
|
284
|
+
"@vercel/functions": {
|
|
285
|
+
"optional": true
|
|
138
286
|
}
|
|
139
287
|
},
|
|
140
288
|
"packageManager": "pnpm@10.33.4+sha512.1c67b3b359b2d408119ba1ed289f34b8fc3c6873412bec6fd264fbdc82489e510fcbecb9ce9d22dae7f3b76269d8441046014bdca53b9979cd7a561ad631b800"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { env } from 'node:process'
|
|
2
|
+
|
|
3
|
+
// One shared URL or per-mode URLs. Validate before opening either store so
|
|
4
|
+
// an ambiguous configuration cannot send application traffic and GC elsewhere.
|
|
5
|
+
export function databaseUrls({ combined = false } = {}) {
|
|
6
|
+
const shared = env['DATABASE_URL'] || null
|
|
7
|
+
const e2e = env['E2E_DATABASE_URL'] || null
|
|
8
|
+
const managed = env['MANAGED_DATABASE_URL'] || null
|
|
9
|
+
if (shared && (e2e || managed)) {
|
|
10
|
+
throw new Error('DATABASE_URL cannot be combined with E2E_DATABASE_URL or MANAGED_DATABASE_URL. Use the shared URL alone, or only the per-mode URLs.')
|
|
11
|
+
}
|
|
12
|
+
if (combined && Boolean(e2e) !== Boolean(managed)) {
|
|
13
|
+
throw new Error('Combined mode requires both E2E_DATABASE_URL and MANAGED_DATABASE_URL, DATABASE_URL alone, or no database URLs. Mixing Neon and SQLite is not supported.')
|
|
14
|
+
}
|
|
15
|
+
return { e2e: shared ?? e2e, managed: shared ?? managed }
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Register resources as they are acquired. Failed assembly rolls them back in
|
|
2
|
+
// reverse order; successful assembly transfers ownership to the returned app.
|
|
3
|
+
export async function initializeApp<T>(assemble: (rollback: AsyncDisposableStack) => T | Promise<T>): Promise<T> {
|
|
4
|
+
const rollback = new AsyncDisposableStack()
|
|
5
|
+
try {
|
|
6
|
+
const app = await assemble(rollback)
|
|
7
|
+
rollback.move()
|
|
8
|
+
return app
|
|
9
|
+
} catch (error) {
|
|
10
|
+
try { await rollback.disposeAsync() }
|
|
11
|
+
catch (cleanupError) {
|
|
12
|
+
// AsyncDisposableStack runs every cleanup even if one fails. Preserve
|
|
13
|
+
// both failures so cleanup errors cannot hide the initialization error.
|
|
14
|
+
throw new SuppressedError(cleanupError, error, 'App initialization and cleanup failed')
|
|
15
|
+
}
|
|
16
|
+
throw error
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer'
|
|
2
|
+
|
|
3
|
+
const UPSTREAM_URL = 'https://registry.npmjs.org/-/npm/v1/security/advisories/bulk'
|
|
4
|
+
const RESPONSE_BODY_LIMIT = 4 * 1024 * 1024
|
|
5
|
+
export const NPM_ADVISORIES_TIMEOUT_MS = 30_000
|
|
6
|
+
|
|
7
|
+
export async function fetchNpmAdvisories(body: Buffer, signal: AbortSignal, debug = false): Promise<{ status: number; body: unknown }> {
|
|
8
|
+
let upstream: Response
|
|
9
|
+
try {
|
|
10
|
+
upstream = await fetch(UPSTREAM_URL, {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
// Force JSON — the bulk endpoint requires it. Drop every
|
|
13
|
+
// client-supplied header to keep an upstream fingerprint from
|
|
14
|
+
// leaking through (cookies, auth, custom UA, ...). The
|
|
15
|
+
// registry's bulk endpoint doesn't need any of them for a
|
|
16
|
+
// public lookup.
|
|
17
|
+
headers: { 'content-type': 'application/json', 'accept': 'application/json' },
|
|
18
|
+
// Re-wrap as a plain Uint8Array — Buffer's underlying
|
|
19
|
+
// ArrayBufferLike type doesn't satisfy fetch's BodyInit
|
|
20
|
+
// narrowing (it can't statically rule out SharedArrayBuffer),
|
|
21
|
+
// but a copy through Uint8Array is zero-cost in practice and
|
|
22
|
+
// unambiguously typed.
|
|
23
|
+
body: new Uint8Array(body),
|
|
24
|
+
signal,
|
|
25
|
+
})
|
|
26
|
+
} catch (err: unknown) {
|
|
27
|
+
if (debug) console.warn('npm-advisories upstream error:', err)
|
|
28
|
+
return { status: 502, body: { error: 'upstream-unreachable' } }
|
|
29
|
+
}
|
|
30
|
+
// Assert JSON on the upstream body. The Content-Type header is
|
|
31
|
+
// unreliable (Cloudflare in front of registry.npmjs.org strips it
|
|
32
|
+
// from some responses; a captive portal / WAF can declare HTML on
|
|
33
|
+
// a body that's actually JSON or vice-versa), so we don't lean on
|
|
34
|
+
// it — instead we buffer the body and parse. A successful
|
|
35
|
+
// JSON.parse is the strongest guarantee we can hand the UI's
|
|
36
|
+
// `await res.json()`. Buffering is bounded by
|
|
37
|
+
// `RESPONSE_BODY_LIMIT`; the advisories endpoint's payloads sit
|
|
38
|
+
// well under that.
|
|
39
|
+
const upstreamContentType = upstream.headers.get('content-type') ?? ''
|
|
40
|
+
let buffered: Buffer | null
|
|
41
|
+
try {
|
|
42
|
+
buffered = await readUpstreamBody(upstream)
|
|
43
|
+
} catch (err: unknown) {
|
|
44
|
+
if (debug) console.warn('npm-advisories upstream body error:', err)
|
|
45
|
+
return { status: 502, body: { error: 'upstream-unreachable' } }
|
|
46
|
+
}
|
|
47
|
+
if (buffered === null) {
|
|
48
|
+
if (debug) console.warn(`npm-advisories upstream too large: status=${upstream.status}`)
|
|
49
|
+
return { status: 502, body: { error: 'upstream-too-large', upstreamStatus: upstream.status } }
|
|
50
|
+
}
|
|
51
|
+
// Treat the body as UTF-8 — `JSON.parse` operates on a string and
|
|
52
|
+
// the registry's responses are always UTF-8 in practice. A
|
|
53
|
+
// non-UTF-8 byte sequence still decodes (with U+FFFD
|
|
54
|
+
// substitution); the subsequent JSON.parse fails and routes
|
|
55
|
+
// through the error branch.
|
|
56
|
+
const text = buffered.toString('utf8')
|
|
57
|
+
let parsed: unknown
|
|
58
|
+
try {
|
|
59
|
+
parsed = JSON.parse(text)
|
|
60
|
+
} catch {
|
|
61
|
+
if (debug) console.warn(`npm-advisories upstream non-JSON: status=${upstream.status} ct=${upstreamContentType || '<none>'} bytes=${buffered.byteLength}`)
|
|
62
|
+
return { status: 502, body: {
|
|
63
|
+
error: 'upstream-not-json',
|
|
64
|
+
upstreamStatus: upstream.status,
|
|
65
|
+
upstreamContentType: upstreamContentType || null,
|
|
66
|
+
} }
|
|
67
|
+
}
|
|
68
|
+
return { status: upstream.status, body: parsed }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Buffer the upstream response body up to RESPONSE_BODY_LIMIT.
|
|
72
|
+
// Returns null if the cap is exceeded (caller maps to a 502
|
|
73
|
+
// `upstream-too-large`), or the cumulative Buffer otherwise. A
|
|
74
|
+
// transport error mid-read (e.g. AbortSignal fired by the deadline
|
|
75
|
+
// timer or by `req` close) throws — the caller catches it.
|
|
76
|
+
//
|
|
77
|
+
// `finally { reader.cancel() }` is load-bearing on the error and
|
|
78
|
+
// cap-exceeded paths: leaving the reader locked to the body holds
|
|
79
|
+
// the underlying undici TCP socket out of the connection pool until
|
|
80
|
+
// GC, and the cap-exceeded path explicitly needs to tear the
|
|
81
|
+
// transfer down so we don't keep buffering bytes we'll never use.
|
|
82
|
+
// On the clean-drain path (done:true), cancel() is a no-op.
|
|
83
|
+
async function readUpstreamBody(upstream: Response): Promise<Buffer | null> {
|
|
84
|
+
if (!upstream.body) return Buffer.alloc(0)
|
|
85
|
+
const reader = upstream.body.getReader()
|
|
86
|
+
const chunks: Uint8Array[] = []
|
|
87
|
+
let received = 0
|
|
88
|
+
try {
|
|
89
|
+
for (;;) {
|
|
90
|
+
const { done, value } = await reader.read()
|
|
91
|
+
if (done) break
|
|
92
|
+
if (!value) continue
|
|
93
|
+
received += value.byteLength
|
|
94
|
+
if (received > RESPONSE_BODY_LIMIT) return null
|
|
95
|
+
chunks.push(value)
|
|
96
|
+
}
|
|
97
|
+
return Buffer.concat(chunks)
|
|
98
|
+
} finally {
|
|
99
|
+
try { await reader.cancel() } catch {}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// Same-origin gate
|
|
2
|
-
// support cross-origin browser clients, so any Origin header present
|
|
3
|
-
// on an incoming request MUST match the server's own host (derived
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// Same-origin gate, shared by the e2e and managed servers (server-common).
|
|
2
|
+
// We don't support cross-origin browser clients, so any Origin header present
|
|
3
|
+
// on an incoming request MUST match the server's own host (derived from
|
|
4
|
+
// `req.headers.host`, or from `X-Forwarded-Host` / `X-Forwarded-Proto` when a
|
|
5
|
+
// trusted reverse proxy is in front).
|
|
6
6
|
//
|
|
7
7
|
// Why "present-must-match" rather than "always required":
|
|
8
8
|
// - Browser WebSocket handshakes always carry Origin (RFC 6455), so a
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto'
|
|
2
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
3
|
+
|
|
4
|
+
type Handler = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>
|
|
5
|
+
type Reapers = Record<string, () => Promise<unknown>>
|
|
6
|
+
type Options = { secret?: string; isShuttingDown?: () => boolean }
|
|
7
|
+
|
|
8
|
+
// Start every cleanup and wait for all of them, including when one fails.
|
|
9
|
+
// The caller must not close storage or return success with work still running.
|
|
10
|
+
export async function runReapers(reapers: Reapers): Promise<void> {
|
|
11
|
+
const results = await Promise.allSettled(Object.values(reapers).map(reap => Promise.resolve().then(reap)))
|
|
12
|
+
const errors = results.filter(result => result.status === 'rejected').map(result => result.reason)
|
|
13
|
+
if (errors.length > 0) throw new AggregateError(errors, 'Cleanup failed')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createReapHandler(reapers: Reapers, { secret = process.env['CRON_SECRET'], isShuttingDown = () => false }: Options = {}) {
|
|
17
|
+
const key = randomBytes(32)
|
|
18
|
+
const hash = (value: string) => createHmac('sha256', key).update(value).digest()
|
|
19
|
+
const expected = secret ? hash(`Bearer ${secret}`) : null
|
|
20
|
+
return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {
|
|
21
|
+
const send = (status: number, body: object, headers = {}) => {
|
|
22
|
+
res.writeHead(status, { 'content-type': 'application/json', 'cache-control': 'no-store', ...headers })
|
|
23
|
+
res.end(JSON.stringify(body))
|
|
24
|
+
}
|
|
25
|
+
const authorization = req.headers.authorization
|
|
26
|
+
if (req.headers['x-deepview-share'] !== undefined) { send(403, { error: 'share-scope-required' }); return }
|
|
27
|
+
if (!expected || typeof authorization !== 'string' || !timingSafeEqual(hash(authorization), expected)) {
|
|
28
|
+
send(401, { error: 'unauthorized' }); return
|
|
29
|
+
}
|
|
30
|
+
if (req.method !== 'GET') { send(405, { error: 'method-not-allowed' }, { allow: 'GET' }); return }
|
|
31
|
+
if (isShuttingDown()) { send(503, { error: 'shutting-down' }); return }
|
|
32
|
+
const startedAt = Date.now()
|
|
33
|
+
try {
|
|
34
|
+
await runReapers(reapers)
|
|
35
|
+
send(200, { ok: true, reaped: Object.keys(reapers), ms: Date.now() - startedAt })
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error('reap failed:', err)
|
|
38
|
+
send(500, { error: 'reap-failed' })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Only top-level servers compose this route. Domain routers stay unaware of
|
|
44
|
+
// other modes, and cleanup uses the stores those servers have already opened.
|
|
45
|
+
export function withReap(next: Handler, reapers: Reapers, options: Options = {}): Handler {
|
|
46
|
+
const reap = createReapHandler(reapers, options)
|
|
47
|
+
return (req, res) => req.url?.split('?', 1)[0] === '/api/reap' ? reap(req, res) : next(req, res)
|
|
48
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { normalizeScanServer } from '../common/scan-server.ts'
|
|
2
|
+
|
|
3
|
+
export function configuredScanServer(value: string | undefined): string | null {
|
|
4
|
+
if (!value?.trim()) return null
|
|
5
|
+
const server = normalizeScanServer(value)
|
|
6
|
+
if (!server) throw new Error('DEEPVIEW_SCAN_SERVER must be an absolute HTTP(S) URL without credentials, query, or fragment')
|
|
7
|
+
return server
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Apply at serve time, before compression and ETag generation. Packaged HTML
|
|
11
|
+
// stays strict and does not bake in the build machine's configuration.
|
|
12
|
+
export function scanServerHtml(html: string, server: string | null, { advertise = false } = {}): string {
|
|
13
|
+
if (!server) return html
|
|
14
|
+
const origin = new URL(server).origin
|
|
15
|
+
const result = html.replace(/(connect-src 'self')(?=[;"])/u, `$1 ${origin}`)
|
|
16
|
+
if (!advertise) return result
|
|
17
|
+
const content = server.replaceAll('&', '&').replaceAll('"', '"').replaceAll('<', '<')
|
|
18
|
+
return result.replace('</head>', `<meta name="deepview-scan-server" content="${content}">\n</head>`)
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Server } from 'node:http'
|
|
2
|
+
|
|
3
|
+
// Only CLI entry points own process signals and termination. Embedded servers
|
|
4
|
+
// expose async disposal and error events to their host instead.
|
|
5
|
+
export function startServer(server: Server, config: { port: number; host: string }): void {
|
|
6
|
+
let shuttingDown = false
|
|
7
|
+
let exitCode = 0
|
|
8
|
+
function shutdown(code: number): void {
|
|
9
|
+
if (code !== 0) exitCode = code
|
|
10
|
+
if (shuttingDown) return
|
|
11
|
+
shuttingDown = true
|
|
12
|
+
console.log('Shutting down…')
|
|
13
|
+
void server[Symbol.asyncDispose]().catch(err => {
|
|
14
|
+
console.error('Shutdown failed:', err)
|
|
15
|
+
exitCode = 1
|
|
16
|
+
}).finally(() => process.exit(exitCode))
|
|
17
|
+
}
|
|
18
|
+
function onSignal(): void { shutdown(0) }
|
|
19
|
+
function onError(err: unknown): void {
|
|
20
|
+
console.error('Server error:', err)
|
|
21
|
+
shutdown(1)
|
|
22
|
+
}
|
|
23
|
+
server.on('error', onError)
|
|
24
|
+
process.on('SIGINT', onSignal)
|
|
25
|
+
process.on('SIGTERM', onSignal)
|
|
26
|
+
process.on('unhandledRejection', onError)
|
|
27
|
+
process.on('uncaughtException', onError)
|
|
28
|
+
server.listen(config.port, config.host)
|
|
29
|
+
}
|