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,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The drop-folder scraper — the reusable half.
|
|
3
|
+
*
|
|
4
|
+
* Owner's ask, 2026-08-13: *"Do this to prepare a reusable strategy for multiple apps to get
|
|
5
|
+
* intelligent processing for binary-server. Some functionality may be reusable in multiple
|
|
6
|
+
* apps in different ways and can go in cb where standardized app functionality is shared. The
|
|
7
|
+
* specific ingestion logic that only binary-server or one app needs can go to the specific
|
|
8
|
+
* app."* … *"Make this tool reusable in case we need something like it on other folders
|
|
9
|
+
* later."*
|
|
10
|
+
*
|
|
11
|
+
* So: WALKING a drop folder, deciding a file has finished copying, sorting content from junk,
|
|
12
|
+
* deleting only what has been confirmed elsewhere, and leaving nothing behind — all of that is
|
|
13
|
+
* the same for music, family photographs, collections videos and notes documents, and all of
|
|
14
|
+
* it is here. What a file MEANS — which album, which artist, which collection — is the app's,
|
|
15
|
+
* and none of it is here.
|
|
16
|
+
*
|
|
17
|
+
* ── 🔴 Three rules that look like paranoia and are not ─────────────────────────────────
|
|
18
|
+
*
|
|
19
|
+
* 1. **A file is deleted only after the destination CONFIRMS it.** The dropzone is the one
|
|
20
|
+
* place the owner's copy may be the only copy: they dragged it in expecting it to be taken.
|
|
21
|
+
* A sweep that deletes on "the upload didn't throw" turns any catalog failure into data
|
|
22
|
+
* loss. The handler returns `stored`/`duplicate` and only then does the original go.
|
|
23
|
+
*
|
|
24
|
+
* 2. **A file must measure the same size twice before it is touched.** Dropping a 4 GB video
|
|
25
|
+
* into a folder is not atomic. Without this the sweep ingests a truncated file, reports
|
|
26
|
+
* success, and deletes the real one as it is still being written. notes' ingester and
|
|
27
|
+
* collections' both learned this the same way.
|
|
28
|
+
*
|
|
29
|
+
* 3. **One bad file never stops the sweep.** Every handler outcome is per-file, and a throw is
|
|
30
|
+
* caught and recorded. The owner's instruction is explicit about the duplicate case — *"This
|
|
31
|
+
* should not stall uploading the rest of the in progress uploads"* — and it generalizes: a
|
|
32
|
+
* dropzone with one unreadable file in it must still drain the other 4,000.
|
|
33
|
+
*/
|
|
34
|
+
import { readdir, rm, rmdir, stat } from "node:fs/promises";
|
|
35
|
+
import { join, relative } from "node:path";
|
|
36
|
+
/** OS bookkeeping and editor scratch. Never content, in any app. */
|
|
37
|
+
const OS_JUNK = new Set([
|
|
38
|
+
".DS_Store",
|
|
39
|
+
".localized",
|
|
40
|
+
"Icon\r",
|
|
41
|
+
"Thumbs.db",
|
|
42
|
+
"desktop.ini",
|
|
43
|
+
"README.md",
|
|
44
|
+
]);
|
|
45
|
+
const PARTIAL_SUFFIXES = [".download", ".crdownload", ".part", ".partial", ".tmp"];
|
|
46
|
+
/** A name that is OS noise, editor scratch, or a copy still in flight. */
|
|
47
|
+
export function isJunkName(name) {
|
|
48
|
+
if (OS_JUNK.has(name))
|
|
49
|
+
return true;
|
|
50
|
+
// A dotfile in a drop folder is the operating system's or another tool's state. The owner
|
|
51
|
+
// drops content, and content does not begin with a dot.
|
|
52
|
+
if (name.startsWith("."))
|
|
53
|
+
return true;
|
|
54
|
+
if (name.startsWith("._"))
|
|
55
|
+
return true; // AppleDouble resource forks
|
|
56
|
+
return PARTIAL_SUFFIXES.some((s) => name.toLowerCase().endsWith(s));
|
|
57
|
+
}
|
|
58
|
+
const extOf = (name) => {
|
|
59
|
+
const dot = name.lastIndexOf(".");
|
|
60
|
+
return dot > 0 ? name.slice(dot).toLowerCase() : "";
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Every candidate file under `root`, deepest-last, with each one's sibling listing.
|
|
64
|
+
*
|
|
65
|
+
* Junk is NOT filtered out here — it is returned like anything else, because a sweep whose job
|
|
66
|
+
* includes *"if it's a wrong type of file delete it"* has to see it in order to delete it.
|
|
67
|
+
* {@link isJunkName} is exported so a handler can classify without re-deriving the list.
|
|
68
|
+
*/
|
|
69
|
+
export async function scanDropzone(root, opts = {}) {
|
|
70
|
+
const skip = new Set(opts.skipDirs ?? []);
|
|
71
|
+
const out = [];
|
|
72
|
+
const walk = async (dir) => {
|
|
73
|
+
if (opts.limit !== undefined && out.length >= opts.limit)
|
|
74
|
+
return;
|
|
75
|
+
let entries;
|
|
76
|
+
try {
|
|
77
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return; // vanished mid-walk — a dropzone is a moving target by nature
|
|
81
|
+
}
|
|
82
|
+
const siblings = opts.captureSiblings
|
|
83
|
+
? entries.filter((e) => e.isFile()).map((e) => e.name)
|
|
84
|
+
: [];
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
if (opts.limit !== undefined && out.length >= opts.limit)
|
|
87
|
+
return;
|
|
88
|
+
const full = join(dir, entry.name);
|
|
89
|
+
if (entry.isDirectory()) {
|
|
90
|
+
if (skip.has(entry.name))
|
|
91
|
+
continue;
|
|
92
|
+
await walk(full);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (!entry.isFile())
|
|
96
|
+
continue;
|
|
97
|
+
try {
|
|
98
|
+
const info = await stat(full);
|
|
99
|
+
out.push({
|
|
100
|
+
path: full,
|
|
101
|
+
relativePath: relative(root, full),
|
|
102
|
+
name: entry.name,
|
|
103
|
+
ext: extOf(entry.name),
|
|
104
|
+
size: info.size,
|
|
105
|
+
mtimeMs: info.mtimeMs,
|
|
106
|
+
siblings,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
/* gone between readdir and stat */
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
await walk(root);
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* How old an EMPTY file has to be before it is believed. See {@link isStable}.
|
|
119
|
+
*
|
|
120
|
+
* A file that has just been created and has no bytes yet is almost certainly mid-copy; the
|
|
121
|
+
* same file a minute later really is empty.
|
|
122
|
+
*/
|
|
123
|
+
export const EMPTY_FILE_GRACE_MS = 60_000;
|
|
124
|
+
/**
|
|
125
|
+
* Has this file finished being copied in? See rule 2 in the header.
|
|
126
|
+
*
|
|
127
|
+
* 🔴 A zero-byte file needs its own answer, and getting it wrong strands the folder forever.
|
|
128
|
+
* The obvious test — "same size twice AND non-empty" — treats a genuinely empty file as
|
|
129
|
+
* permanently mid-copy: it is never handled, never deleted, and so the dropzone never empties,
|
|
130
|
+
* which is the one outcome the owner's brief measures success by (*"in the end there should be
|
|
131
|
+
* nothing left"*). Measured on a first run: three real files, all 0 bytes, reported as "still
|
|
132
|
+
* copying" on every sweep for as long as they sat there.
|
|
133
|
+
*
|
|
134
|
+
* Emptiness is only evidence of an unfinished copy while the file is NEW, so age decides. A
|
|
135
|
+
* file created a minute ago with no bytes in it is empty, not arriving.
|
|
136
|
+
*/
|
|
137
|
+
export async function isStable(file, stabilityMs = 750) {
|
|
138
|
+
await new Promise((resolve) => setTimeout(resolve, stabilityMs));
|
|
139
|
+
try {
|
|
140
|
+
const now = await stat(file.path);
|
|
141
|
+
if (now.size !== file.size)
|
|
142
|
+
return false; // still growing
|
|
143
|
+
if (now.size > 0)
|
|
144
|
+
return true;
|
|
145
|
+
return Date.now() - now.mtimeMs > EMPTY_FILE_GRACE_MS;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return false; // taken by something else, or never really there
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Remove directories left empty by a sweep, deepest first — and never the root.
|
|
153
|
+
*
|
|
154
|
+
* 🔴 `rmdir` refuses a non-empty directory, and that refusal IS the safety property. A
|
|
155
|
+
* recursive delete here would take a file the sweep deliberately chose not to ingest — a held
|
|
156
|
+
* duplicate, a failure left in place for the owner to look at — which is precisely the set of
|
|
157
|
+
* files that must survive.
|
|
158
|
+
*/
|
|
159
|
+
export async function pruneEmptyDirs(root, dir = root) {
|
|
160
|
+
let removed = 0;
|
|
161
|
+
let entries;
|
|
162
|
+
try {
|
|
163
|
+
entries = await readdir(dir);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
for (const name of entries) {
|
|
169
|
+
const full = join(dir, name);
|
|
170
|
+
try {
|
|
171
|
+
if ((await stat(full)).isDirectory())
|
|
172
|
+
removed += await pruneEmptyDirs(root, full);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
/* gone */
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (dir === root)
|
|
179
|
+
return removed;
|
|
180
|
+
try {
|
|
181
|
+
await rmdir(dir);
|
|
182
|
+
return removed + 1;
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return removed; // not empty — the right outcome, and not an error
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Walk a dropzone, hand every file to `handle`, and leave nothing behind that was dealt with.
|
|
190
|
+
*
|
|
191
|
+
* 🔴 The DELETION is here, and it is deliberately not the handler's job. Every app would
|
|
192
|
+
* otherwise reimplement rule 1, and the one that got it wrong would lose the owner's only copy
|
|
193
|
+
* silently. A handler says what happened; this decides what that means for the file on disk.
|
|
194
|
+
*/
|
|
195
|
+
export async function sweepDropzone(root, handle, opts = {}) {
|
|
196
|
+
const report = {
|
|
197
|
+
scanned: 0,
|
|
198
|
+
stored: 0,
|
|
199
|
+
duplicate: 0,
|
|
200
|
+
discarded: 0,
|
|
201
|
+
held: 0,
|
|
202
|
+
failed: [],
|
|
203
|
+
unstable: [],
|
|
204
|
+
bytesRemoved: 0,
|
|
205
|
+
emptyDirsRemoved: 0,
|
|
206
|
+
remaining: 0,
|
|
207
|
+
};
|
|
208
|
+
const files = await scanDropzone(root, opts);
|
|
209
|
+
for (const [index, file] of files.entries()) {
|
|
210
|
+
report.scanned++;
|
|
211
|
+
opts.onProgress?.(index + 1, files.length);
|
|
212
|
+
if (!(await isStable(file, opts.stabilityMs))) {
|
|
213
|
+
report.unstable.push(file.relativePath);
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
let outcome;
|
|
217
|
+
try {
|
|
218
|
+
outcome = opts.dryRun ? { kind: "held", detail: "dry run" } : await handle(file);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
// Rule 3: a handler that throws costs one file, never the sweep.
|
|
222
|
+
outcome = {
|
|
223
|
+
kind: "failed",
|
|
224
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
switch (outcome.kind) {
|
|
228
|
+
case "stored":
|
|
229
|
+
case "duplicate":
|
|
230
|
+
case "discard": {
|
|
231
|
+
if (outcome.kind === "stored")
|
|
232
|
+
report.stored++;
|
|
233
|
+
else if (outcome.kind === "duplicate")
|
|
234
|
+
report.duplicate++;
|
|
235
|
+
else
|
|
236
|
+
report.discarded++;
|
|
237
|
+
if (opts.dryRun)
|
|
238
|
+
break;
|
|
239
|
+
try {
|
|
240
|
+
await rm(file.path);
|
|
241
|
+
report.bytesRemoved += file.size;
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
// The bytes are safe at the destination; only the tidying failed. Reporting it
|
|
245
|
+
// as a FAILURE would send the owner looking for a file that arrived perfectly.
|
|
246
|
+
report.failed.push({
|
|
247
|
+
relativePath: file.relativePath,
|
|
248
|
+
error: `filed, but the original could not be removed: ${error instanceof Error ? error.message : String(error)}`,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
case "held":
|
|
254
|
+
report.held++;
|
|
255
|
+
break;
|
|
256
|
+
case "failed":
|
|
257
|
+
report.failed.push({ relativePath: file.relativePath, error: outcome.detail });
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (!opts.dryRun)
|
|
262
|
+
report.emptyDirsRemoved = await pruneEmptyDirs(root);
|
|
263
|
+
report.remaining = (await scanDropzone(root, { skipDirs: opts.skipDirs })).length;
|
|
264
|
+
return report;
|
|
265
|
+
}
|
|
266
|
+
/** A one-line summary — every consumer prints one, and they should read alike. */
|
|
267
|
+
export const describeSweep = (report) => `${report.stored} added, ${report.duplicate} already had, ${report.discarded} discarded, ` +
|
|
268
|
+
`${report.held} held, ${report.failed.length} failed, ${report.unstable.length} still copying` +
|
|
269
|
+
(report.bytesRemoved > 0
|
|
270
|
+
? ` · ${(report.bytesRemoved / 1024 ** 3).toFixed(2)} GB freed from the queue`
|
|
271
|
+
: "") +
|
|
272
|
+
(report.remaining > 0 ? ` · ${report.remaining} left in the folder` : " · folder is empty");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side re-export of the canonical error primitives, which now live in the
|
|
3
|
+
* framework-free {@link ../shared/errors} module so cursedshell's plugin-pure layer
|
|
4
|
+
* can import the SAME `ApiError` + envelope without pulling any server code
|
|
5
|
+
* (`cursedbelt-core/errors` subpath). Server modules keep importing from `./errors`.
|
|
6
|
+
*/
|
|
7
|
+
export { AppError, type AppErrorSummary, ApiError, type ApiErrorOptions, type ErrorEnvelope, isAppError, isApiError, type ToErrorEnvelopeOptions, toErrorEnvelope, type ValidationIssue, VALIDATION_ERROR_CODE, VALIDATION_STATUS, toValidationIssues, validationEnvelope, } from 'cursedbelt-core/errors';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side re-export of the canonical error primitives, which now live in the
|
|
3
|
+
* framework-free {@link ../shared/errors} module so cursedshell's plugin-pure layer
|
|
4
|
+
* can import the SAME `ApiError` + envelope without pulling any server code
|
|
5
|
+
* (`cursedbelt-core/errors` subpath). Server modules keep importing from `./errors`.
|
|
6
|
+
*/
|
|
7
|
+
export { AppError, ApiError, isAppError, isApiError, toErrorEnvelope, VALIDATION_ERROR_CODE, VALIDATION_STATUS, toValidationIssues, validationEnvelope, } from 'cursedbelt-core/errors';
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wiring a REAL argon2id into the KDF seam (01 §3.3/§3.4, finding 1.2).
|
|
3
|
+
*
|
|
4
|
+
* cwip ships no KDF — it is zero-dependency by contract — so
|
|
5
|
+
* `setArgon2idDeriver` sat inert: nothing registered a binding, and every
|
|
6
|
+
* `unlock()` would have thrown `GUARD_KDF_UNAVAILABLE` the first time a real
|
|
7
|
+
* user tried it in production. `assertArgon2idReady()` converts that into a boot
|
|
8
|
+
* failure; this module is the other half — the adapter that makes registering a
|
|
9
|
+
* binding a one-liner, and the reason a host has no excuse to hand-roll one.
|
|
10
|
+
*
|
|
11
|
+
* The requirements on a binding are not negotiable, and the adapter enforces
|
|
12
|
+
* them rather than documenting them:
|
|
13
|
+
*
|
|
14
|
+
* * **Raw bytes out.** A binding that returns a PHC/base64 STRING is a
|
|
15
|
+
* `key-material-as-string` violation regardless of how strong the KDF is —
|
|
16
|
+
* a JS string is immutable and GC-managed, so the key lingers in
|
|
17
|
+
* unallocated RAM until the collector happens to overwrite it.
|
|
18
|
+
* * **Caller-supplied salt.** Anything that generates its own salt (e.g.
|
|
19
|
+
* `Bun.password`) cannot re-derive the key for an existing envelope, so it
|
|
20
|
+
* cannot open a secret it sealed yesterday.
|
|
21
|
+
* * **Synchronous.** The seam is sync on purpose and its throughput ceiling is
|
|
22
|
+
* documented on `Argon2idDeriver`; an async binding would hand back a
|
|
23
|
+
* promise AND (usually) a string.
|
|
24
|
+
*/
|
|
25
|
+
import { type Argon2idDeriver } from 'cwip/guard';
|
|
26
|
+
/**
|
|
27
|
+
* The shape of a raw, synchronous argon2id binding, in the REFERENCE
|
|
28
|
+
* implementation's vocabulary: `algorithm` is the argon2 variant number
|
|
29
|
+
* (2 = argon2id) and `version` is the argon2 algorithm version as the spec
|
|
30
|
+
* writes it (`0x10` / `0x13`) — the same number the envelope's `kdf.ver`
|
|
31
|
+
* records.
|
|
32
|
+
*
|
|
33
|
+
* `@node-rs/argon2`'s `hashRawSync` is shape-compatible but NOT
|
|
34
|
+
* vocabulary-compatible: its `version` is a NAPI enum (`Version.V0x10 = 0`,
|
|
35
|
+
* `Version.V0x13 = 1`), so handing it `0x13` is an `InvalidArg` throw on every
|
|
36
|
+
* single derivation. {@link nodeRsArgon2idBinding} is the (tiny) translation,
|
|
37
|
+
* and {@link registerNodeRsArgon2id} applies it — libsodium's `crypto_pwhash`
|
|
38
|
+
* needs a comparable shim.
|
|
39
|
+
*/
|
|
40
|
+
export interface RawArgon2idBinding {
|
|
41
|
+
hashRawSync(password: Uint8Array, options: {
|
|
42
|
+
salt: Uint8Array;
|
|
43
|
+
/** Memory cost in KiB. */
|
|
44
|
+
memoryCost: number;
|
|
45
|
+
/** Time cost (iterations). */
|
|
46
|
+
timeCost: number;
|
|
47
|
+
/** Parallelism (lanes). */
|
|
48
|
+
parallelism: number;
|
|
49
|
+
/** Output length in bytes. */
|
|
50
|
+
outputLen: number;
|
|
51
|
+
/** argon2 variant: 2 = argon2id. */
|
|
52
|
+
algorithm?: number;
|
|
53
|
+
/** argon2 algorithm version (0x10 | 0x13). */
|
|
54
|
+
version?: number;
|
|
55
|
+
}): Uint8Array;
|
|
56
|
+
}
|
|
57
|
+
/** argon2id's variant number in the `@node-rs/argon2` / reference-implementation vocabulary. */
|
|
58
|
+
export declare const ARGON2ID_ALGORITHM = 2;
|
|
59
|
+
/**
|
|
60
|
+
* Build a deriver from a raw binding, checking the two properties that make it
|
|
61
|
+
* usable as key material. The length check is not paranoia: a binding that
|
|
62
|
+
* silently truncates would weaken every secret sealed under it, and the failure
|
|
63
|
+
* would look like nothing at all.
|
|
64
|
+
*/
|
|
65
|
+
export declare const argon2idDeriverFrom: (binding: RawArgon2idBinding) => Argon2idDeriver;
|
|
66
|
+
/**
|
|
67
|
+
* Translate a `@node-rs/argon2` module into a {@link RawArgon2idBinding}.
|
|
68
|
+
*
|
|
69
|
+
* The whole translation is the `version` field, and skipping it is not a
|
|
70
|
+
* cosmetic bug: node-rs validates the enum, so an unmapped `0x13` throws
|
|
71
|
+
* `InvalidArg` from the native layer on EVERY derivation — the first unlock, the
|
|
72
|
+
* first login, every password verify. That failure is invisible until a host
|
|
73
|
+
* actually registers this binding, which is exactly what the local host now does
|
|
74
|
+
* at boot.
|
|
75
|
+
*/
|
|
76
|
+
export declare const nodeRsArgon2idBinding: (module: RawArgon2idBinding) => RawArgon2idBinding;
|
|
77
|
+
/** Register a raw binding as the process-wide deriver, then prove the seam is armed. */
|
|
78
|
+
export declare const registerArgon2idBinding: (binding: RawArgon2idBinding) => void;
|
|
79
|
+
/**
|
|
80
|
+
* Register `@node-rs/argon2` if the host installed it.
|
|
81
|
+
*
|
|
82
|
+
* It is an OPTIONAL peer dependency: a generated app with no GuardEngine surface
|
|
83
|
+
* should not carry a native module, and an app that has one must make the choice
|
|
84
|
+
* explicitly. The specifier is held in a variable so bundlers and `tsc` do not
|
|
85
|
+
* try to resolve a package that may not be there.
|
|
86
|
+
*
|
|
87
|
+
* @throws {AppError} `GUARD_KDF_BINDING_MISSING` naming the install command —
|
|
88
|
+
* an unhelpful `ERR_MODULE_NOT_FOUND` at boot is exactly the failure this
|
|
89
|
+
* module exists to prevent.
|
|
90
|
+
*
|
|
91
|
+
* The same indirection that hides the specifier from a bundler hides it from
|
|
92
|
+
* every static import walker, so the guard's peer map would report
|
|
93
|
+
* this edge as absent. The pragma is what puts it back.
|
|
94
|
+
*
|
|
95
|
+
* @peer @node-rs/argon2
|
|
96
|
+
*/
|
|
97
|
+
export declare const registerNodeRsArgon2id: () => Promise<void>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wiring a REAL argon2id into the KDF seam (01 §3.3/§3.4, finding 1.2).
|
|
3
|
+
*
|
|
4
|
+
* cwip ships no KDF — it is zero-dependency by contract — so
|
|
5
|
+
* `setArgon2idDeriver` sat inert: nothing registered a binding, and every
|
|
6
|
+
* `unlock()` would have thrown `GUARD_KDF_UNAVAILABLE` the first time a real
|
|
7
|
+
* user tried it in production. `assertArgon2idReady()` converts that into a boot
|
|
8
|
+
* failure; this module is the other half — the adapter that makes registering a
|
|
9
|
+
* binding a one-liner, and the reason a host has no excuse to hand-roll one.
|
|
10
|
+
*
|
|
11
|
+
* The requirements on a binding are not negotiable, and the adapter enforces
|
|
12
|
+
* them rather than documenting them:
|
|
13
|
+
*
|
|
14
|
+
* * **Raw bytes out.** A binding that returns a PHC/base64 STRING is a
|
|
15
|
+
* `key-material-as-string` violation regardless of how strong the KDF is —
|
|
16
|
+
* a JS string is immutable and GC-managed, so the key lingers in
|
|
17
|
+
* unallocated RAM until the collector happens to overwrite it.
|
|
18
|
+
* * **Caller-supplied salt.** Anything that generates its own salt (e.g.
|
|
19
|
+
* `Bun.password`) cannot re-derive the key for an existing envelope, so it
|
|
20
|
+
* cannot open a secret it sealed yesterday.
|
|
21
|
+
* * **Synchronous.** The seam is sync on purpose and its throughput ceiling is
|
|
22
|
+
* documented on `Argon2idDeriver`; an async binding would hand back a
|
|
23
|
+
* promise AND (usually) a string.
|
|
24
|
+
*/
|
|
25
|
+
import { assertArgon2idReady, CC_ARGON2ID_VERSION, setArgon2idDeriver, } from 'cwip/guard';
|
|
26
|
+
import { AppError } from '../errors';
|
|
27
|
+
/** argon2id's variant number in the `@node-rs/argon2` / reference-implementation vocabulary. */
|
|
28
|
+
export const ARGON2ID_ALGORITHM = 2;
|
|
29
|
+
/**
|
|
30
|
+
* Build a deriver from a raw binding, checking the two properties that make it
|
|
31
|
+
* usable as key material. The length check is not paranoia: a binding that
|
|
32
|
+
* silently truncates would weaken every secret sealed under it, and the failure
|
|
33
|
+
* would look like nothing at all.
|
|
34
|
+
*/
|
|
35
|
+
export const argon2idDeriverFrom = (binding) => {
|
|
36
|
+
return (input) => {
|
|
37
|
+
const output = binding.hashRawSync(input.password, {
|
|
38
|
+
salt: input.salt,
|
|
39
|
+
memoryCost: input.params.m,
|
|
40
|
+
timeCost: input.params.t,
|
|
41
|
+
parallelism: input.params.p,
|
|
42
|
+
outputLen: input.keyLength,
|
|
43
|
+
algorithm: ARGON2ID_ALGORITHM,
|
|
44
|
+
// Honor the version the ENVELOPE was sealed with, not the binding's
|
|
45
|
+
// compile-time default: 0x10 and 0x13 produce different bytes for
|
|
46
|
+
// identical m/t/p/salt/password, which is why the envelope records it.
|
|
47
|
+
version: input.version ?? CC_ARGON2ID_VERSION,
|
|
48
|
+
});
|
|
49
|
+
if (typeof output === 'string')
|
|
50
|
+
throw new AppError('The registered argon2id binding returned a string. Key material must be raw bytes — a string cannot be zeroized (01 §3.4).', { code: 'GUARD_KDF_BINDING_INVALID', status: 500, category: 'security', isOperational: false });
|
|
51
|
+
if (!(output instanceof Uint8Array))
|
|
52
|
+
throw new AppError('The registered argon2id binding did not return a Uint8Array.', {
|
|
53
|
+
code: 'GUARD_KDF_BINDING_INVALID',
|
|
54
|
+
status: 500,
|
|
55
|
+
category: 'security',
|
|
56
|
+
isOperational: false,
|
|
57
|
+
});
|
|
58
|
+
return output;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* `@node-rs/argon2`'s `Version` enum, keyed by the argon2 version number the
|
|
63
|
+
* ENVELOPE records. Held here rather than imported so the adapter never has to
|
|
64
|
+
* load the optional native module to know how to talk to it.
|
|
65
|
+
*/
|
|
66
|
+
// 0x10 and 0x13 ARE the Argon2 version identifiers: the spec, the reference
|
|
67
|
+
// implementation and every envelope on disk write them in hex. Biome's autofix
|
|
68
|
+
// rewrites them as 16 and 19 — the same map and a worse one, because nobody
|
|
69
|
+
// reading an `$argon2id$v=19$` record would recognise the decimal.
|
|
70
|
+
// biome-ignore lint/complexity/useSimpleNumberKeys: see above — hex IS the spec's spelling
|
|
71
|
+
const NODE_RS_VERSION = { 0x10: 0, 0x13: 1 };
|
|
72
|
+
/**
|
|
73
|
+
* Translate a `@node-rs/argon2` module into a {@link RawArgon2idBinding}.
|
|
74
|
+
*
|
|
75
|
+
* The whole translation is the `version` field, and skipping it is not a
|
|
76
|
+
* cosmetic bug: node-rs validates the enum, so an unmapped `0x13` throws
|
|
77
|
+
* `InvalidArg` from the native layer on EVERY derivation — the first unlock, the
|
|
78
|
+
* first login, every password verify. That failure is invisible until a host
|
|
79
|
+
* actually registers this binding, which is exactly what the local host now does
|
|
80
|
+
* at boot.
|
|
81
|
+
*/
|
|
82
|
+
export const nodeRsArgon2idBinding = (module) => ({
|
|
83
|
+
hashRawSync(password, options) {
|
|
84
|
+
const declared = options.version ?? CC_ARGON2ID_VERSION;
|
|
85
|
+
const mapped = NODE_RS_VERSION[declared];
|
|
86
|
+
if (mapped === undefined)
|
|
87
|
+
throw new AppError(`argon2 version 0x${declared.toString(16)} is not one @node-rs/argon2 implements (0x10 or 0x13). The envelope asking for it cannot be opened by this binding — reseal it, or register a binding that supports the version.`, {
|
|
88
|
+
code: 'GUARD_KDF_BINDING_INVALID',
|
|
89
|
+
status: 500,
|
|
90
|
+
category: 'security',
|
|
91
|
+
isOperational: false,
|
|
92
|
+
context: { version: declared },
|
|
93
|
+
});
|
|
94
|
+
return module.hashRawSync(password, { ...options, version: mapped });
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
/** Register a raw binding as the process-wide deriver, then prove the seam is armed. */
|
|
98
|
+
export const registerArgon2idBinding = (binding) => {
|
|
99
|
+
setArgon2idDeriver(argon2idDeriverFrom(binding));
|
|
100
|
+
// Fail here rather than at the first unlock: this call is the whole point.
|
|
101
|
+
assertArgon2idReady();
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Register `@node-rs/argon2` if the host installed it.
|
|
105
|
+
*
|
|
106
|
+
* It is an OPTIONAL peer dependency: a generated app with no GuardEngine surface
|
|
107
|
+
* should not carry a native module, and an app that has one must make the choice
|
|
108
|
+
* explicitly. The specifier is held in a variable so bundlers and `tsc` do not
|
|
109
|
+
* try to resolve a package that may not be there.
|
|
110
|
+
*
|
|
111
|
+
* @throws {AppError} `GUARD_KDF_BINDING_MISSING` naming the install command —
|
|
112
|
+
* an unhelpful `ERR_MODULE_NOT_FOUND` at boot is exactly the failure this
|
|
113
|
+
* module exists to prevent.
|
|
114
|
+
*
|
|
115
|
+
* The same indirection that hides the specifier from a bundler hides it from
|
|
116
|
+
* every static import walker, so the guard's peer map would report
|
|
117
|
+
* this edge as absent. The pragma is what puts it back.
|
|
118
|
+
*
|
|
119
|
+
* @peer @node-rs/argon2
|
|
120
|
+
*/
|
|
121
|
+
export const registerNodeRsArgon2id = async () => {
|
|
122
|
+
const specifier = '@node-rs/argon2';
|
|
123
|
+
let loaded;
|
|
124
|
+
try {
|
|
125
|
+
loaded = (await import(specifier));
|
|
126
|
+
}
|
|
127
|
+
catch (cause) {
|
|
128
|
+
throw new AppError('GuardEngine needs an argon2id binding and `@node-rs/argon2` is not installed. Run `bun add @node-rs/argon2` in the app, or call registerArgon2idBinding(...) with your own raw, synchronous binding.', { code: 'GUARD_KDF_BINDING_MISSING', status: 500, category: 'security', isOperational: false, cause });
|
|
129
|
+
}
|
|
130
|
+
if (typeof loaded.hashRawSync !== 'function')
|
|
131
|
+
throw new AppError('`@node-rs/argon2` is installed but exposes no `hashRawSync` — it is too old for the raw-bytes seam.', {
|
|
132
|
+
code: 'GUARD_KDF_BINDING_INVALID',
|
|
133
|
+
status: 500,
|
|
134
|
+
category: 'security',
|
|
135
|
+
isOperational: false,
|
|
136
|
+
});
|
|
137
|
+
registerArgon2idBinding(nodeRsArgon2idBinding(loaded));
|
|
138
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// The GuardEngine server wiring (02 §4): the argon2id binding adapter that arms
|
|
2
|
+
// cwip's KDF seam, and the Ed25519 session signer that mints and revokes.
|
|
3
|
+
export * from './argon2Binding';
|
|
4
|
+
export * from './verifier';
|
|
5
|
+
export * from './revocationStore';
|
|
6
|
+
export * from './sessionSigner';
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { createInProcessPasswordVerifier, type PasswordVerifierPort } from './passwordVerifier';
|
|
2
|
+
/** Raised when the worker thread dies, fails to start, or is disposed mid-flight. */
|
|
3
|
+
export declare const GUARD_KDF_WORKER_FAILED = "GUARD_KDF_WORKER_FAILED";
|
|
4
|
+
/** Raised when the worker does not answer within the configured budget. */
|
|
5
|
+
export declare const GUARD_KDF_WORKER_TIMEOUT = "GUARD_KDF_WORKER_TIMEOUT";
|
|
6
|
+
/**
|
|
7
|
+
* Default per-request ceiling. Generous relative to a ~250 ms derivation on
|
|
8
|
+
* purpose: this is a liveness backstop for a wedged thread, not a latency SLO,
|
|
9
|
+
* and a tight budget here would turn a loaded machine into a login outage.
|
|
10
|
+
*/
|
|
11
|
+
export declare const KDF_WORKER_DEFAULT_TIMEOUT_MS = 15000;
|
|
12
|
+
export type KdfWorkerRequest = {
|
|
13
|
+
id: number;
|
|
14
|
+
kind: 'seal';
|
|
15
|
+
userId: string;
|
|
16
|
+
password: Uint8Array;
|
|
17
|
+
} | {
|
|
18
|
+
id: number;
|
|
19
|
+
kind: 'verify';
|
|
20
|
+
userId: string;
|
|
21
|
+
envelopeJson: string;
|
|
22
|
+
password: Uint8Array;
|
|
23
|
+
};
|
|
24
|
+
export type KdfWorkerResponse = {
|
|
25
|
+
id: number;
|
|
26
|
+
ok: true;
|
|
27
|
+
value: string | boolean;
|
|
28
|
+
} | {
|
|
29
|
+
id: number;
|
|
30
|
+
ok: false;
|
|
31
|
+
code: string;
|
|
32
|
+
message: string;
|
|
33
|
+
};
|
|
34
|
+
/** The subset of a worker-thread global this module needs, in either runtime. */
|
|
35
|
+
interface WorkerScope {
|
|
36
|
+
postMessage(data: unknown): void;
|
|
37
|
+
onMessage(handler: (data: unknown) => void): void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Run the KDF worker's message loop. A worker entry module is this call and
|
|
41
|
+
* nothing else (see `kdfWorkerEntry.ts`).
|
|
42
|
+
*
|
|
43
|
+
* `register` is injectable so the spec can drive the loop with a cheap fake
|
|
44
|
+
* binding — registering the real native argon2 in a test that only checks
|
|
45
|
+
* message plumbing would pay 250 ms per case to prove nothing about the
|
|
46
|
+
* plumbing. The DEFAULT is the real binding, because a worker that silently ran
|
|
47
|
+
* a fake KDF would be a catastrophe rather than a bug.
|
|
48
|
+
*/
|
|
49
|
+
export declare function serveKdfWorker(options?: {
|
|
50
|
+
scope?: WorkerScope;
|
|
51
|
+
register?: () => Promise<void>;
|
|
52
|
+
}): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* The subset of both runtimes' Worker the client needs.
|
|
55
|
+
*
|
|
56
|
+
* `post` RESOLVES ONCE THE DATA HAS BEEN HANDED TO THE THREAD, and that is not a
|
|
57
|
+
* stylistic choice. A worker is constructed asynchronously, so early requests
|
|
58
|
+
* are queued; the queue holds the caller's `Uint8Array` by reference. A client
|
|
59
|
+
* that zeroized the password right after a fire-and-forget `post()` would blank
|
|
60
|
+
* the buffer the queue is still holding, and the worker would then derive a key
|
|
61
|
+
* from 32 zero bytes — accepting every wrong password that happened to be
|
|
62
|
+
* presented during startup. Awaiting the post is what makes "zeroize as early as
|
|
63
|
+
* possible" and "send the real bytes" compatible.
|
|
64
|
+
*/
|
|
65
|
+
interface HostWorker {
|
|
66
|
+
post(data: unknown): Promise<void>;
|
|
67
|
+
onMessage(handler: (data: unknown) => void): void;
|
|
68
|
+
onError(handler: (error: unknown) => void): void;
|
|
69
|
+
terminate(): void;
|
|
70
|
+
}
|
|
71
|
+
export interface KdfWorkerOptions {
|
|
72
|
+
/** Module specifier / URL of an entry that calls {@link serveKdfWorker}. */
|
|
73
|
+
entry: string | URL;
|
|
74
|
+
/** Per-request ceiling. Defaults to {@link KDF_WORKER_DEFAULT_TIMEOUT_MS}. */
|
|
75
|
+
timeoutMs?: number;
|
|
76
|
+
/** Spawn override — the spec uses it to drive the protocol without a real thread. */
|
|
77
|
+
spawn?: (entry: string | URL) => HostWorker;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* A {@link PasswordVerifierPort} backed by one long-lived worker thread.
|
|
81
|
+
*
|
|
82
|
+
* Hand it to `createAccountService({ passwords })` on a host that expects login
|
|
83
|
+
* concurrency. Local single-user hosts should NOT — they would pay a thread and
|
|
84
|
+
* a native module load to serialize a workload that was never contended.
|
|
85
|
+
*/
|
|
86
|
+
export declare function createKdfWorkerPasswordVerifier(options: KdfWorkerOptions): PasswordVerifierPort;
|
|
87
|
+
/**
|
|
88
|
+
* The URL of the entry module {@link createKdfWorkerPasswordVerifier} spawns.
|
|
89
|
+
*
|
|
90
|
+
* Resolved relative to THIS module rather than hard-coded by the host, so an app
|
|
91
|
+
* never has to know where inside the package the entry lives:
|
|
92
|
+
*
|
|
93
|
+
* createKdfWorkerPasswordVerifier({ entry: kdfWorkerEntryUrl() })
|
|
94
|
+
*
|
|
95
|
+
* Under the `bun` export condition this resolves to the TypeScript source, which
|
|
96
|
+
* is what every first-party consumer runs (see the monorepo's zero-build-lag
|
|
97
|
+
* contract). A non-Bun host consuming built `dist/` names its own built entry.
|
|
98
|
+
*/
|
|
99
|
+
export declare const kdfWorkerEntryUrl: () => URL;
|
|
100
|
+
/** Re-exported so a host wiring the guard tier needs one import. */
|
|
101
|
+
export { createInProcessPasswordVerifier, type PasswordVerifierPort };
|