cursedbelt-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/dist/server/activity/index.d.ts +36 -0
- package/dist/server/activity/index.js +36 -0
- package/dist/server/activity/migrations.d.ts +21 -0
- package/dist/server/activity/migrations.js +55 -0
- package/dist/server/activity/shareSource.d.ts +11 -0
- package/dist/server/activity/shareSource.js +45 -0
- package/dist/server/activity/store.d.ts +123 -0
- package/dist/server/activity/store.js +178 -0
- package/dist/server/app.d.ts +56 -0
- package/dist/server/app.js +45 -0
- package/dist/server/audit/index.d.ts +2 -0
- package/dist/server/audit/index.js +2 -0
- package/dist/server/audit/migrations.d.ts +2 -0
- package/dist/server/audit/migrations.js +79 -0
- package/dist/server/audit/sqliteSink.d.ts +36 -0
- package/dist/server/audit/sqliteSink.js +95 -0
- package/dist/server/audit/sqliteSink.test.d.ts +1 -0
- package/dist/server/audit/sqliteSink.test.js +180 -0
- package/dist/server/auth/cookie.d.ts +22 -0
- package/dist/server/auth/cookie.js +35 -0
- package/dist/server/auth/csrf.d.ts +42 -0
- package/dist/server/auth/csrf.js +36 -0
- package/dist/server/auth/fileTokenSigner.d.ts +10 -0
- package/dist/server/auth/fileTokenSigner.js +22 -0
- package/dist/server/auth/getOnly.d.ts +20 -0
- package/dist/server/auth/getOnly.js +27 -0
- package/dist/server/auth/index.d.ts +12 -0
- package/dist/server/auth/index.js +15 -0
- package/dist/server/auth/jwt.d.ts +18 -0
- package/dist/server/auth/jwt.js +56 -0
- package/dist/server/auth/loginThrottle.d.ts +118 -0
- package/dist/server/auth/loginThrottle.js +204 -0
- package/dist/server/auth/middleware.d.ts +14 -0
- package/dist/server/auth/middleware.js +47 -0
- package/dist/server/auth/password.d.ts +14 -0
- package/dist/server/auth/password.js +65 -0
- package/dist/server/auth/sessionStore.d.ts +19 -0
- package/dist/server/auth/sessionStore.js +221 -0
- package/dist/server/auth/totp.d.ts +34 -0
- package/dist/server/auth/totp.js +81 -0
- package/dist/server/auth/types.d.ts +133 -0
- package/dist/server/auth/types.js +1 -0
- package/dist/server/auth/vault.d.ts +27 -0
- package/dist/server/auth/vault.js +57 -0
- package/dist/server/context.d.ts +35 -0
- package/dist/server/context.js +1 -0
- package/dist/server/ctgr.d.ts +32 -0
- package/dist/server/ctgr.js +69 -0
- package/dist/server/db/kysely.d.ts +14 -0
- package/dist/server/db/kysely.js +16 -0
- package/dist/server/db/plumbingTypes.d.ts +116 -0
- package/dist/server/db/plumbingTypes.js +12 -0
- package/dist/server/dropzone/duplicates.d.ts +82 -0
- package/dist/server/dropzone/duplicates.js +90 -0
- package/dist/server/dropzone/index.d.ts +13 -0
- package/dist/server/dropzone/index.js +13 -0
- package/dist/server/dropzone/scan.d.ts +166 -0
- package/dist/server/dropzone/scan.js +272 -0
- package/dist/server/errors.d.ts +7 -0
- package/dist/server/errors.js +7 -0
- package/dist/server/guard/argon2Binding.d.ts +97 -0
- package/dist/server/guard/argon2Binding.js +138 -0
- package/dist/server/guard/index.d.ts +4 -0
- package/dist/server/guard/index.js +6 -0
- package/dist/server/guard/kdfWorker.d.ts +101 -0
- package/dist/server/guard/kdfWorker.js +301 -0
- package/dist/server/guard/kdfWorkerEntry.d.ts +1 -0
- package/dist/server/guard/kdfWorkerEntry.js +15 -0
- package/dist/server/guard/passwordVerifier.d.ts +65 -0
- package/dist/server/guard/passwordVerifier.js +122 -0
- package/dist/server/guard/revocationStore.d.ts +132 -0
- package/dist/server/guard/revocationStore.js +211 -0
- package/dist/server/guard/sessionSigner.d.ts +132 -0
- package/dist/server/guard/sessionSigner.js +303 -0
- package/dist/server/guard/verifier.d.ts +21 -0
- package/dist/server/guard/verifier.js +1 -0
- package/dist/server/incidents/channels.d.ts +161 -0
- package/dist/server/incidents/channels.js +357 -0
- package/dist/server/incidents/checks.d.ts +61 -0
- package/dist/server/incidents/checks.js +55 -0
- package/dist/server/incidents/index.d.ts +51 -0
- package/dist/server/incidents/index.js +51 -0
- package/dist/server/incidents/migrations.d.ts +20 -0
- package/dist/server/incidents/migrations.js +58 -0
- package/dist/server/incidents/notifier.d.ts +79 -0
- package/dist/server/incidents/notifier.js +141 -0
- package/dist/server/incidents/reporter.d.ts +60 -0
- package/dist/server/incidents/reporter.js +49 -0
- package/dist/server/incidents/routes.d.ts +91 -0
- package/dist/server/incidents/routes.js +202 -0
- package/dist/server/incidents/store.d.ts +75 -0
- package/dist/server/incidents/store.js +176 -0
- package/dist/server/incidents/types.d.ts +107 -0
- package/dist/server/incidents/types.js +32 -0
- package/dist/server/index.d.ts +25 -0
- package/dist/server/index.js +53 -0
- package/dist/server/jobs/fireQueue.d.ts +12 -0
- package/dist/server/jobs/fireQueue.js +37 -0
- package/dist/server/jobs/index.d.ts +6 -0
- package/dist/server/jobs/index.js +10 -0
- package/dist/server/jobs/logger.d.ts +10 -0
- package/dist/server/jobs/logger.js +14 -0
- package/dist/server/jobs/plainjobAdapter.d.ts +19 -0
- package/dist/server/jobs/plainjobAdapter.js +48 -0
- package/dist/server/jobs/polling.d.ts +17 -0
- package/dist/server/jobs/polling.js +79 -0
- package/dist/server/jobs/runner.d.ts +24 -0
- package/dist/server/jobs/runner.js +186 -0
- package/dist/server/jobs/timeout.d.ts +28 -0
- package/dist/server/jobs/timeout.js +47 -0
- package/dist/server/jobs/types.d.ts +167 -0
- package/dist/server/jobs/types.js +12 -0
- package/dist/server/master-lock/guard.d.ts +53 -0
- package/dist/server/master-lock/guard.js +205 -0
- package/dist/server/master-lock/index.d.ts +21 -0
- package/dist/server/master-lock/index.js +21 -0
- package/dist/server/master-lock/lockPage.d.ts +34 -0
- package/dist/server/master-lock/lockPage.js +281 -0
- package/dist/server/master-lock/masterLock.d.ts +294 -0
- package/dist/server/master-lock/masterLock.js +523 -0
- package/dist/server/master-lock/principals.d.ts +76 -0
- package/dist/server/master-lock/principals.js +157 -0
- package/dist/server/master-lock/seed.d.ts +47 -0
- package/dist/server/master-lock/seed.js +93 -0
- package/dist/server/master-lock/store.d.ts +19 -0
- package/dist/server/master-lock/store.js +20 -0
- package/dist/server/media-bun/image.d.ts +7 -0
- package/dist/server/media-bun/image.js +96 -0
- package/dist/server/media-bun/index.d.ts +4 -0
- package/dist/server/media-bun/index.js +10 -0
- package/dist/server/media-bun/streaming.d.ts +86 -0
- package/dist/server/media-bun/streaming.js +237 -0
- package/dist/server/media-bun/video.d.ts +35 -0
- package/dist/server/media-bun/video.js +181 -0
- package/dist/server/metrics/metricsBuffer.d.ts +39 -0
- package/dist/server/metrics/metricsBuffer.js +36 -0
- package/dist/server/metrics/normalizeRoute.d.ts +5 -0
- package/dist/server/metrics/normalizeRoute.js +58 -0
- package/dist/server/middleware/correlationId.d.ts +9 -0
- package/dist/server/middleware/correlationId.js +20 -0
- package/dist/server/middleware/corsAllowlist.d.ts +38 -0
- package/dist/server/middleware/corsAllowlist.js +37 -0
- package/dist/server/middleware/errorEnvelope.d.ts +17 -0
- package/dist/server/middleware/errorEnvelope.js +32 -0
- package/dist/server/middleware/index.d.ts +9 -0
- package/dist/server/middleware/index.js +10 -0
- package/dist/server/middleware/localOrigin.d.ts +71 -0
- package/dist/server/middleware/localOrigin.js +119 -0
- package/dist/server/middleware/rateLimit.d.ts +56 -0
- package/dist/server/middleware/rateLimit.js +86 -0
- package/dist/server/middleware/requestLogger.d.ts +29 -0
- package/dist/server/middleware/requestLogger.js +47 -0
- package/dist/server/middleware/securityHeaders.d.ts +29 -0
- package/dist/server/middleware/securityHeaders.js +44 -0
- package/dist/server/middleware/zValidator.d.ts +29 -0
- package/dist/server/middleware/zValidator.js +57 -0
- package/dist/server/migration/runner.d.ts +42 -0
- package/dist/server/migration/runner.js +70 -0
- package/dist/server/migration/types.d.ts +16 -0
- package/dist/server/migration/types.js +1 -0
- package/dist/server/net/outboundGuard.d.ts +30 -0
- package/dist/server/net/outboundGuard.js +199 -0
- package/dist/server/notifications/hub.d.ts +67 -0
- package/dist/server/notifications/hub.js +187 -0
- package/dist/server/notifications/index.d.ts +47 -0
- package/dist/server/notifications/index.js +46 -0
- package/dist/server/notifications/migrations.d.ts +13 -0
- package/dist/server/notifications/migrations.js +20 -0
- package/dist/server/notifications/routes.d.ts +58 -0
- package/dist/server/notifications/routes.js +113 -0
- package/dist/server/notifications/service.d.ts +58 -0
- package/dist/server/notifications/service.js +41 -0
- package/dist/server/paths/appDataHome.d.ts +19 -0
- package/dist/server/paths/appDataHome.js +68 -0
- package/dist/server/private-media/crypto.d.ts +37 -0
- package/dist/server/private-media/crypto.js +111 -0
- package/dist/server/private-media/index-store.d.ts +31 -0
- package/dist/server/private-media/index-store.js +36 -0
- package/dist/server/private-media/mountPrivateRoutes.d.ts +26 -0
- package/dist/server/private-media/mountPrivateRoutes.js +219 -0
- package/dist/server/private-media/pipeline.d.ts +37 -0
- package/dist/server/private-media/pipeline.js +97 -0
- package/dist/server/private-media/unlock.d.ts +52 -0
- package/dist/server/private-media/unlock.js +55 -0
- package/dist/server/resume/index.d.ts +2 -0
- package/dist/server/resume/index.js +2 -0
- package/dist/server/resume/routes.d.ts +41 -0
- package/dist/server/resume/routes.js +50 -0
- package/dist/server/resume/store.d.ts +37 -0
- package/dist/server/resume/store.js +38 -0
- package/dist/server/retention/archive.d.ts +78 -0
- package/dist/server/retention/archive.js +284 -0
- package/dist/server/retention/fleet.d.ts +50 -0
- package/dist/server/retention/fleet.js +66 -0
- package/dist/server/retention/index.d.ts +38 -0
- package/dist/server/retention/index.js +38 -0
- package/dist/server/retention/policy.d.ts +263 -0
- package/dist/server/retention/policy.js +264 -0
- package/dist/server/retention/store.d.ts +101 -0
- package/dist/server/retention/store.js +251 -0
- package/dist/server/retention/sweeper.d.ts +69 -0
- package/dist/server/retention/sweeper.js +289 -0
- package/dist/server/retention/target.d.ts +143 -0
- package/dist/server/retention/target.js +438 -0
- package/dist/server/search/index.d.ts +2 -0
- package/dist/server/search/index.js +6 -0
- package/dist/server/search/pgSearchProvider.d.ts +91 -0
- package/dist/server/search/pgSearchProvider.js +330 -0
- package/dist/server/search/pgSearchProvider.pg.test.d.ts +1 -0
- package/dist/server/search/pgSearchProvider.pg.test.js +338 -0
- package/dist/server/search/pgSearchSchema.d.ts +81 -0
- package/dist/server/search/pgSearchSchema.js +89 -0
- package/dist/server/sharing/index.d.ts +18 -0
- package/dist/server/sharing/index.js +16 -0
- package/dist/server/sharing/migrations.d.ts +6 -0
- package/dist/server/sharing/migrations.js +79 -0
- package/dist/server/sharing/router.d.ts +111 -0
- package/dist/server/sharing/router.js +93 -0
- package/dist/server/sharing/sql.d.ts +67 -0
- package/dist/server/sharing/sql.js +88 -0
- package/dist/server/sharing/store.d.ts +173 -0
- package/dist/server/sharing/store.js +484 -0
- package/dist/server/sqlite/backup.d.ts +48 -0
- package/dist/server/sqlite/backup.js +97 -0
- package/dist/server/sqlite/browse.d.ts +42 -0
- package/dist/server/sqlite/browse.js +84 -0
- package/dist/server/sqlite/export.d.ts +32 -0
- package/dist/server/sqlite/export.js +42 -0
- package/dist/server/sqlite/fts5.d.ts +106 -0
- package/dist/server/sqlite/fts5.js +154 -0
- package/dist/server/sqlite/health.d.ts +44 -0
- package/dist/server/sqlite/health.js +52 -0
- package/dist/server/sqlite/import.d.ts +36 -0
- package/dist/server/sqlite/import.js +108 -0
- package/dist/server/sqlite/index.d.ts +9 -0
- package/dist/server/sqlite/index.js +15 -0
- package/dist/server/sqlite/readonlySql.d.ts +15 -0
- package/dist/server/sqlite/readonlySql.js +65 -0
- package/dist/server/sqlite/stats.d.ts +22 -0
- package/dist/server/sqlite/stats.js +32 -0
- package/dist/server/sqlite/viewer.d.ts +17 -0
- package/dist/server/sqlite/viewer.js +56 -0
- package/dist/server/storage/binaryServerProcessing.d.ts +23 -0
- package/dist/server/storage/binaryServerProcessing.js +81 -0
- package/dist/server/storage/binaryServerStore.d.ts +3 -0
- package/dist/server/storage/binaryServerStore.js +95 -0
- package/dist/server/storage/diskStore.d.ts +2 -0
- package/dist/server/storage/diskStore.js +88 -0
- package/dist/server/storage/files/adapter.d.ts +33 -0
- package/dist/server/storage/files/adapter.js +203 -0
- package/dist/server/storage/files/catalogue.d.ts +72 -0
- package/dist/server/storage/files/catalogue.js +1033 -0
- package/dist/server/storage/files/chunkedUpload.d.ts +56 -0
- package/dist/server/storage/files/chunkedUpload.js +70 -0
- package/dist/server/storage/files/fileRoutes.d.ts +51 -0
- package/dist/server/storage/files/fileRoutes.js +405 -0
- package/dist/server/storage/files/index.d.ts +9 -0
- package/dist/server/storage/files/index.js +11 -0
- package/dist/server/storage/files/migrations.d.ts +2 -0
- package/dist/server/storage/files/migrations.js +163 -0
- package/dist/server/storage/files/mimeByExt.d.ts +1 -0
- package/dist/server/storage/files/mimeByExt.js +13 -0
- package/dist/server/storage/files/stack.d.ts +136 -0
- package/dist/server/storage/files/stack.js +132 -0
- package/dist/server/storage/files/storageOps.d.ts +54 -0
- package/dist/server/storage/files/storageOps.js +110 -0
- package/dist/server/storage/files/types.d.ts +261 -0
- package/dist/server/storage/files/types.js +22 -0
- package/dist/server/storage/imageThumbnail.d.ts +3 -0
- package/dist/server/storage/imageThumbnail.js +50 -0
- package/dist/server/storage/index.d.ts +15 -0
- package/dist/server/storage/index.js +27 -0
- package/dist/server/storage/mountMediaRoutes.d.ts +28 -0
- package/dist/server/storage/mountMediaRoutes.js +141 -0
- package/dist/server/storage/objectStoreMediaStore.d.ts +4 -0
- package/dist/server/storage/objectStoreMediaStore.js +57 -0
- package/dist/server/storage/s3ObjectStore.d.ts +63 -0
- package/dist/server/storage/s3ObjectStore.js +187 -0
- package/dist/server/storage/sources.d.ts +47 -0
- package/dist/server/storage/sources.js +148 -0
- package/dist/server/storage/streamRange.d.ts +19 -0
- package/dist/server/storage/streamRange.js +69 -0
- package/dist/server/storage/streamToken.d.ts +16 -0
- package/dist/server/storage/streamToken.js +54 -0
- package/dist/server/storage/transcodeJobs.d.ts +65 -0
- package/dist/server/storage/transcodeJobs.js +104 -0
- package/dist/server/storage/types.d.ts +193 -0
- package/dist/server/storage/types.js +41 -0
- package/dist/server/storage/videoDerivativeKeys.d.ts +127 -0
- package/dist/server/storage/videoDerivativeKeys.js +149 -0
- package/dist/server/storage/videoProcessor.d.ts +30 -0
- package/dist/server/storage/videoProcessor.js +148 -0
- package/dist/server/sync/alarm.d.ts +34 -0
- package/dist/server/sync/alarm.js +91 -0
- package/dist/server/sync/commands.d.ts +87 -0
- package/dist/server/sync/commands.js +241 -0
- package/dist/server/sync/engine.d.ts +62 -0
- package/dist/server/sync/engine.js +184 -0
- package/dist/server/sync/http.d.ts +106 -0
- package/dist/server/sync/http.js +243 -0
- package/dist/server/sync/index.d.ts +41 -0
- package/dist/server/sync/index.js +41 -0
- package/dist/server/sync/opLog.d.ts +61 -0
- package/dist/server/sync/opLog.js +96 -0
- package/dist/server/sync/planner.d.ts +31 -0
- package/dist/server/sync/planner.js +30 -0
- package/dist/server/sync/status.d.ts +63 -0
- package/dist/server/sync/status.js +49 -0
- package/dist/server/sync/timer.d.ts +52 -0
- package/dist/server/sync/timer.js +170 -0
- package/dist/server/sync/tokens.d.ts +25 -0
- package/dist/server/sync/tokens.js +51 -0
- package/dist/server/sync/types.d.ts +101 -0
- package/dist/server/sync/types.js +29 -0
- package/dist/server/ws/eventBus.d.ts +14 -0
- package/dist/server/ws/eventBus.js +42 -0
- package/dist/server/ws/hub.d.ts +20 -0
- package/dist/server/ws/hub.js +154 -0
- package/dist/server/ws/index.d.ts +5 -0
- package/dist/server/ws/index.js +7 -0
- package/dist/server/ws/presence.d.ts +11 -0
- package/dist/server/ws/presence.js +20 -0
- package/dist/server/ws/room.d.ts +17 -0
- package/dist/server/ws/room.js +23 -0
- package/dist/server/ws/types.d.ts +122 -0
- package/dist/server/ws/types.js +1 -0
- package/package.json +234 -0
- package/src/declaredDepsAreImported.spec.ts +87 -0
- package/src/leafSubpathsImportNothing.spec.ts +358 -0
- package/src/lockfileIsTracked.spec.ts +50 -0
- package/src/namedSubpathsResolve.spec.ts +122 -0
- package/src/noPathDeps.spec.ts +24 -0
- package/src/publishShape.spec.ts +89 -0
- package/src/server/activity/index.ts +59 -0
- package/src/server/activity/migrations.ts +67 -0
- package/src/server/activity/shareSource.ts +57 -0
- package/src/server/activity/store.spec.ts +255 -0
- package/src/server/activity/store.ts +368 -0
- package/src/server/app.spec.ts +243 -0
- package/src/server/app.ts +89 -0
- package/src/server/audit/index.ts +2 -0
- package/src/server/audit/migrations.ts +88 -0
- package/src/server/audit/sqliteSink.test.ts +200 -0
- package/src/server/audit/sqliteSink.ts +162 -0
- package/src/server/auth/cookie.spec.ts +46 -0
- package/src/server/auth/cookie.ts +42 -0
- package/src/server/auth/csrf.spec.ts +81 -0
- package/src/server/auth/csrf.ts +83 -0
- package/src/server/auth/fileTokenSigner.ts +40 -0
- package/src/server/auth/getOnly.spec.ts +53 -0
- package/src/server/auth/getOnly.ts +32 -0
- package/src/server/auth/index.ts +51 -0
- package/src/server/auth/jwt.spec.ts +106 -0
- package/src/server/auth/jwt.ts +75 -0
- package/src/server/auth/loginThrottle.spec.ts +213 -0
- package/src/server/auth/loginThrottle.ts +261 -0
- package/src/server/auth/middleware.spec.ts +148 -0
- package/src/server/auth/middleware.ts +56 -0
- package/src/server/auth/password.spec.ts +48 -0
- package/src/server/auth/password.ts +71 -0
- package/src/server/auth/sessionStore.spec.ts +189 -0
- package/src/server/auth/sessionStore.ts +261 -0
- package/src/server/auth/totp.spec.ts +73 -0
- package/src/server/auth/totp.ts +92 -0
- package/src/server/auth/types.ts +146 -0
- package/src/server/auth/vault.spec.ts +51 -0
- package/src/server/auth/vault.ts +71 -0
- package/src/server/context.ts +37 -0
- package/src/server/ctgr.spec.ts +138 -0
- package/src/server/ctgr.ts +108 -0
- package/src/server/db/kysely.spec.ts +62 -0
- package/src/server/db/kysely.ts +21 -0
- package/src/server/db/plumbingTypes.ts +126 -0
- package/src/server/dropzone/duplicates.ts +121 -0
- package/src/server/dropzone/index.ts +30 -0
- package/src/server/dropzone/scan.spec.ts +255 -0
- package/src/server/dropzone/scan.ts +342 -0
- package/src/server/errors.spec.ts +76 -0
- package/src/server/errors.ts +22 -0
- package/src/server/guard/argon2Binding.spec.ts +117 -0
- package/src/server/guard/argon2Binding.ts +195 -0
- package/src/server/guard/argon2Kat.spec.ts +250 -0
- package/src/server/guard/guard.spec.ts +390 -0
- package/src/server/guard/index.ts +6 -0
- package/src/server/guard/kdfWorker.spec.ts +283 -0
- package/src/server/guard/kdfWorker.ts +367 -0
- package/src/server/guard/kdfWorkerEntry.ts +16 -0
- package/src/server/guard/passwordVerifier.spec.ts +71 -0
- package/src/server/guard/passwordVerifier.ts +175 -0
- package/src/server/guard/revocationStore.spec.ts +135 -0
- package/src/server/guard/revocationStore.ts +291 -0
- package/src/server/guard/sessionSigner.ts +425 -0
- package/src/server/guard/verifier.ts +27 -0
- package/src/server/incidents/channels.ts +487 -0
- package/src/server/incidents/checks.ts +120 -0
- package/src/server/incidents/incidents.spec.ts +463 -0
- package/src/server/incidents/index.ts +96 -0
- package/src/server/incidents/migrations.ts +66 -0
- package/src/server/incidents/notifier.ts +215 -0
- package/src/server/incidents/reporter.ts +110 -0
- package/src/server/incidents/routes.ts +314 -0
- package/src/server/incidents/store.ts +329 -0
- package/src/server/incidents/types.ts +116 -0
- package/src/server/index.ts +248 -0
- package/src/server/jobs/fireQueue.spec.ts +85 -0
- package/src/server/jobs/fireQueue.ts +37 -0
- package/src/server/jobs/index.ts +26 -0
- package/src/server/jobs/logger.ts +16 -0
- package/src/server/jobs/plainjobAdapter.spec.ts +34 -0
- package/src/server/jobs/plainjobAdapter.ts +54 -0
- package/src/server/jobs/polling.spec.ts +219 -0
- package/src/server/jobs/polling.ts +81 -0
- package/src/server/jobs/runner.spec.ts +213 -0
- package/src/server/jobs/runner.ts +213 -0
- package/src/server/jobs/timeout.spec.ts +35 -0
- package/src/server/jobs/timeout.ts +53 -0
- package/src/server/jobs/types.ts +188 -0
- package/src/server/master-lock/guard.spec.ts +347 -0
- package/src/server/master-lock/guard.ts +290 -0
- package/src/server/master-lock/index.ts +44 -0
- package/src/server/master-lock/lockPage.spec.ts +88 -0
- package/src/server/master-lock/lockPage.ts +313 -0
- package/src/server/master-lock/masterLock.spec.ts +338 -0
- package/src/server/master-lock/masterLock.ts +627 -0
- package/src/server/master-lock/principals.spec.ts +378 -0
- package/src/server/master-lock/principals.ts +175 -0
- package/src/server/master-lock/seed.spec.ts +69 -0
- package/src/server/master-lock/seed.ts +112 -0
- package/src/server/master-lock/store.ts +35 -0
- package/src/server/media-bun/image.spec.ts +115 -0
- package/src/server/media-bun/image.ts +134 -0
- package/src/server/media-bun/index.ts +52 -0
- package/src/server/media-bun/streaming.spec.ts +134 -0
- package/src/server/media-bun/streaming.ts +347 -0
- package/src/server/media-bun/video.spec.ts +115 -0
- package/src/server/media-bun/video.ts +232 -0
- package/src/server/metrics/metricsBuffer.ts +92 -0
- package/src/server/metrics/normalizeRoute.spec.ts +51 -0
- package/src/server/metrics/normalizeRoute.ts +63 -0
- package/src/server/middleware/correlationId.ts +24 -0
- package/src/server/middleware/corsAllowlist.spec.ts +118 -0
- package/src/server/middleware/corsAllowlist.ts +69 -0
- package/src/server/middleware/errorEnvelope.ts +38 -0
- package/src/server/middleware/index.ts +19 -0
- package/src/server/middleware/localOrigin.spec.ts +168 -0
- package/src/server/middleware/localOrigin.ts +139 -0
- package/src/server/middleware/rateLimit.spec.ts +72 -0
- package/src/server/middleware/rateLimit.ts +125 -0
- package/src/server/middleware/requestLogger.ts +95 -0
- package/src/server/middleware/securityHeaders.ts +78 -0
- package/src/server/middleware/zValidator.spec.ts +251 -0
- package/src/server/middleware/zValidator.ts +114 -0
- package/src/server/migration/runner.spec.ts +88 -0
- package/src/server/migration/runner.ts +87 -0
- package/src/server/migration/types.ts +17 -0
- package/src/server/net/outboundGuard.spec.ts +90 -0
- package/src/server/net/outboundGuard.ts +205 -0
- package/src/server/notifications/hub.ts +245 -0
- package/src/server/notifications/index.ts +77 -0
- package/src/server/notifications/migrations.ts +39 -0
- package/src/server/notifications/routes.ts +177 -0
- package/src/server/notifications/service.spec.ts +305 -0
- package/src/server/notifications/service.ts +112 -0
- package/src/server/paths/appDataHome.spec.ts +87 -0
- package/src/server/paths/appDataHome.ts +84 -0
- package/src/server/private-media/blobRoute.spec.ts +165 -0
- package/src/server/private-media/crypto.spec.ts +81 -0
- package/src/server/private-media/crypto.ts +155 -0
- package/src/server/private-media/gatePolicy.spec.ts +98 -0
- package/src/server/private-media/index-store.ts +83 -0
- package/src/server/private-media/mountPrivateRoutes.ts +265 -0
- package/src/server/private-media/pipeline.spec.ts +111 -0
- package/src/server/private-media/pipeline.ts +170 -0
- package/src/server/private-media/routes.spec.ts +265 -0
- package/src/server/private-media/unlock.ts +112 -0
- package/src/server/resume/index.ts +8 -0
- package/src/server/resume/resume.spec.ts +118 -0
- package/src/server/resume/routes.ts +92 -0
- package/src/server/resume/store.ts +82 -0
- package/src/server/retention/archive.spec.ts +181 -0
- package/src/server/retention/archive.ts +353 -0
- package/src/server/retention/fleet.ts +104 -0
- package/src/server/retention/index.ts +101 -0
- package/src/server/retention/policy.spec.ts +132 -0
- package/src/server/retention/policy.ts +392 -0
- package/src/server/retention/store.spec.ts +236 -0
- package/src/server/retention/store.ts +338 -0
- package/src/server/retention/sweeper.spec.ts +321 -0
- package/src/server/retention/sweeper.ts +367 -0
- package/src/server/retention/target.spec.ts +592 -0
- package/src/server/retention/target.ts +613 -0
- package/src/server/search/index.ts +12 -0
- package/src/server/search/pgSearchProvider.pg.test.ts +392 -0
- package/src/server/search/pgSearchProvider.ts +421 -0
- package/src/server/search/pgSearchSchema.ts +147 -0
- package/src/server/sharing/index.ts +65 -0
- package/src/server/sharing/migrations.ts +128 -0
- package/src/server/sharing/router.spec.ts +167 -0
- package/src/server/sharing/router.ts +194 -0
- package/src/server/sharing/sql.ts +109 -0
- package/src/server/sharing/store.spec.ts +408 -0
- package/src/server/sharing/store.ts +737 -0
- package/src/server/sqlite/backup.spec.ts +114 -0
- package/src/server/sqlite/backup.ts +154 -0
- package/src/server/sqlite/browse.spec.ts +70 -0
- package/src/server/sqlite/browse.ts +120 -0
- package/src/server/sqlite/export.spec.ts +43 -0
- package/src/server/sqlite/export.ts +74 -0
- package/src/server/sqlite/fts5.spec.ts +175 -0
- package/src/server/sqlite/fts5.ts +255 -0
- package/src/server/sqlite/health.spec.ts +79 -0
- package/src/server/sqlite/health.ts +105 -0
- package/src/server/sqlite/import.spec.ts +75 -0
- package/src/server/sqlite/import.ts +141 -0
- package/src/server/sqlite/index.ts +64 -0
- package/src/server/sqlite/readonlySql.spec.ts +58 -0
- package/src/server/sqlite/readonlySql.ts +67 -0
- package/src/server/sqlite/stats.spec.ts +21 -0
- package/src/server/sqlite/stats.ts +61 -0
- package/src/server/sqlite/viewer.spec.ts +127 -0
- package/src/server/sqlite/viewer.ts +72 -0
- package/src/server/storage/binaryServerProcessing.integration.spec.ts +222 -0
- package/src/server/storage/binaryServerProcessing.spec.ts +150 -0
- package/src/server/storage/binaryServerProcessing.ts +127 -0
- package/src/server/storage/binaryServerStore.ts +102 -0
- package/src/server/storage/chunked.integration.spec.ts +185 -0
- package/src/server/storage/diskStore.ts +83 -0
- package/src/server/storage/files/adapter.photo.display.spec.ts +169 -0
- package/src/server/storage/files/adapter.photo.spec.ts +128 -0
- package/src/server/storage/files/adapter.spec.ts +121 -0
- package/src/server/storage/files/adapter.ts +255 -0
- package/src/server/storage/files/catalogue.media-host.spec.ts +184 -0
- package/src/server/storage/files/catalogue.orderings.spec.ts +157 -0
- package/src/server/storage/files/catalogue.private.spec.ts +106 -0
- package/src/server/storage/files/catalogue.recover.spec.ts +131 -0
- package/src/server/storage/files/catalogue.sort.spec.ts +154 -0
- package/src/server/storage/files/catalogue.spec.ts +133 -0
- package/src/server/storage/files/catalogue.trash-import.spec.ts +125 -0
- package/src/server/storage/files/catalogue.ts +1326 -0
- package/src/server/storage/files/chunkedUpload.spec.ts +111 -0
- package/src/server/storage/files/chunkedUpload.ts +146 -0
- package/src/server/storage/files/collections.spec.ts +294 -0
- package/src/server/storage/files/fileRoutes.replace.spec.ts +88 -0
- package/src/server/storage/files/fileRoutes.spec.ts +327 -0
- package/src/server/storage/files/fileRoutes.ts +462 -0
- package/src/server/storage/files/index.ts +66 -0
- package/src/server/storage/files/migrations.ts +187 -0
- package/src/server/storage/files/mimeByExt.ts +14 -0
- package/src/server/storage/files/stack.spec.ts +258 -0
- package/src/server/storage/files/stack.ts +284 -0
- package/src/server/storage/files/storageOps.spec.ts +126 -0
- package/src/server/storage/files/storageOps.ts +213 -0
- package/src/server/storage/files/types.ts +285 -0
- package/src/server/storage/imageThumbnail.spec.ts +81 -0
- package/src/server/storage/imageThumbnail.ts +60 -0
- package/src/server/storage/index.ts +122 -0
- package/src/server/storage/mountMediaRoutes.ts +231 -0
- package/src/server/storage/objectStore.spec.ts +272 -0
- package/src/server/storage/objectStoreMediaStore.ts +63 -0
- package/src/server/storage/s3ObjectStore.ts +239 -0
- package/src/server/storage/sources.ts +245 -0
- package/src/server/storage/storage.spec.ts +219 -0
- package/src/server/storage/streamRange.ts +92 -0
- package/src/server/storage/streamToken.ts +76 -0
- package/src/server/storage/transcode.integration.spec.ts +134 -0
- package/src/server/storage/transcodeJobs.spec.ts +152 -0
- package/src/server/storage/transcodeJobs.ts +171 -0
- package/src/server/storage/types.ts +230 -0
- package/src/server/storage/videoDerivativeKeys.spec.ts +112 -0
- package/src/server/storage/videoDerivativeKeys.ts +172 -0
- package/src/server/storage/videoProcessor.posterOnly.spec.ts +106 -0
- package/src/server/storage/videoProcessor.ts +229 -0
- package/src/server/sync/alarm.spec.ts +149 -0
- package/src/server/sync/alarm.ts +137 -0
- package/src/server/sync/commands.spec.ts +145 -0
- package/src/server/sync/commands.ts +361 -0
- package/src/server/sync/engine.spec.ts +496 -0
- package/src/server/sync/engine.ts +255 -0
- package/src/server/sync/http.ts +316 -0
- package/src/server/sync/httpRemote.spec.ts +158 -0
- package/src/server/sync/index.ts +90 -0
- package/src/server/sync/opLog.spec.ts +110 -0
- package/src/server/sync/opLog.ts +189 -0
- package/src/server/sync/planner.spec.ts +53 -0
- package/src/server/sync/planner.ts +62 -0
- package/src/server/sync/status.spec.ts +92 -0
- package/src/server/sync/status.ts +108 -0
- package/src/server/sync/timer.spec.ts +150 -0
- package/src/server/sync/timer.ts +207 -0
- package/src/server/sync/tokens.spec.ts +38 -0
- package/src/server/sync/tokens.ts +94 -0
- package/src/server/sync/types.ts +108 -0
- package/src/server/ws/eventBus.spec.ts +67 -0
- package/src/server/ws/eventBus.ts +46 -0
- package/src/server/ws/hub.integration.spec.ts +93 -0
- package/src/server/ws/hub.spec.ts +282 -0
- package/src/server/ws/hub.ts +168 -0
- package/src/server/ws/index.ts +20 -0
- package/src/server/ws/presence.spec.ts +27 -0
- package/src/server/ws/presence.ts +26 -0
- package/src/server/ws/room.spec.ts +36 -0
- package/src/server/ws/room.ts +29 -0
- package/src/server/ws/types.ts +134 -0
- package/src/skippedTestsAreAnswered.spec.ts +215 -0
- package/src/testTmpRoot.spec.ts +102 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { type BackupInfo, createSqliteBackupService, snapshotSqlite, type SqliteBackupOpts, type SqliteBackupS3Opts, type SqliteBackupService, } from './backup';
|
|
2
|
+
export { clampLimit, clampOffset, isKnownTable, listSqliteTables, NotReadOnlyError, quoteIdent, readSqliteTable, runReadonlySqlite, type SqliteTableInfo, type SqliteTablePage, UnknownTableError, } from './browse';
|
|
3
|
+
export { exportSqliteSnapshot, exportSqliteTable, type SnapshotExport, type TableExport, type TableExportFormat, } from './export';
|
|
4
|
+
export { applyFtsSchema, buildFtsSchema, createFts5Search, type Fts5Search, type FtsHighlightOpts, type FtsResult, type FtsSearchOpts, type FtsSnippetOpts, type FtsTableSpec, sanitizeFtsQuery, } from './fts5';
|
|
5
|
+
export { createSqliteHealthChecks, type SqliteHealthCheck, type SqliteHealthOpts, type SqliteHealthResult, type SqliteHealthStatus, } from './health';
|
|
6
|
+
export { type ImportMode, type ImportResult, importRowsIntoSqliteTable, type RestoreResult, restoreSqliteSnapshot, } from './import';
|
|
7
|
+
export { isReadOnlySql } from './readonlySql';
|
|
8
|
+
export { collectSqliteStats, type DbStats, type TableStat } from './stats';
|
|
9
|
+
export { createSqliteViewerMiddleware } from './viewer';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// cursedbelt SQLite toolkit extras (task 30) — bun:sqlite-native primitives layered
|
|
2
|
+
// on the migration runner (task 24): FTS5 ranked search, a read-only DB viewer, the
|
|
3
|
+
// VACUUM-INTO backup service, DB-layer health probes, plus the Hono-free browse /
|
|
4
|
+
// export / import / stats primitives that back both the viewer middleware and any
|
|
5
|
+
// bespoke-transport consumer (a cursedshell plugin, the encrypted-GET "f" app). All
|
|
6
|
+
// app-agnostic; the apps supply table names, paths, and thresholds.
|
|
7
|
+
export { createSqliteBackupService, snapshotSqlite, } from './backup';
|
|
8
|
+
export { clampLimit, clampOffset, isKnownTable, listSqliteTables, NotReadOnlyError, quoteIdent, readSqliteTable, runReadonlySqlite, UnknownTableError, } from './browse';
|
|
9
|
+
export { exportSqliteSnapshot, exportSqliteTable, } from './export';
|
|
10
|
+
export { applyFtsSchema, buildFtsSchema, createFts5Search, sanitizeFtsQuery, } from './fts5';
|
|
11
|
+
export { createSqliteHealthChecks, } from './health';
|
|
12
|
+
export { importRowsIntoSqliteTable, restoreSqliteSnapshot, } from './import';
|
|
13
|
+
export { isReadOnlySql } from './readonlySql';
|
|
14
|
+
export { collectSqliteStats } from './stats';
|
|
15
|
+
export { createSqliteViewerMiddleware } from './viewer';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defense-in-depth read-only guard for the SQLite viewer's ad-hoc query endpoint. A
|
|
3
|
+
* conservative *lexical* check, NOT a parser: it rejects the obvious foot-guns
|
|
4
|
+
* (writes, DDL, PRAGMA, ATTACH, stacked statements) before SQL reaches the DB. The
|
|
5
|
+
* real guarantees are the owner-only mount + this allowlist, layered.
|
|
6
|
+
*
|
|
7
|
+
* cursedbelt keeps its own copy rather than depending on cwip — the toolkit's server
|
|
8
|
+
* surface stays dependency-light, and the rule set here is tuned for SQLite (PRAGMA /
|
|
9
|
+
* ATTACH are SQLite-specific write vectors).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* True only for a single read-only statement: a `SELECT`, or a `WITH … SELECT` CTE.
|
|
13
|
+
* Rejects stacked statements, `SELECT … INTO`, and any forbidden keyword as a word.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isReadOnlySql(sql: string): boolean;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defense-in-depth read-only guard for the SQLite viewer's ad-hoc query endpoint. A
|
|
3
|
+
* conservative *lexical* check, NOT a parser: it rejects the obvious foot-guns
|
|
4
|
+
* (writes, DDL, PRAGMA, ATTACH, stacked statements) before SQL reaches the DB. The
|
|
5
|
+
* real guarantees are the owner-only mount + this allowlist, layered.
|
|
6
|
+
*
|
|
7
|
+
* cursedbelt keeps its own copy rather than depending on cwip — the toolkit's server
|
|
8
|
+
* surface stays dependency-light, and the rule set here is tuned for SQLite (PRAGMA /
|
|
9
|
+
* ATTACH are SQLite-specific write vectors).
|
|
10
|
+
*/
|
|
11
|
+
const FORBIDDEN = [
|
|
12
|
+
'insert',
|
|
13
|
+
'update',
|
|
14
|
+
'delete',
|
|
15
|
+
'drop',
|
|
16
|
+
'alter',
|
|
17
|
+
'truncate',
|
|
18
|
+
'create',
|
|
19
|
+
'replace',
|
|
20
|
+
'attach',
|
|
21
|
+
'detach',
|
|
22
|
+
'reindex',
|
|
23
|
+
'vacuum',
|
|
24
|
+
'pragma',
|
|
25
|
+
'begin',
|
|
26
|
+
'commit',
|
|
27
|
+
'rollback',
|
|
28
|
+
'savepoint',
|
|
29
|
+
'release',
|
|
30
|
+
'grant',
|
|
31
|
+
'revoke',
|
|
32
|
+
];
|
|
33
|
+
/** Strip `--` line comments and block comments, collapse whitespace, lowercase. */
|
|
34
|
+
function normalize(sql) {
|
|
35
|
+
return sql
|
|
36
|
+
.replace(/--[^\n]*/g, ' ')
|
|
37
|
+
.replace(/\/\*[\s\S]*?\*\//g, ' ')
|
|
38
|
+
.replace(/\s+/g, ' ')
|
|
39
|
+
.trim()
|
|
40
|
+
.toLowerCase();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* True only for a single read-only statement: a `SELECT`, or a `WITH … SELECT` CTE.
|
|
44
|
+
* Rejects stacked statements, `SELECT … INTO`, and any forbidden keyword as a word.
|
|
45
|
+
*/
|
|
46
|
+
export function isReadOnlySql(sql) {
|
|
47
|
+
const s = normalize(sql);
|
|
48
|
+
if (!s)
|
|
49
|
+
return false;
|
|
50
|
+
// Only a trailing `;` terminator is allowed — no stacked statements.
|
|
51
|
+
const body = s.replace(/;\s*$/, '');
|
|
52
|
+
if (body.includes(';'))
|
|
53
|
+
return false;
|
|
54
|
+
// Must begin with SELECT or a CTE.
|
|
55
|
+
if (!/^(select|with)\b/.test(body))
|
|
56
|
+
return false;
|
|
57
|
+
// `SELECT … INTO new_table` writes a table — block it.
|
|
58
|
+
if (/\bselect\b[\s\S]*\binto\b/.test(body))
|
|
59
|
+
return false;
|
|
60
|
+
for (const kw of FORBIDDEN) {
|
|
61
|
+
if (new RegExp(`\\b${kw}\\b`).test(body))
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Database } from 'bun:sqlite';
|
|
2
|
+
/**
|
|
3
|
+
* DB usage stats for `bun:sqlite` — per-table row counts and on-disk byte sizes
|
|
4
|
+
* plus the total database file size. Feeds both StatTiles and the rows/bytes charts
|
|
5
|
+
* in an admin surface. Per-table bytes use the `dbstat` virtual table when the build
|
|
6
|
+
* supports it (it does in `bun:sqlite`); if a query for it ever fails, byte sizes
|
|
7
|
+
* degrade to `null` rather than throwing — row counts and the file size still work.
|
|
8
|
+
*/
|
|
9
|
+
export interface TableStat {
|
|
10
|
+
name: string;
|
|
11
|
+
rows: number;
|
|
12
|
+
/** On-disk bytes for this table's pages, or `null` when `dbstat` is unavailable. */
|
|
13
|
+
bytes: number | null;
|
|
14
|
+
}
|
|
15
|
+
export interface DbStats {
|
|
16
|
+
/** Total database file size in bytes (`page_count * page_size`). */
|
|
17
|
+
fileBytes: number;
|
|
18
|
+
/** Sum of every table's row count. */
|
|
19
|
+
totalRows: number;
|
|
20
|
+
tables: TableStat[];
|
|
21
|
+
}
|
|
22
|
+
export declare function collectSqliteStats(db: Database): DbStats;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { listSqliteTables } from './browse';
|
|
2
|
+
/** Whole-database size from the page pragmas (works without `dbstat`). */
|
|
3
|
+
function fileBytes(db) {
|
|
4
|
+
const pageCount = db.query('PRAGMA page_count').get()?.page_count ?? 0;
|
|
5
|
+
const pageSize = db.query('PRAGMA page_size').get()?.page_size ?? 0;
|
|
6
|
+
return pageCount * pageSize;
|
|
7
|
+
}
|
|
8
|
+
/** Per-table byte sizes from `dbstat`, or `null` for all tables if it's unavailable. */
|
|
9
|
+
function bytesByTable(db) {
|
|
10
|
+
try {
|
|
11
|
+
const rows = db
|
|
12
|
+
.query('SELECT name, SUM(pgsize) AS bytes FROM dbstat GROUP BY name')
|
|
13
|
+
.all();
|
|
14
|
+
return new Map(rows.map((r) => [r.name, r.bytes]));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function collectSqliteStats(db) {
|
|
21
|
+
const byTable = bytesByTable(db);
|
|
22
|
+
const tables = listSqliteTables(db).map(({ name, count }) => ({
|
|
23
|
+
name,
|
|
24
|
+
rows: count,
|
|
25
|
+
bytes: byTable ? (byTable.get(name) ?? 0) : null,
|
|
26
|
+
}));
|
|
27
|
+
return {
|
|
28
|
+
fileBytes: fileBytes(db),
|
|
29
|
+
totalRows: tables.reduce((sum, t) => sum + t.rows, 0),
|
|
30
|
+
tables,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Database } from 'bun:sqlite';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
/**
|
|
4
|
+
* A read-only SQLite browser as a Hono sub-app — a thin HTTP wrapper over the
|
|
5
|
+
* Hono-free primitives in `browse.ts` (the same primitives a cursedshell plugin or
|
|
6
|
+
* a bespoke-transport app consumes directly). Mount it behind the owner-only guard:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* app.route('/api/v1/admin/sqlite', ownerOnly(createSqliteViewerMiddleware(db)));
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* Three endpoints — list tables + counts, paginate one table, run an ad-hoc
|
|
13
|
+
* `SELECT` — letting the owner inspect the live DB without shell access. Every path
|
|
14
|
+
* is read-only (see `browse.ts` for the injection/read-only guards). Authn/authz is
|
|
15
|
+
* the mounting app's job (this sub-app trusts that it is already owner-gated).
|
|
16
|
+
*/
|
|
17
|
+
export declare function createSqliteViewerMiddleware(db: Database): Hono;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { ApiError, toErrorEnvelope } from '../errors';
|
|
3
|
+
import { listSqliteTables, NotReadOnlyError, readSqliteTable, runReadonlySqlite, UnknownTableError, } from './browse';
|
|
4
|
+
/**
|
|
5
|
+
* A read-only SQLite browser as a Hono sub-app — a thin HTTP wrapper over the
|
|
6
|
+
* Hono-free primitives in `browse.ts` (the same primitives a cursedshell plugin or
|
|
7
|
+
* a bespoke-transport app consumes directly). Mount it behind the owner-only guard:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* app.route('/api/v1/admin/sqlite', ownerOnly(createSqliteViewerMiddleware(db)));
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Three endpoints — list tables + counts, paginate one table, run an ad-hoc
|
|
14
|
+
* `SELECT` — letting the owner inspect the live DB without shell access. Every path
|
|
15
|
+
* is read-only (see `browse.ts` for the injection/read-only guards). Authn/authz is
|
|
16
|
+
* the mounting app's job (this sub-app trusts that it is already owner-gated).
|
|
17
|
+
*/
|
|
18
|
+
export function createSqliteViewerMiddleware(db) {
|
|
19
|
+
const app = new Hono();
|
|
20
|
+
app.get('/tables', (c) => c.json({ items: listSqliteTables(db) }));
|
|
21
|
+
app.get('/tables/:table', (c) => {
|
|
22
|
+
try {
|
|
23
|
+
return c.json(readSqliteTable(db, c.req.param('table'), {
|
|
24
|
+
limit: c.req.query('limit'),
|
|
25
|
+
offset: c.req.query('offset'),
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
if (err instanceof UnknownTableError) {
|
|
30
|
+
return c.json(toErrorEnvelope(new ApiError(404, 'Unknown table', { code: 'unknown_table' })), 404);
|
|
31
|
+
}
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
app.post('/query', async (c) => {
|
|
36
|
+
let payload;
|
|
37
|
+
try {
|
|
38
|
+
payload = await c.req.json();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return c.json(toErrorEnvelope(new ApiError(400, 'Invalid JSON body', { code: 'bad_request' })), 400);
|
|
42
|
+
}
|
|
43
|
+
const params = Array.isArray(payload.params) ? payload.params : [];
|
|
44
|
+
try {
|
|
45
|
+
const items = runReadonlySqlite(db, payload.sql, params);
|
|
46
|
+
return c.json({ items });
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (err instanceof NotReadOnlyError) {
|
|
50
|
+
return c.json(toErrorEnvelope(new ApiError(400, err.message, { code: 'not_read_only' })), 400);
|
|
51
|
+
}
|
|
52
|
+
return c.json(toErrorEnvelope(new ApiError(400, err instanceof Error ? err.message : String(err), { code: 'query_failed' })), 400);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return app;
|
|
56
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ImageDerivatives, VideoProcessor } from './files/catalogue';
|
|
2
|
+
export type BinaryServerProcessingConfig = {
|
|
3
|
+
/** e.g. 'https://binary-server.cursedalchemy.com' — same value as the byte store's baseUrl. */
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
/** App namespace (path + token scope), e.g. 'p'. Keys sent to the transcode API are
|
|
6
|
+
* app-scoped (`<appId>/<key>`), matching what the MediaStore adapter writes. */
|
|
7
|
+
appId: string;
|
|
8
|
+
/** Shared server-to-server secret (x-internal-secret). */
|
|
9
|
+
internalSecret: string;
|
|
10
|
+
/** HLS rung heights (passed through as the job's ladder). */
|
|
11
|
+
ladderHeights?: number[];
|
|
12
|
+
/** Poll cadence while a job runs. */
|
|
13
|
+
pollMs?: number;
|
|
14
|
+
/** Give up on a job after this long (it keeps running server-side; the row just fails). */
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
fetchImpl?: typeof fetch;
|
|
17
|
+
/** Injectable clock/sleep for tests. */
|
|
18
|
+
sleep?: (ms: number) => Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
export declare function createBinaryServerProcessing(cfg: BinaryServerProcessingConfig): {
|
|
21
|
+
videoProcessor: VideoProcessor;
|
|
22
|
+
imageDerivatives: ImageDerivatives;
|
|
23
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createTranscodeJobClient } from './transcodeJobs';
|
|
2
|
+
import { fsHlsPrefix, fsMp4Key, fsPosterKey, fsSpriteKey, fsVttKey } from './types';
|
|
3
|
+
export function createBinaryServerProcessing(cfg) {
|
|
4
|
+
const jobs = createTranscodeJobClient(cfg);
|
|
5
|
+
const { appKey, submit, poll } = jobs;
|
|
6
|
+
const videoProcessor = async (opts) => {
|
|
7
|
+
const { owner, id, onProgress } = opts;
|
|
8
|
+
const failed = {
|
|
9
|
+
status: 'failed',
|
|
10
|
+
durationSeconds: 0,
|
|
11
|
+
hasHls: false,
|
|
12
|
+
hasSprite: false,
|
|
13
|
+
hasPoster: false,
|
|
14
|
+
};
|
|
15
|
+
try {
|
|
16
|
+
onProgress?.('processing', 1);
|
|
17
|
+
const jobId = await submit({
|
|
18
|
+
strategy: 'library',
|
|
19
|
+
nodeId: id,
|
|
20
|
+
sourceKey: appKey(opts.sourceKey),
|
|
21
|
+
binaryKey: appKey(fsMp4Key(owner, id)),
|
|
22
|
+
sourceKeyOut: appKey(fsMp4Key(owner, id)),
|
|
23
|
+
hlsPrefix: appKey(fsHlsPrefix(owner, id)),
|
|
24
|
+
posterKey: appKey(fsPosterKey(owner, id)),
|
|
25
|
+
spriteKey: appKey(fsSpriteKey(owner, id)),
|
|
26
|
+
vttKey: appKey(fsVttKey(owner, id)),
|
|
27
|
+
posterOnly: opts.posterOnly === true,
|
|
28
|
+
settings: { ladder: opts.ladderHeights ?? [480, 720, 1080] },
|
|
29
|
+
});
|
|
30
|
+
const job = await poll(jobId, (pct) => onProgress?.('processing', Math.min(99, pct)));
|
|
31
|
+
if (job.status !== 'ready') {
|
|
32
|
+
// The "a failed job maps to status failed" fixture test deliberately drives this
|
|
33
|
+
// path — tagged `[expected-in-tests]` (grep-filterable) rather than silenced, so a
|
|
34
|
+
// real binary-server outage still surfaces.
|
|
35
|
+
console.warn(`[binaryServerProcessing][expected-in-tests] video job failed for ${id}: ${job.error ?? '?'}`);
|
|
36
|
+
onProgress?.('failed', 0);
|
|
37
|
+
return failed;
|
|
38
|
+
}
|
|
39
|
+
onProgress?.('ready', 100);
|
|
40
|
+
return {
|
|
41
|
+
status: 'ready',
|
|
42
|
+
durationSeconds: job.result?.durationSeconds ?? 0,
|
|
43
|
+
hasHls: job.result?.hasHls ?? false,
|
|
44
|
+
hasSprite: job.result?.hasSprite ?? false,
|
|
45
|
+
hasPoster: job.result?.hasPoster ?? false,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
// The "a rejected submit maps to status failed" fixture test deliberately drives this
|
|
50
|
+
// path — tagged `[expected-in-tests]` (grep-filterable) rather than silenced, so a
|
|
51
|
+
// real binary-server outage still surfaces.
|
|
52
|
+
console.warn(`[binaryServerProcessing][expected-in-tests] video job errored for ${id}: ${err instanceof Error ? err.message : err}`);
|
|
53
|
+
onProgress?.('failed', 0);
|
|
54
|
+
return failed;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const imageDerivatives = async (args) => {
|
|
58
|
+
try {
|
|
59
|
+
const jobId = await submit({
|
|
60
|
+
strategy: 'image',
|
|
61
|
+
nodeId: args.id,
|
|
62
|
+
sourceKey: appKey(args.binaryKey),
|
|
63
|
+
binaryKey: appKey(args.binaryKey),
|
|
64
|
+
posterKey: appKey(args.posterKey),
|
|
65
|
+
...(args.needsDisplay ? { displayKey: appKey(args.displayKey) } : {}),
|
|
66
|
+
});
|
|
67
|
+
const job = await poll(jobId);
|
|
68
|
+
if (job.status !== 'ready' || !job.result?.hasThumbnail)
|
|
69
|
+
return { hasThumbnail: false };
|
|
70
|
+
return { hasThumbnail: true };
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
// The "browser-renderable image ... failure maps to hasThumbnail false" fixture test
|
|
74
|
+
// deliberately drives this path — tagged `[expected-in-tests]` (grep-filterable)
|
|
75
|
+
// rather than silenced, so a real binary-server outage still surfaces.
|
|
76
|
+
console.warn(`[binaryServerProcessing][expected-in-tests] image job errored for ${args.id}: ${err instanceof Error ? err.message : err}`);
|
|
77
|
+
return { hasThumbnail: false };
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
return { videoProcessor, imageDerivatives };
|
|
81
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// binary-server MediaStore adapter. binary-server (Bun/SQLite, RS256 token-gated, Range-capable)
|
|
2
|
+
// is a production storage path: a home/edge file service the app signs short-lived tokens for.
|
|
3
|
+
// User-facing downloads REDIRECT (303) to the signed edge URL rather than proxying bytes back
|
|
4
|
+
// through the app; server-side reads (transcode source, checks) stream locally via getRange.
|
|
5
|
+
//
|
|
6
|
+
// The RS256 signer is INJECTED — the app holds the private key (binary-server holds only the
|
|
7
|
+
// public key). cursedbelt carries no key material and no asymmetric-crypto specifics; it just
|
|
8
|
+
// calls `signFileToken` with the claims binary-server expects.
|
|
9
|
+
export function createBinaryServerStore(cfg) {
|
|
10
|
+
const appKey = (key) => `${cfg.appId}/${key}`;
|
|
11
|
+
const mediaUrl = async (key, extra) => {
|
|
12
|
+
const token = await cfg.signFileToken({ k: appKey(key), ...extra });
|
|
13
|
+
return `${cfg.baseUrl}/media/${appKey(key)}?token=${encodeURIComponent(token)}`;
|
|
14
|
+
};
|
|
15
|
+
const uploadUrl = async (key) => {
|
|
16
|
+
const token = await cfg.signFileToken({ k: appKey(key) });
|
|
17
|
+
return `${cfg.baseUrl}/upload/${appKey(key)}?token=${encodeURIComponent(token)}`;
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
async put(key, bytes, mime) {
|
|
21
|
+
const res = await fetch(await uploadUrl(key), {
|
|
22
|
+
method: 'PUT',
|
|
23
|
+
body: new Blob([bytes], { type: mime }),
|
|
24
|
+
});
|
|
25
|
+
if (!res.ok)
|
|
26
|
+
throw new Error(`binary-server put ${key}: ${res.status}`);
|
|
27
|
+
},
|
|
28
|
+
async putStream(key, body, mime, opts) {
|
|
29
|
+
const headers = { 'content-type': mime };
|
|
30
|
+
if (opts?.contentLength != null)
|
|
31
|
+
headers['content-length'] = String(opts.contentLength);
|
|
32
|
+
const res = await fetch(await uploadUrl(key), {
|
|
33
|
+
method: 'PUT',
|
|
34
|
+
body,
|
|
35
|
+
headers,
|
|
36
|
+
// A web ReadableStream body requires duplex: 'half' per the fetch streaming spec.
|
|
37
|
+
duplex: 'half',
|
|
38
|
+
});
|
|
39
|
+
if (!res.ok)
|
|
40
|
+
throw new Error(`binary-server putStream ${key}: ${res.status}`);
|
|
41
|
+
},
|
|
42
|
+
async get(key) {
|
|
43
|
+
const res = await fetch(await mediaUrl(key));
|
|
44
|
+
if (res.status === 404)
|
|
45
|
+
return null;
|
|
46
|
+
if (!res.ok)
|
|
47
|
+
throw new Error(`binary-server get ${key}: ${res.status}`);
|
|
48
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
49
|
+
},
|
|
50
|
+
async remove(key) {
|
|
51
|
+
// binary-server gates DELETE on BOTH the internal secret AND a per-op, path-scoped RS256
|
|
52
|
+
// token carrying op:'delete' (owner ruling #10, defense in depth). Sign+send both.
|
|
53
|
+
const token = await cfg.signFileToken({ k: appKey(key), op: 'delete' });
|
|
54
|
+
const res = await fetch(`${cfg.baseUrl}/media/${appKey(key)}?token=${encodeURIComponent(token)}`, {
|
|
55
|
+
method: 'DELETE',
|
|
56
|
+
headers: cfg.internalSecret ? { 'x-internal-secret': cfg.internalSecret } : {},
|
|
57
|
+
});
|
|
58
|
+
if (!res.ok && res.status !== 404)
|
|
59
|
+
throw new Error(`binary-server remove ${key}: ${res.status}`);
|
|
60
|
+
},
|
|
61
|
+
async removePrefix(prefix) {
|
|
62
|
+
// The delete token's exact-key claim is the container path; bs derives the tree from it
|
|
63
|
+
// plus ?container=1. Same two-barrier gate as remove().
|
|
64
|
+
const token = await cfg.signFileToken({ k: appKey(prefix), op: 'delete' });
|
|
65
|
+
const res = await fetch(`${cfg.baseUrl}/media/${appKey(prefix)}?container=1&token=${encodeURIComponent(token)}`, {
|
|
66
|
+
method: 'DELETE',
|
|
67
|
+
headers: cfg.internalSecret ? { 'x-internal-secret': cfg.internalSecret } : {},
|
|
68
|
+
});
|
|
69
|
+
if (!res.ok && res.status !== 404) {
|
|
70
|
+
throw new Error(`binary-server removePrefix ${prefix}: ${res.status}`);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
async stat(key) {
|
|
74
|
+
// A 0-0 range is the cheapest way to learn total size (Content-Range: …/<total>).
|
|
75
|
+
const res = await fetch(await mediaUrl(key), { headers: { Range: 'bytes=0-0' } });
|
|
76
|
+
if (res.status === 404)
|
|
77
|
+
return null;
|
|
78
|
+
const cr = res.headers.get('content-range');
|
|
79
|
+
const total = cr ? Number(cr.split('/')[1]) : Number(res.headers.get('content-length'));
|
|
80
|
+
return Number.isFinite(total) ? { size: total } : null;
|
|
81
|
+
},
|
|
82
|
+
async getRange(key, range) {
|
|
83
|
+
const headers = {};
|
|
84
|
+
if (range)
|
|
85
|
+
headers.Range = `bytes=${range.start}-${range.end}`;
|
|
86
|
+
const res = await fetch(await mediaUrl(key), { headers });
|
|
87
|
+
if (res.status === 404 || !res.body)
|
|
88
|
+
return null;
|
|
89
|
+
return { stream: res.body };
|
|
90
|
+
},
|
|
91
|
+
async redirectUrl(key, opts) {
|
|
92
|
+
return mediaUrl(key, { fn: opts.filename, dl: 'inline' });
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { mkdir, rm, unlink } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
// Local-disk MediaStore (the dev default). Bun-native: Bun.file/Bun.write handle web streams
|
|
4
|
+
// and byte-range slices directly, so there is no node:stream on the hot path. Keys are
|
|
5
|
+
// generated server-side (owner/id…) but we still guard against path traversal so a stored key
|
|
6
|
+
// can never escape the media root.
|
|
7
|
+
export function createDiskStore(root) {
|
|
8
|
+
const resolveKey = (key) => {
|
|
9
|
+
const full = path.join(root, key);
|
|
10
|
+
const rel = path.relative(root, full);
|
|
11
|
+
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
12
|
+
throw new Error(`Invalid media key: ${key}`);
|
|
13
|
+
}
|
|
14
|
+
return full;
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
async put(key, bytes) {
|
|
18
|
+
// Bun.write creates intermediate directories automatically.
|
|
19
|
+
await Bun.write(resolveKey(key), bytes);
|
|
20
|
+
},
|
|
21
|
+
async putStream(key, body) {
|
|
22
|
+
const full = resolveKey(key);
|
|
23
|
+
// Grab the reader BEFORE any real await: in Bun 1.3.x a request-body stream's
|
|
24
|
+
// internals detach across an I/O tick, after which releaseLock() (and the
|
|
25
|
+
// async iterator) throw "undefined is not a function" — 500ing every upload.
|
|
26
|
+
const reader = body.getReader();
|
|
27
|
+
await mkdir(path.dirname(full), { recursive: true });
|
|
28
|
+
// Stream through a Bun FileSink — peak memory is one chunk. (NB: `Bun.write(full,
|
|
29
|
+
// new Response(body))` HANGS on a web ReadableStream in Bun 1.3.x, so we pump manually.)
|
|
30
|
+
const writer = Bun.file(full).writer();
|
|
31
|
+
try {
|
|
32
|
+
while (true) {
|
|
33
|
+
const { done, value } = await reader.read();
|
|
34
|
+
if (done)
|
|
35
|
+
break;
|
|
36
|
+
writer.write(value);
|
|
37
|
+
}
|
|
38
|
+
await writer.end();
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
try {
|
|
42
|
+
reader.releaseLock();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Same Bun 1.3.x detach bug via a caller-side await (e.g. an async auth
|
|
46
|
+
// guard): reads still complete, only this cleanup call explodes — and by
|
|
47
|
+
// here the stream is fully consumed, so there is nothing left to release.
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
async get(key) {
|
|
52
|
+
const file = Bun.file(resolveKey(key));
|
|
53
|
+
if (!(await file.exists()))
|
|
54
|
+
return null;
|
|
55
|
+
return new Uint8Array(await file.arrayBuffer());
|
|
56
|
+
},
|
|
57
|
+
async remove(key) {
|
|
58
|
+
try {
|
|
59
|
+
await unlink(resolveKey(key));
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
if (err?.code !== 'ENOENT')
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
async removePrefix(prefix) {
|
|
67
|
+
await rm(resolveKey(prefix), { recursive: true, force: true });
|
|
68
|
+
},
|
|
69
|
+
async stat(key) {
|
|
70
|
+
const file = Bun.file(resolveKey(key));
|
|
71
|
+
if (!(await file.exists()))
|
|
72
|
+
return null;
|
|
73
|
+
return { size: file.size };
|
|
74
|
+
},
|
|
75
|
+
async getRange(key, range) {
|
|
76
|
+
const file = Bun.file(resolveKey(key));
|
|
77
|
+
if (!(await file.exists()))
|
|
78
|
+
return null;
|
|
79
|
+
// Bun.file.slice(start, end) is exclusive-end; our ranges are inclusive.
|
|
80
|
+
const blob = range ? file.slice(range.start, range.end + 1) : file;
|
|
81
|
+
return { stream: blob.stream() };
|
|
82
|
+
},
|
|
83
|
+
async localPath(key) {
|
|
84
|
+
const full = resolveKey(key);
|
|
85
|
+
return (await Bun.file(full).exists()) ? full : null;
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { MediaUrls } from '../sources';
|
|
2
|
+
import type { MediaGallerySource, MediaSource, PhotoSource } from '../types';
|
|
3
|
+
import type { FileUrls } from './fileRoutes';
|
|
4
|
+
import type { FileCatalogue, FileToPlayable } from './types';
|
|
5
|
+
/** Resolve a video FileRecord to a PlayableVideo with tokenised URLs. Non-video ⇒ null. */
|
|
6
|
+
export declare function createFileToPlayable(urls: MediaUrls, sourceId: string): FileToPlayable;
|
|
7
|
+
/** Expose a FileCatalogue as a video-only `MediaSource` — the gallery is a view, not a store. */
|
|
8
|
+
export declare function createCatalogueVideoSource(cfg: {
|
|
9
|
+
id: string;
|
|
10
|
+
title: string;
|
|
11
|
+
catalogue: FileCatalogue;
|
|
12
|
+
urls: MediaUrls;
|
|
13
|
+
}): MediaSource;
|
|
14
|
+
/** Expose a FileCatalogue as an image-only `PhotoSource` — a view, not a store. */
|
|
15
|
+
export declare function createCataloguePhotoSource(cfg: {
|
|
16
|
+
id: string;
|
|
17
|
+
title: string;
|
|
18
|
+
catalogue: FileCatalogue;
|
|
19
|
+
fileUrls: FileUrls;
|
|
20
|
+
mediaUrls: MediaUrls;
|
|
21
|
+
}): PhotoSource;
|
|
22
|
+
/** Expose a FileCatalogue as a `MediaGallerySource` — photos + videos in one feed.
|
|
23
|
+
* Videos are tokenised under `videoSourceId` (must match the registered video source so
|
|
24
|
+
* `mountMediaRoutes` serves their streams); photo posters/thumbnails under this source's `id`. */
|
|
25
|
+
export declare function createCatalogueMediaSource(cfg: {
|
|
26
|
+
id: string;
|
|
27
|
+
title: string;
|
|
28
|
+
catalogue: FileCatalogue;
|
|
29
|
+
urls: MediaUrls;
|
|
30
|
+
fileUrls: FileUrls;
|
|
31
|
+
/** SourceId the video stream tokens are minted under. Default `id`. */
|
|
32
|
+
videoSourceId?: string;
|
|
33
|
+
}): MediaGallerySource;
|