happy2 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -0
- package/package.json +74 -0
- package/packages/happy2-server/Dockerfile +18 -0
- package/packages/happy2-server/README.md +418 -0
- package/packages/happy2-server/bin/happy2.js +3 -0
- package/packages/happy2-server/dist/cli.d.ts +3 -0
- package/packages/happy2-server/dist/cli.d.ts.map +1 -0
- package/packages/happy2-server/dist/cli.js +44 -0
- package/packages/happy2-server/dist/cli.js.map +1 -0
- package/packages/happy2-server/dist/index.d.ts +24 -0
- package/packages/happy2-server/dist/index.d.ts.map +1 -0
- package/packages/happy2-server/dist/index.js +22 -0
- package/packages/happy2-server/dist/index.js.map +1 -0
- package/packages/happy2-server/dist/modules/agents/builtin-images.d.ts +8 -0
- package/packages/happy2-server/dist/modules/agents/builtin-images.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agents/builtin-images.js +283 -0
- package/packages/happy2-server/dist/modules/agents/builtin-images.js.map +1 -0
- package/packages/happy2-server/dist/modules/agents/command.d.ts +3 -0
- package/packages/happy2-server/dist/modules/agents/command.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agents/command.js +7 -0
- package/packages/happy2-server/dist/modules/agents/command.js.map +1 -0
- package/packages/happy2-server/dist/modules/agents/daemon.d.ts +106 -0
- package/packages/happy2-server/dist/modules/agents/daemon.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agents/daemon.js +522 -0
- package/packages/happy2-server/dist/modules/agents/daemon.js.map +1 -0
- package/packages/happy2-server/dist/modules/agents/docker.d.ts +51 -0
- package/packages/happy2-server/dist/modules/agents/docker.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agents/docker.js +256 -0
- package/packages/happy2-server/dist/modules/agents/docker.js.map +1 -0
- package/packages/happy2-server/dist/modules/agents/docker.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/agents/docker.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agents/docker.test.js +155 -0
- package/packages/happy2-server/dist/modules/agents/docker.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/agents/index.d.ts +5 -0
- package/packages/happy2-server/dist/modules/agents/index.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agents/index.js +4 -0
- package/packages/happy2-server/dist/modules/agents/index.js.map +1 -0
- package/packages/happy2-server/dist/modules/agents/service.d.ts +140 -0
- package/packages/happy2-server/dist/modules/agents/service.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agents/service.js +1283 -0
- package/packages/happy2-server/dist/modules/agents/service.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/cloudflare-access.d.ts +15 -0
- package/packages/happy2-server/dist/modules/auth/cloudflare-access.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/cloudflare-access.js +49 -0
- package/packages/happy2-server/dist/modules/auth/cloudflare-access.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/crypto.d.ts +4 -0
- package/packages/happy2-server/dist/modules/auth/crypto.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/crypto.js +31 -0
- package/packages/happy2-server/dist/modules/auth/crypto.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/crypto.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/auth/crypto.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/crypto.test.js +11 -0
- package/packages/happy2-server/dist/modules/auth/crypto.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/email.d.ts +3 -0
- package/packages/happy2-server/dist/modules/auth/email.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/email.js +22 -0
- package/packages/happy2-server/dist/modules/auth/email.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/metadata.d.ts +5 -0
- package/packages/happy2-server/dist/modules/auth/metadata.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/metadata.js +28 -0
- package/packages/happy2-server/dist/modules/auth/metadata.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/metadata.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/auth/metadata.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/metadata.test.js +10 -0
- package/packages/happy2-server/dist/modules/auth/metadata.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/methods.d.ts +10 -0
- package/packages/happy2-server/dist/modules/auth/methods.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/methods.js +21 -0
- package/packages/happy2-server/dist/modules/auth/methods.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/methods.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/auth/methods.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/methods.test.js +16 -0
- package/packages/happy2-server/dist/modules/auth/methods.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/oidc.d.ts +9 -0
- package/packages/happy2-server/dist/modules/auth/oidc.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/oidc.js +68 -0
- package/packages/happy2-server/dist/modules/auth/oidc.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/service.d.ts +44 -0
- package/packages/happy2-server/dist/modules/auth/service.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/service.js +208 -0
- package/packages/happy2-server/dist/modules/auth/service.js.map +1 -0
- package/packages/happy2-server/dist/modules/auth/tokens.d.ts +21 -0
- package/packages/happy2-server/dist/modules/auth/tokens.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/auth/tokens.js +79 -0
- package/packages/happy2-server/dist/modules/auth/tokens.js.map +1 -0
- package/packages/happy2-server/dist/modules/automation/repository.d.ts +127 -0
- package/packages/happy2-server/dist/modules/automation/repository.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/automation/repository.js +821 -0
- package/packages/happy2-server/dist/modules/automation/repository.js.map +1 -0
- package/packages/happy2-server/dist/modules/collaboration/repository.d.ts +839 -0
- package/packages/happy2-server/dist/modules/collaboration/repository.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/collaboration/repository.js +5795 -0
- package/packages/happy2-server/dist/modules/collaboration/repository.js.map +1 -0
- package/packages/happy2-server/dist/modules/collaboration/repository.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/collaboration/repository.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/collaboration/repository.test.js +620 -0
- package/packages/happy2-server/dist/modules/collaboration/repository.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/collaboration/types.d.ts +243 -0
- package/packages/happy2-server/dist/modules/collaboration/types.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/collaboration/types.js +8 -0
- package/packages/happy2-server/dist/modules/collaboration/types.js.map +1 -0
- package/packages/happy2-server/dist/modules/config/defaults.d.ts +8 -0
- package/packages/happy2-server/dist/modules/config/defaults.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/config/defaults.js +70 -0
- package/packages/happy2-server/dist/modules/config/defaults.js.map +1 -0
- package/packages/happy2-server/dist/modules/config/defaults.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/config/defaults.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/config/defaults.test.js +27 -0
- package/packages/happy2-server/dist/modules/config/defaults.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/config/environment.d.ts +4 -0
- package/packages/happy2-server/dist/modules/config/environment.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/config/environment.js +92 -0
- package/packages/happy2-server/dist/modules/config/environment.js.map +1 -0
- package/packages/happy2-server/dist/modules/config/loader.d.ts +5 -0
- package/packages/happy2-server/dist/modules/config/loader.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/config/loader.js +251 -0
- package/packages/happy2-server/dist/modules/config/loader.js.map +1 -0
- package/packages/happy2-server/dist/modules/config/loader.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/config/loader.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/config/loader.test.js +108 -0
- package/packages/happy2-server/dist/modules/config/loader.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/config/paths.d.ts +7 -0
- package/packages/happy2-server/dist/modules/config/paths.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/config/paths.js +15 -0
- package/packages/happy2-server/dist/modules/config/paths.js.map +1 -0
- package/packages/happy2-server/dist/modules/config/paths.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/config/paths.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/config/paths.test.js +22 -0
- package/packages/happy2-server/dist/modules/config/paths.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/config/runtime.d.ts +6 -0
- package/packages/happy2-server/dist/modules/config/runtime.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/config/runtime.js +14 -0
- package/packages/happy2-server/dist/modules/config/runtime.js.map +1 -0
- package/packages/happy2-server/dist/modules/config/type.d.ts +88 -0
- package/packages/happy2-server/dist/modules/config/type.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/config/type.js +2 -0
- package/packages/happy2-server/dist/modules/config/type.js.map +1 -0
- package/packages/happy2-server/dist/modules/database.d.ts +105 -0
- package/packages/happy2-server/dist/modules/database.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/database.js +583 -0
- package/packages/happy2-server/dist/modules/database.js.map +1 -0
- package/packages/happy2-server/dist/modules/drizzle.d.ts +11 -0
- package/packages/happy2-server/dist/modules/drizzle.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/drizzle.js +31 -0
- package/packages/happy2-server/dist/modules/drizzle.js.map +1 -0
- package/packages/happy2-server/dist/modules/files/lock.d.ts +3 -0
- package/packages/happy2-server/dist/modules/files/lock.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/files/lock.js +83 -0
- package/packages/happy2-server/dist/modules/files/lock.js.map +1 -0
- package/packages/happy2-server/dist/modules/files/media.d.ts +18 -0
- package/packages/happy2-server/dist/modules/files/media.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/files/media.js +352 -0
- package/packages/happy2-server/dist/modules/files/media.js.map +1 -0
- package/packages/happy2-server/dist/modules/files/provider.d.ts +130 -0
- package/packages/happy2-server/dist/modules/files/provider.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/files/provider.js +448 -0
- package/packages/happy2-server/dist/modules/files/provider.js.map +1 -0
- package/packages/happy2-server/dist/modules/files/quota.d.ts +58 -0
- package/packages/happy2-server/dist/modules/files/quota.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/files/quota.js +180 -0
- package/packages/happy2-server/dist/modules/files/quota.js.map +1 -0
- package/packages/happy2-server/dist/modules/files/routes.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/files/routes.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/files/routes.test.js +163 -0
- package/packages/happy2-server/dist/modules/files/routes.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/files/scanner.d.ts +27 -0
- package/packages/happy2-server/dist/modules/files/scanner.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/files/scanner.js +66 -0
- package/packages/happy2-server/dist/modules/files/scanner.js.map +1 -0
- package/packages/happy2-server/dist/modules/files/storage.d.ts +95 -0
- package/packages/happy2-server/dist/modules/files/storage.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/files/storage.js +855 -0
- package/packages/happy2-server/dist/modules/files/storage.js.map +1 -0
- package/packages/happy2-server/dist/modules/files/storage.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/files/storage.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/files/storage.test.js +170 -0
- package/packages/happy2-server/dist/modules/files/storage.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/index.d.ts +6 -0
- package/packages/happy2-server/dist/modules/integrations/index.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/index.js +6 -0
- package/packages/happy2-server/dist/modules/integrations/index.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/repository.d.ts +136 -0
- package/packages/happy2-server/dist/modules/integrations/repository.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/repository.js +1229 -0
- package/packages/happy2-server/dist/modules/integrations/repository.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/repository.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/integrations/repository.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/repository.test.js +345 -0
- package/packages/happy2-server/dist/modules/integrations/repository.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/routes.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/integrations/routes.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/routes.test.js +161 -0
- package/packages/happy2-server/dist/modules/integrations/routes.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/secrets.d.ts +19 -0
- package/packages/happy2-server/dist/modules/integrations/secrets.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/secrets.js +69 -0
- package/packages/happy2-server/dist/modules/integrations/secrets.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/ssrf.d.ts +32 -0
- package/packages/happy2-server/dist/modules/integrations/ssrf.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/ssrf.js +185 -0
- package/packages/happy2-server/dist/modules/integrations/ssrf.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/ssrf.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/integrations/ssrf.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/ssrf.test.js +56 -0
- package/packages/happy2-server/dist/modules/integrations/ssrf.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/transport.d.ts +21 -0
- package/packages/happy2-server/dist/modules/integrations/transport.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/transport.js +108 -0
- package/packages/happy2-server/dist/modules/integrations/transport.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/transport.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/integrations/transport.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/transport.test.js +66 -0
- package/packages/happy2-server/dist/modules/integrations/transport.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/types.d.ts +155 -0
- package/packages/happy2-server/dist/modules/integrations/types.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/integrations/types.js +26 -0
- package/packages/happy2-server/dist/modules/integrations/types.js.map +1 -0
- package/packages/happy2-server/dist/modules/operations/export-worker.d.ts +16 -0
- package/packages/happy2-server/dist/modules/operations/export-worker.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/operations/export-worker.js +56 -0
- package/packages/happy2-server/dist/modules/operations/export-worker.js.map +1 -0
- package/packages/happy2-server/dist/modules/operations/repository.d.ts +215 -0
- package/packages/happy2-server/dist/modules/operations/repository.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/operations/repository.js +2011 -0
- package/packages/happy2-server/dist/modules/operations/repository.js.map +1 -0
- package/packages/happy2-server/dist/modules/operations/repository.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/operations/repository.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/operations/repository.test.js +610 -0
- package/packages/happy2-server/dist/modules/operations/repository.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/operations/types.d.ts +144 -0
- package/packages/happy2-server/dist/modules/operations/types.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/operations/types.js +9 -0
- package/packages/happy2-server/dist/modules/operations/types.js.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/events.d.ts +99 -0
- package/packages/happy2-server/dist/modules/realtime/events.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/events.js +173 -0
- package/packages/happy2-server/dist/modules/realtime/events.js.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/index.d.ts +4 -0
- package/packages/happy2-server/dist/modules/realtime/index.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/index.js +4 -0
- package/packages/happy2-server/dist/modules/realtime/index.js.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/local.d.ts +37 -0
- package/packages/happy2-server/dist/modules/realtime/local.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/local.js +181 -0
- package/packages/happy2-server/dist/modules/realtime/local.js.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/local.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/realtime/local.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/local.test.js +186 -0
- package/packages/happy2-server/dist/modules/realtime/local.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/pubsub.d.ts +26 -0
- package/packages/happy2-server/dist/modules/realtime/pubsub.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/realtime/pubsub.js +7 -0
- package/packages/happy2-server/dist/modules/realtime/pubsub.js.map +1 -0
- package/packages/happy2-server/dist/modules/request/database-idempotency.d.ts +15 -0
- package/packages/happy2-server/dist/modules/request/database-idempotency.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/request/database-idempotency.js +141 -0
- package/packages/happy2-server/dist/modules/request/database-idempotency.js.map +1 -0
- package/packages/happy2-server/dist/modules/request/idempotency-hook.d.ts +12 -0
- package/packages/happy2-server/dist/modules/request/idempotency-hook.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/request/idempotency-hook.js +98 -0
- package/packages/happy2-server/dist/modules/request/idempotency-hook.js.map +1 -0
- package/packages/happy2-server/dist/modules/request/idempotency.d.ts +146 -0
- package/packages/happy2-server/dist/modules/request/idempotency.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/request/idempotency.js +312 -0
- package/packages/happy2-server/dist/modules/request/idempotency.js.map +1 -0
- package/packages/happy2-server/dist/modules/request/idempotency.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/request/idempotency.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/request/idempotency.test.js +191 -0
- package/packages/happy2-server/dist/modules/request/idempotency.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/request/index.d.ts +5 -0
- package/packages/happy2-server/dist/modules/request/index.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/request/index.js +5 -0
- package/packages/happy2-server/dist/modules/request/index.js.map +1 -0
- package/packages/happy2-server/dist/modules/request/rate-limit.d.ts +100 -0
- package/packages/happy2-server/dist/modules/request/rate-limit.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/request/rate-limit.js +239 -0
- package/packages/happy2-server/dist/modules/request/rate-limit.js.map +1 -0
- package/packages/happy2-server/dist/modules/request/rate-limit.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/request/rate-limit.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/request/rate-limit.test.js +123 -0
- package/packages/happy2-server/dist/modules/request/rate-limit.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/schema.d.ts +31454 -0
- package/packages/happy2-server/dist/modules/schema.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/schema.js +1081 -0
- package/packages/happy2-server/dist/modules/schema.js.map +1 -0
- package/packages/happy2-server/dist/modules/workspace/index.d.ts +3 -0
- package/packages/happy2-server/dist/modules/workspace/index.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/workspace/index.js +3 -0
- package/packages/happy2-server/dist/modules/workspace/index.js.map +1 -0
- package/packages/happy2-server/dist/modules/workspace/service.d.ts +54 -0
- package/packages/happy2-server/dist/modules/workspace/service.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/workspace/service.js +997 -0
- package/packages/happy2-server/dist/modules/workspace/service.js.map +1 -0
- package/packages/happy2-server/dist/modules/workspace/types.d.ts +58 -0
- package/packages/happy2-server/dist/modules/workspace/types.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/workspace/types.js +11 -0
- package/packages/happy2-server/dist/modules/workspace/types.js.map +1 -0
- package/packages/happy2-server/dist/routes/agents.d.ts +5 -0
- package/packages/happy2-server/dist/routes/agents.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/agents.js +225 -0
- package/packages/happy2-server/dist/routes/agents.js.map +1 -0
- package/packages/happy2-server/dist/routes/auth.d.ts +5 -0
- package/packages/happy2-server/dist/routes/auth.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/auth.js +128 -0
- package/packages/happy2-server/dist/routes/auth.js.map +1 -0
- package/packages/happy2-server/dist/routes/automation.d.ts +6 -0
- package/packages/happy2-server/dist/routes/automation.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/automation.js +315 -0
- package/packages/happy2-server/dist/routes/automation.js.map +1 -0
- package/packages/happy2-server/dist/routes/basic.d.ts +3 -0
- package/packages/happy2-server/dist/routes/basic.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/basic.js +5 -0
- package/packages/happy2-server/dist/routes/basic.js.map +1 -0
- package/packages/happy2-server/dist/routes/collaboration.d.ts +7 -0
- package/packages/happy2-server/dist/routes/collaboration.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/collaboration.js +1285 -0
- package/packages/happy2-server/dist/routes/collaboration.js.map +1 -0
- package/packages/happy2-server/dist/routes/files.d.ts +9 -0
- package/packages/happy2-server/dist/routes/files.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/files.js +397 -0
- package/packages/happy2-server/dist/routes/files.js.map +1 -0
- package/packages/happy2-server/dist/routes/integrations.d.ts +6 -0
- package/packages/happy2-server/dist/routes/integrations.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/integrations.js +486 -0
- package/packages/happy2-server/dist/routes/integrations.js.map +1 -0
- package/packages/happy2-server/dist/routes/operations.d.ts +5 -0
- package/packages/happy2-server/dist/routes/operations.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/operations.js +588 -0
- package/packages/happy2-server/dist/routes/operations.js.map +1 -0
- package/packages/happy2-server/dist/routes/operations.test.d.ts +2 -0
- package/packages/happy2-server/dist/routes/operations.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/operations.test.js +106 -0
- package/packages/happy2-server/dist/routes/operations.test.js.map +1 -0
- package/packages/happy2-server/dist/routes/sync.d.ts +6 -0
- package/packages/happy2-server/dist/routes/sync.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/sync.js +549 -0
- package/packages/happy2-server/dist/routes/sync.js.map +1 -0
- package/packages/happy2-server/dist/routes/workspace.d.ts +5 -0
- package/packages/happy2-server/dist/routes/workspace.d.ts.map +1 -0
- package/packages/happy2-server/dist/routes/workspace.js +240 -0
- package/packages/happy2-server/dist/routes/workspace.js.map +1 -0
- package/packages/happy2-server/dist/runner.d.ts +3 -0
- package/packages/happy2-server/dist/runner.d.ts.map +1 -0
- package/packages/happy2-server/dist/runner.js +30 -0
- package/packages/happy2-server/dist/runner.js.map +1 -0
- package/packages/happy2-server/dist/server.d.ts +32 -0
- package/packages/happy2-server/dist/server.d.ts.map +1 -0
- package/packages/happy2-server/dist/server.js +284 -0
- package/packages/happy2-server/dist/server.js.map +1 -0
- package/packages/happy2-server/dist/standalone.d.ts +13 -0
- package/packages/happy2-server/dist/standalone.d.ts.map +1 -0
- package/packages/happy2-server/dist/standalone.js +99 -0
- package/packages/happy2-server/dist/standalone.js.map +1 -0
- package/packages/happy2-server/dist/web/assets/figtree-latin-wght-normal-D_ZTVpCC.woff2 +0 -0
- package/packages/happy2-server/dist/web/assets/happy-otter-Q2O_g-DT.png +0 -0
- package/packages/happy2-server/dist/web/assets/index-COvbX8JP.css +2 -0
- package/packages/happy2-server/dist/web/assets/index-DdpugxMO.js +57 -0
- package/packages/happy2-server/dist/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/packages/happy2-server/dist/web/assets/onboarding-CRUpq9xl.png +0 -0
- package/packages/happy2-server/dist/web/index.html +13 -0
- package/packages/happy2-server/drizzle/0000_initial.sql +13 -0
- package/packages/happy2-server/drizzle/0001_accounts_profiles_files.sql +42 -0
- package/packages/happy2-server/drizzle/0002_file_visibility_and_uploader.sql +5 -0
- package/packages/happy2-server/drizzle/0003_collaboration.sql +565 -0
- package/packages/happy2-server/drizzle/0004_collaboration_expansion.sql +1099 -0
- package/packages/happy2-server/drizzle/0005_ai_agents.sql +85 -0
- package/packages/happy2-server/drizzle/0006_rig_global_event_queue.sql +10 -0
- package/packages/happy2-server/drizzle/0007_rename_server_identity.sql +3 -0
- package/packages/happy2-server/drizzle/0008_agent_message_streaming.sql +47 -0
- package/packages/happy2-server/drizzle/0009_chat_workspace_binding_lookup.sql +2 -0
- package/packages/happy2-server/drizzle/0010_rig_secret_assignments.sql +21 -0
- package/packages/happy2-server/drizzle/meta/_journal.json +83 -0
- package/packages/happy2-server/happy2.example.toml +104 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { assertRealtimeEvent, assertRealtimeId, assertRealtimeTopic, DEFAULT_REALTIME_LIMITS, realtimeTopics, } from "./events.js";
|
|
2
|
+
import { PubSubClosedError, } from "./pubsub.js";
|
|
3
|
+
/** In-memory, process-local pubsub. All state disappears on close or restart. */
|
|
4
|
+
export class LocalPubSub {
|
|
5
|
+
clock;
|
|
6
|
+
limits;
|
|
7
|
+
onSubscriberError;
|
|
8
|
+
subscribers = new Map();
|
|
9
|
+
connections = new Map();
|
|
10
|
+
connectionsByUser = new Map();
|
|
11
|
+
lastActivityByUser = new Map();
|
|
12
|
+
closed = false;
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.clock = options.clock ?? Date.now;
|
|
15
|
+
this.limits = { ...DEFAULT_REALTIME_LIMITS, ...options.limits };
|
|
16
|
+
this.onSubscriberError = options.onSubscriberError;
|
|
17
|
+
assertLimits(this.limits);
|
|
18
|
+
}
|
|
19
|
+
async publish(topic, event) {
|
|
20
|
+
this.assertOpen();
|
|
21
|
+
assertRealtimeTopic(topic, this.limits);
|
|
22
|
+
assertRealtimeEvent(event, this.limits);
|
|
23
|
+
const safeEvent = deepFreeze(structuredClone(event));
|
|
24
|
+
const subscribers = [...(this.subscribers.get(topic) ?? [])];
|
|
25
|
+
await Promise.all(subscribers.map(async (subscriber) => {
|
|
26
|
+
try {
|
|
27
|
+
await subscriber(safeEvent);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
this.reportSubscriberError(error, { topic, event: safeEvent });
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
subscribe(topic, subscriber) {
|
|
35
|
+
this.assertOpen();
|
|
36
|
+
assertRealtimeTopic(topic, this.limits);
|
|
37
|
+
if (typeof subscriber !== "function")
|
|
38
|
+
throw new Error("Subscriber must be a function");
|
|
39
|
+
const subscribers = this.subscribers.get(topic) ?? new Set();
|
|
40
|
+
subscribers.add(subscriber);
|
|
41
|
+
this.subscribers.set(topic, subscribers);
|
|
42
|
+
let subscribed = true;
|
|
43
|
+
return () => {
|
|
44
|
+
if (!subscribed)
|
|
45
|
+
return;
|
|
46
|
+
subscribed = false;
|
|
47
|
+
subscribers.delete(subscriber);
|
|
48
|
+
if (subscribers.size === 0)
|
|
49
|
+
this.subscribers.delete(topic);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async connectPresence(connection) {
|
|
53
|
+
this.assertOpen();
|
|
54
|
+
assertRealtimeId(connection.connectionId, "connection id", this.limits);
|
|
55
|
+
assertRealtimeId(connection.userId, "user id", this.limits);
|
|
56
|
+
const occurredAt = this.occurredAt(connection.occurredAt);
|
|
57
|
+
const existing = this.connections.get(connection.connectionId);
|
|
58
|
+
if (existing) {
|
|
59
|
+
if (existing.userId !== connection.userId)
|
|
60
|
+
throw new Error("Presence connection id is already in use");
|
|
61
|
+
if (occurredAt > existing.lastActiveAt) {
|
|
62
|
+
existing.lastActiveAt = occurredAt;
|
|
63
|
+
this.rememberActivity(existing.userId, occurredAt);
|
|
64
|
+
}
|
|
65
|
+
return this.snapshot(existing.userId);
|
|
66
|
+
}
|
|
67
|
+
const local = {
|
|
68
|
+
connectionId: connection.connectionId,
|
|
69
|
+
userId: connection.userId,
|
|
70
|
+
lastActiveAt: occurredAt,
|
|
71
|
+
};
|
|
72
|
+
this.connections.set(local.connectionId, local);
|
|
73
|
+
const userConnections = this.connectionsByUser.get(local.userId) ?? new Set();
|
|
74
|
+
userConnections.add(local.connectionId);
|
|
75
|
+
this.connectionsByUser.set(local.userId, userConnections);
|
|
76
|
+
this.rememberActivity(local.userId, occurredAt);
|
|
77
|
+
return this.emitPresence("connected", local.userId, occurredAt);
|
|
78
|
+
}
|
|
79
|
+
async recordPresenceActivity(connectionId, occurredAt) {
|
|
80
|
+
this.assertOpen();
|
|
81
|
+
assertRealtimeId(connectionId, "connection id", this.limits);
|
|
82
|
+
const connection = this.connections.get(connectionId);
|
|
83
|
+
if (!connection)
|
|
84
|
+
return undefined;
|
|
85
|
+
const time = this.occurredAt(occurredAt);
|
|
86
|
+
connection.lastActiveAt = Math.max(connection.lastActiveAt, time);
|
|
87
|
+
this.rememberActivity(connection.userId, connection.lastActiveAt);
|
|
88
|
+
return this.emitPresence("activity", connection.userId, time);
|
|
89
|
+
}
|
|
90
|
+
async disconnectPresence(connectionId, occurredAt) {
|
|
91
|
+
this.assertOpen();
|
|
92
|
+
assertRealtimeId(connectionId, "connection id", this.limits);
|
|
93
|
+
const connection = this.connections.get(connectionId);
|
|
94
|
+
if (!connection)
|
|
95
|
+
return undefined;
|
|
96
|
+
const time = this.occurredAt(occurredAt);
|
|
97
|
+
this.connections.delete(connectionId);
|
|
98
|
+
const userConnections = this.connectionsByUser.get(connection.userId);
|
|
99
|
+
userConnections?.delete(connectionId);
|
|
100
|
+
if (userConnections?.size === 0)
|
|
101
|
+
this.connectionsByUser.delete(connection.userId);
|
|
102
|
+
this.rememberActivity(connection.userId, Math.max(connection.lastActiveAt, time));
|
|
103
|
+
return this.emitPresence("disconnected", connection.userId, time);
|
|
104
|
+
}
|
|
105
|
+
async getPresenceSnapshot(userIds) {
|
|
106
|
+
this.assertOpen();
|
|
107
|
+
const ids = userIds
|
|
108
|
+
? [...userIds]
|
|
109
|
+
: [...new Set([...this.connectionsByUser.keys(), ...this.lastActivityByUser.keys()])];
|
|
110
|
+
for (const userId of ids)
|
|
111
|
+
assertRealtimeId(userId, "user id", this.limits);
|
|
112
|
+
return ids.map((userId) => this.snapshot(userId));
|
|
113
|
+
}
|
|
114
|
+
async close() {
|
|
115
|
+
if (this.closed)
|
|
116
|
+
return;
|
|
117
|
+
this.closed = true;
|
|
118
|
+
this.subscribers.clear();
|
|
119
|
+
this.connections.clear();
|
|
120
|
+
this.connectionsByUser.clear();
|
|
121
|
+
this.lastActivityByUser.clear();
|
|
122
|
+
}
|
|
123
|
+
async emitPresence(change, userId, occurredAt) {
|
|
124
|
+
const snapshot = this.snapshot(userId);
|
|
125
|
+
const event = { type: "presence", change, snapshot, occurredAt };
|
|
126
|
+
await this.publish(realtimeTopics.presence, event);
|
|
127
|
+
return snapshot;
|
|
128
|
+
}
|
|
129
|
+
snapshot(userId) {
|
|
130
|
+
const connectionCount = this.connectionsByUser.get(userId)?.size ?? 0;
|
|
131
|
+
return Object.freeze({
|
|
132
|
+
userId,
|
|
133
|
+
status: connectionCount > 0 ? "online" : "offline",
|
|
134
|
+
connectionCount,
|
|
135
|
+
lastActiveAt: this.lastActivityByUser.get(userId),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
rememberActivity(userId, occurredAt) {
|
|
139
|
+
this.lastActivityByUser.set(userId, Math.max(this.lastActivityByUser.get(userId) ?? 0, occurredAt));
|
|
140
|
+
while (this.lastActivityByUser.size > this.limits.maxPresenceUsers) {
|
|
141
|
+
const removable = [...this.lastActivityByUser.keys()].find((candidate) => !this.connectionsByUser.has(candidate));
|
|
142
|
+
if (!removable)
|
|
143
|
+
break;
|
|
144
|
+
this.lastActivityByUser.delete(removable);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
occurredAt(value) {
|
|
148
|
+
const result = value ?? this.clock();
|
|
149
|
+
if (!Number.isSafeInteger(result) || result < 0)
|
|
150
|
+
throw new Error("Invalid presence time");
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
assertOpen() {
|
|
154
|
+
if (this.closed)
|
|
155
|
+
throw new PubSubClosedError();
|
|
156
|
+
}
|
|
157
|
+
reportSubscriberError(error, context) {
|
|
158
|
+
try {
|
|
159
|
+
const reported = this.onSubscriberError?.(error, context);
|
|
160
|
+
if (reported)
|
|
161
|
+
void reported.catch(() => undefined);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Subscriber error reporting must never break fanout.
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function deepFreeze(value) {
|
|
169
|
+
if (!value || typeof value !== "object" || Object.isFrozen(value))
|
|
170
|
+
return value;
|
|
171
|
+
for (const child of Object.values(value))
|
|
172
|
+
deepFreeze(child);
|
|
173
|
+
return Object.freeze(value);
|
|
174
|
+
}
|
|
175
|
+
function assertLimits(limits) {
|
|
176
|
+
for (const [name, value] of Object.entries(limits)) {
|
|
177
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
178
|
+
throw new Error(`Realtime limit ${name} must be a positive safe integer`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../../sources/modules/realtime/local.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,GAOjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACH,iBAAiB,GAKpB,MAAM,aAAa,CAAC;AAsBrB,iFAAiF;AACjF,MAAM,OAAO,WAAW;IACH,KAAK,CAAe;IACpB,MAAM,CAAiB;IACvB,iBAAiB,CAA2C;IAC5D,WAAW,GAAG,IAAI,GAAG,EAA0C,CAAC;IAChE,WAAW,GAAG,IAAI,GAAG,EAA2B,CAAC;IACjD,iBAAiB,GAAG,IAAI,GAAG,EAAuB,CAAC;IACnD,kBAAkB,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxD,MAAM,GAAG,KAAK,CAAC;IAEvB,YAAY,OAAO,GAAuB,EAAE;QACxC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,uBAAuB,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAChE,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACnD,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAoB,EAAE,KAAoB;QACpD,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7D,MAAM,OAAO,CAAC,GAAG,CACb,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;YACjC,IAAI,CAAC;gBACD,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YACnE,CAAC;QACL,CAAC,CAAC,CACL,CAAC;IACN,CAAC;IAED,SAAS,CAAC,KAAoB,EAAE,UAA8B;QAC1D,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,OAAO,UAAU,KAAK,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACvF,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,GAAG,EAAsB,CAAC;QACjF,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QACzC,IAAI,UAAU,GAAG,IAAI,CAAC;QACtB,OAAO,GAAG,EAAE;YACR,IAAI,CAAC,UAAU;gBAAE,OAAO;YACxB,UAAU,GAAG,KAAK,CAAC;YACnB,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC;gBAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/D,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,UAA8B;QAChD,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,gBAAgB,CAAC,UAAU,CAAC,YAAY,EAAE,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACxE,gBAAgB,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAC/D,IAAI,QAAQ,EAAE,CAAC;YACX,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM;gBACrC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;YAChE,IAAI,UAAU,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;gBACrC,QAAQ,CAAC,YAAY,GAAG,UAAU,CAAC;gBACnC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YACvD,CAAC;YACD,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC;QAED,MAAM,KAAK,GAAoB;YAC3B,YAAY,EAAE,UAAU,CAAC,YAAY;YACrC,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,YAAY,EAAE,UAAU;SAC3B,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QAChD,MAAM,eAAe,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;QACtF,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACxC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QAC1D,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,sBAAsB,CACxB,YAAoB,EACpB,UAAmB;QAEnB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,gBAAgB,CAAC,YAAY,EAAE,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACtD,IAAI,CAAC,UAAU;YAAE,OAAO,SAAS,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACzC,UAAU,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAClE,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,kBAAkB,CACpB,YAAoB,EACpB,UAAmB;QAEnB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,gBAAgB,CAAC,YAAY,EAAE,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACtD,IAAI,CAAC,UAAU;YAAE,OAAO,SAAS,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACtC,MAAM,eAAe,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACtE,eAAe,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;QACtC,IAAI,eAAe,EAAE,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAClF,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,OAA2B;QACjD,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,OAAO;YACf,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;YACd,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1F,KAAK,MAAM,MAAM,IAAI,GAAG;YAAE,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3E,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,KAAK;QACP,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;IACpC,CAAC;IAEO,KAAK,CAAC,YAAY,CACtB,MAAsB,EACtB,MAAc,EACd,UAAkB;QAElB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,KAAK,GAAkB,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;QAChF,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACnD,OAAO,QAAQ,CAAC;IACpB,CAAC;IAEO,QAAQ,CAAC,MAAc;QAC3B,MAAM,eAAe,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;QACtE,OAAO,MAAM,CAAC,MAAM,CAAC;YACjB,MAAM;YACN,MAAM,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YAClD,eAAe;YACf,YAAY,EAAE,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC;SACpD,CAAC,CAAC;IACP,CAAC;IAEO,gBAAgB,CAAC,MAAc,EAAE,UAAkB;QACvD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CACvB,MAAM,EACN,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CACjE,CAAC;QACF,OAAO,IAAI,CAAC,kBAAkB,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;YACjE,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CACtD,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CACxD,CAAC;YACF,IAAI,CAAC,SAAS;gBAAE,MAAM;YACtB,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC;IAEO,UAAU,CAAC,KAAyB;QACxC,MAAM,MAAM,GAAG,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC1F,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,UAAU;QACd,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,iBAAiB,EAAE,CAAC;IACnD,CAAC;IAEO,qBAAqB,CAAC,KAAc,EAAE,OAA+B;QACzE,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAC1D,IAAI,QAAQ;gBAAE,KAAK,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACL,sDAAsD;QAC1D,CAAC;IACL,CAAC;CACJ;AAED,SAAS,UAAU,CAAI,KAAQ;IAC3B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAChF,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;QAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,YAAY,CAAC,MAAsB;IACxC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,kBAAkB,IAAI,kCAAkC,CAAC,CAAC;IAClF,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.test.d.ts","sourceRoot":"","sources":["../../../sources/modules/realtime/local.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { LocalPubSub, PubSubClosedError, realtimeTopics, } from "./index.js";
|
|
3
|
+
const syncEvent = {
|
|
4
|
+
type: "sync",
|
|
5
|
+
sequence: "9007199254740993",
|
|
6
|
+
chats: [{ chatId: "chat-one", pts: "9007199254740992" }],
|
|
7
|
+
areas: ["messages"],
|
|
8
|
+
};
|
|
9
|
+
describe("LocalPubSub contract", () => {
|
|
10
|
+
it("fans out by topic, awaits async subscribers, and unsubscribes idempotently", async () => {
|
|
11
|
+
const pubsub = new LocalPubSub();
|
|
12
|
+
const received = [];
|
|
13
|
+
const listener = vi.fn(async (event) => {
|
|
14
|
+
await Promise.resolve();
|
|
15
|
+
received.push(event);
|
|
16
|
+
});
|
|
17
|
+
const unsubscribe = pubsub.subscribe(realtimeTopics.user("user-one"), listener);
|
|
18
|
+
await pubsub.publish(realtimeTopics.chat("chat-one"), syncEvent);
|
|
19
|
+
await pubsub.publish(realtimeTopics.user("user-one"), syncEvent);
|
|
20
|
+
expect(received).toEqual([syncEvent]);
|
|
21
|
+
expect(Object.isFrozen(received[0])).toBe(true);
|
|
22
|
+
expect(Object.isFrozen(received[0].chats)).toBe(true);
|
|
23
|
+
unsubscribe();
|
|
24
|
+
unsubscribe();
|
|
25
|
+
await pubsub.publish(realtimeTopics.user("user-one"), syncEvent);
|
|
26
|
+
expect(listener).toHaveBeenCalledTimes(1);
|
|
27
|
+
});
|
|
28
|
+
it("isolates subscriber failures so every async subscriber receives the event", async () => {
|
|
29
|
+
const errors = [];
|
|
30
|
+
const pubsub = new LocalPubSub({
|
|
31
|
+
onSubscriberError: (error) => {
|
|
32
|
+
errors.push(error);
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
const delivered = vi.fn();
|
|
36
|
+
pubsub.subscribe(realtimeTopics.server, async () => {
|
|
37
|
+
await Promise.resolve();
|
|
38
|
+
throw new Error("listener failed");
|
|
39
|
+
});
|
|
40
|
+
pubsub.subscribe(realtimeTopics.server, delivered);
|
|
41
|
+
await expect(pubsub.publish(realtimeTopics.server, syncEvent)).resolves.toBeUndefined();
|
|
42
|
+
expect(delivered).toHaveBeenCalledWith(syncEvent);
|
|
43
|
+
expect(errors).toHaveLength(1);
|
|
44
|
+
});
|
|
45
|
+
it("consumes asynchronous subscriber-error reporter failures", async () => {
|
|
46
|
+
const pubsub = new LocalPubSub({
|
|
47
|
+
onSubscriberError: async () => {
|
|
48
|
+
throw new Error("reporter failed");
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
pubsub.subscribe(realtimeTopics.server, () => {
|
|
52
|
+
throw new Error("subscriber failed");
|
|
53
|
+
});
|
|
54
|
+
await expect(pubsub.publish(realtimeTopics.server, syncEvent)).resolves.toBeUndefined();
|
|
55
|
+
await Promise.resolve();
|
|
56
|
+
});
|
|
57
|
+
it("bounds retained offline presence history", async () => {
|
|
58
|
+
let now = 1;
|
|
59
|
+
const pubsub = new LocalPubSub({
|
|
60
|
+
clock: () => now++,
|
|
61
|
+
limits: { maxPresenceUsers: 2 },
|
|
62
|
+
});
|
|
63
|
+
for (const userId of ["one", "two", "three"]) {
|
|
64
|
+
const connectionId = `connection-${userId}`;
|
|
65
|
+
await pubsub.connectPresence({ connectionId, userId });
|
|
66
|
+
await pubsub.disconnectPresence(connectionId);
|
|
67
|
+
}
|
|
68
|
+
expect(await pubsub.getPresenceSnapshot()).toHaveLength(2);
|
|
69
|
+
});
|
|
70
|
+
it("accepts lossless SQLite sequences and rejects malformed or oversized hints", async () => {
|
|
71
|
+
const pubsub = new LocalPubSub({ limits: { maxSyncChats: 1 } });
|
|
72
|
+
await expect(pubsub.publish(realtimeTopics.server, syncEvent)).resolves.toBeUndefined();
|
|
73
|
+
await expect(pubsub.publish(realtimeTopics.server, { ...syncEvent, sequence: "01" })).rejects.toThrow("unsigned decimal string");
|
|
74
|
+
await expect(pubsub.publish(realtimeTopics.server, {
|
|
75
|
+
...syncEvent,
|
|
76
|
+
chats: [...syncEvent.chats, { chatId: "chat-two", pts: "1" }],
|
|
77
|
+
})).rejects.toThrow("at most 1 chats");
|
|
78
|
+
await expect(pubsub.publish(realtimeTopics.server, {
|
|
79
|
+
type: "unknown",
|
|
80
|
+
})).rejects.toThrow("Invalid realtime event type");
|
|
81
|
+
});
|
|
82
|
+
it("enforces typing expiry and WebRTC signaling bounds", async () => {
|
|
83
|
+
const pubsub = new LocalPubSub({
|
|
84
|
+
limits: { maxTypingTtlMs: 5_000, maxSessionDescriptionBytes: 16 },
|
|
85
|
+
});
|
|
86
|
+
const typing = {
|
|
87
|
+
type: "typing",
|
|
88
|
+
chatId: "chat-one",
|
|
89
|
+
userId: "user-one",
|
|
90
|
+
active: true,
|
|
91
|
+
occurredAt: 1_000,
|
|
92
|
+
expiresAt: 6_000,
|
|
93
|
+
};
|
|
94
|
+
const offer = {
|
|
95
|
+
type: "call.signal",
|
|
96
|
+
callId: "call-one",
|
|
97
|
+
chatId: "chat-one",
|
|
98
|
+
senderUserId: "user-one",
|
|
99
|
+
recipientUserId: "user-two",
|
|
100
|
+
signal: { kind: "offer", sdp: "v=0" },
|
|
101
|
+
occurredAt: 1_000,
|
|
102
|
+
};
|
|
103
|
+
await expect(pubsub.publish(realtimeTopics.chat("chat-one"), typing)).resolves.toBeUndefined();
|
|
104
|
+
await expect(pubsub.publish(realtimeTopics.call("call-one"), offer)).resolves.toBeUndefined();
|
|
105
|
+
await expect(pubsub.publish(realtimeTopics.chat("chat-one"), {
|
|
106
|
+
...typing,
|
|
107
|
+
expiresAt: 6_001,
|
|
108
|
+
})).rejects.toThrow("within 5000 ms");
|
|
109
|
+
await expect(pubsub.publish(realtimeTopics.call("call-one"), {
|
|
110
|
+
...offer,
|
|
111
|
+
signal: { kind: "offer", sdp: "x".repeat(17) },
|
|
112
|
+
})).rejects.toThrow("session description");
|
|
113
|
+
});
|
|
114
|
+
it("tracks multiple presence connections, activity, and offline snapshots", async () => {
|
|
115
|
+
let now = 100;
|
|
116
|
+
const pubsub = new LocalPubSub({ clock: () => now });
|
|
117
|
+
const events = [];
|
|
118
|
+
pubsub.subscribe(realtimeTopics.presence, (event) => {
|
|
119
|
+
if (event.type === "presence")
|
|
120
|
+
events.push(event);
|
|
121
|
+
});
|
|
122
|
+
await expect(pubsub.connectPresence({ connectionId: "connection-one", userId: "user-one" })).resolves.toEqual({
|
|
123
|
+
userId: "user-one",
|
|
124
|
+
status: "online",
|
|
125
|
+
connectionCount: 1,
|
|
126
|
+
lastActiveAt: 100,
|
|
127
|
+
});
|
|
128
|
+
now = 110;
|
|
129
|
+
await pubsub.connectPresence({ connectionId: "connection-two", userId: "user-one" });
|
|
130
|
+
now = 120;
|
|
131
|
+
await pubsub.recordPresenceActivity("connection-one");
|
|
132
|
+
now = 130;
|
|
133
|
+
await pubsub.disconnectPresence("connection-one");
|
|
134
|
+
expect(await pubsub.getPresenceSnapshot(["user-one", "never-online"])).toEqual([
|
|
135
|
+
{
|
|
136
|
+
userId: "user-one",
|
|
137
|
+
status: "online",
|
|
138
|
+
connectionCount: 1,
|
|
139
|
+
lastActiveAt: 130,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
userId: "never-online",
|
|
143
|
+
status: "offline",
|
|
144
|
+
connectionCount: 0,
|
|
145
|
+
lastActiveAt: undefined,
|
|
146
|
+
},
|
|
147
|
+
]);
|
|
148
|
+
now = 140;
|
|
149
|
+
await pubsub.disconnectPresence("connection-two");
|
|
150
|
+
expect(await pubsub.getPresenceSnapshot(["user-one"])).toEqual([
|
|
151
|
+
{
|
|
152
|
+
userId: "user-one",
|
|
153
|
+
status: "offline",
|
|
154
|
+
connectionCount: 0,
|
|
155
|
+
lastActiveAt: 140,
|
|
156
|
+
},
|
|
157
|
+
]);
|
|
158
|
+
expect(events.map((event) => event.change)).toEqual([
|
|
159
|
+
"connected",
|
|
160
|
+
"connected",
|
|
161
|
+
"activity",
|
|
162
|
+
"disconnected",
|
|
163
|
+
"disconnected",
|
|
164
|
+
]);
|
|
165
|
+
});
|
|
166
|
+
it("makes repeated presence connection safe but rejects cross-user reuse", async () => {
|
|
167
|
+
const pubsub = new LocalPubSub({ clock: () => 100 });
|
|
168
|
+
await pubsub.connectPresence({ connectionId: "same", userId: "user-one" });
|
|
169
|
+
await expect(pubsub.connectPresence({ connectionId: "same", userId: "user-one" })).resolves.toMatchObject({ connectionCount: 1 });
|
|
170
|
+
await expect(pubsub.connectPresence({ connectionId: "same", userId: "user-two" })).rejects.toThrow("already in use");
|
|
171
|
+
await expect(pubsub.recordPresenceActivity("unknown")).resolves.toBeUndefined();
|
|
172
|
+
await expect(pubsub.disconnectPresence("unknown")).resolves.toBeUndefined();
|
|
173
|
+
});
|
|
174
|
+
it("clears subscriptions and ephemeral presence state when closed", async () => {
|
|
175
|
+
const pubsub = new LocalPubSub();
|
|
176
|
+
const listener = vi.fn();
|
|
177
|
+
pubsub.subscribe(realtimeTopics.server, listener);
|
|
178
|
+
await pubsub.connectPresence({ connectionId: "connection-one", userId: "user-one" });
|
|
179
|
+
await pubsub.close();
|
|
180
|
+
await pubsub.close();
|
|
181
|
+
await expect(pubsub.publish(realtimeTopics.server, syncEvent)).rejects.toBeInstanceOf(PubSubClosedError);
|
|
182
|
+
await expect(pubsub.getPresenceSnapshot()).rejects.toBeInstanceOf(PubSubClosedError);
|
|
183
|
+
expect(listener).not.toHaveBeenCalled();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
//# sourceMappingURL=local.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.test.js","sourceRoot":"","sources":["../../../sources/modules/realtime/local.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PresenceSnapshot, RealtimeEvent, RealtimeTopic } from "./events.js";
|
|
2
|
+
export type RealtimeSubscriber = (event: RealtimeEvent) => void | Promise<void>;
|
|
3
|
+
export type Unsubscribe = () => void;
|
|
4
|
+
export interface PresenceConnection {
|
|
5
|
+
readonly connectionId: string;
|
|
6
|
+
readonly userId: string;
|
|
7
|
+
readonly occurredAt?: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Transport-neutral ephemeral fanout. A Redis adapter can implement the same
|
|
11
|
+
* contract without changing route code. No implementation may treat it as the
|
|
12
|
+
* source of truth for sync state.
|
|
13
|
+
*/
|
|
14
|
+
export interface PubSub {
|
|
15
|
+
publish(topic: RealtimeTopic, event: RealtimeEvent): Promise<void>;
|
|
16
|
+
subscribe(topic: RealtimeTopic, subscriber: RealtimeSubscriber): Unsubscribe;
|
|
17
|
+
connectPresence(connection: PresenceConnection): Promise<PresenceSnapshot>;
|
|
18
|
+
recordPresenceActivity(connectionId: string, occurredAt?: number): Promise<PresenceSnapshot | undefined>;
|
|
19
|
+
disconnectPresence(connectionId: string, occurredAt?: number): Promise<PresenceSnapshot | undefined>;
|
|
20
|
+
getPresenceSnapshot(userIds?: readonly string[]): Promise<readonly PresenceSnapshot[]>;
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export declare class PubSubClosedError extends Error {
|
|
24
|
+
constructor();
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=pubsub.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pubsub.d.ts","sourceRoot":"","sources":["../../../sources/modules/realtime/pubsub.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAElF,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAChF,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACnB,OAAO,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,kBAAkB,GAAG,WAAW,CAAC;IAE7E,eAAe,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC3E,sBAAsB,CAClB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IACzC,kBAAkB,CACd,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IACzC,mBAAmB,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,gBAAgB,EAAE,CAAC,CAAC;IAEvF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IACxC,cAGC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pubsub.js","sourceRoot":"","sources":["../../../sources/modules/realtime/pubsub.ts"],"names":[],"mappings":"AAkCA,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACxC;QACI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IACpC,CAAC;CACJ"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Client } from "@libsql/client";
|
|
2
|
+
import type { IdempotencyAcquireInput, IdempotencyAcquireResult, IdempotencyCompleteInput, IdempotencyStore } from "./idempotency.js";
|
|
3
|
+
/** Shared SQLite/libSQL adapter; leases and fencing remain authoritative across processes. */
|
|
4
|
+
export declare class DatabaseIdempotencyStore<TResponse> implements IdempotencyStore<TResponse> {
|
|
5
|
+
private readonly client;
|
|
6
|
+
private readonly db;
|
|
7
|
+
private readonly ownsClient;
|
|
8
|
+
constructor(source: string | Client, authToken?: string);
|
|
9
|
+
acquire(input: IdempotencyAcquireInput): Promise<IdempotencyAcquireResult<TResponse>>;
|
|
10
|
+
complete(input: IdempotencyCompleteInput<TResponse>): Promise<boolean>;
|
|
11
|
+
release(storageKey: string, token: string): Promise<boolean>;
|
|
12
|
+
purgeExpired(now: number, limit?: number): Promise<number>;
|
|
13
|
+
close(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=database-idempotency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-idempotency.d.ts","sourceRoot":"","sources":["../../../sources/modules/request/database-idempotency.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAG3D,OAAO,KAAK,EACR,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,gBAAgB,EACnB,MAAM,kBAAkB,CAAC;AAU1B,8FAA8F;AAC9F,qBAAa,wBAAwB,CAAC,SAAS,CAAE,YAAW,gBAAgB,CAAC,SAAS,CAAC;IACnF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IAErC,YAAY,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAKtD;IAEK,OAAO,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC,SAAS,CAAC,CAAC,CA8C1F;IAEK,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAyB3E;IAEK,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBjE;IAEK,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB9D;IAED,KAAK,IAAI,IAAI,CAEZ;CACJ"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { createId } from "@paralleldrive/cuid2";
|
|
2
|
+
import { and, asc, eq, inArray, lte, sql } from "drizzle-orm";
|
|
3
|
+
import { createClient } from "@libsql/client";
|
|
4
|
+
import { createDatabase, retrySqliteBusy } from "../drizzle.js";
|
|
5
|
+
import { idempotencyKeys } from "../schema.js";
|
|
6
|
+
const requestKey = (storageKey) => and(eq(idempotencyKeys.principalType, "system"), eq(idempotencyKeys.principalId, "http"), eq(idempotencyKeys.scope, "request"), eq(idempotencyKeys.idempotencyKey, storageKey));
|
|
7
|
+
/** Shared SQLite/libSQL adapter; leases and fencing remain authoritative across processes. */
|
|
8
|
+
export class DatabaseIdempotencyStore {
|
|
9
|
+
client;
|
|
10
|
+
db;
|
|
11
|
+
ownsClient;
|
|
12
|
+
constructor(source, authToken) {
|
|
13
|
+
this.ownsClient = typeof source === "string";
|
|
14
|
+
this.client =
|
|
15
|
+
typeof source === "string" ? createClient({ url: source, authToken }) : source;
|
|
16
|
+
this.db = createDatabase(this.client);
|
|
17
|
+
}
|
|
18
|
+
async acquire(input) {
|
|
19
|
+
return retrySqliteBusy(() => this.db.transaction(async (tx) => {
|
|
20
|
+
let row = await find(tx, input.storageKey);
|
|
21
|
+
if (row && Date.parse(row.expiresAt) <= input.now) {
|
|
22
|
+
await tx.delete(idempotencyKeys).where(eq(idempotencyKeys.id, row.id));
|
|
23
|
+
row = undefined;
|
|
24
|
+
}
|
|
25
|
+
if (row) {
|
|
26
|
+
if (row.requestHash !== input.fingerprint)
|
|
27
|
+
return { kind: "conflict" };
|
|
28
|
+
if (row.status === "completed")
|
|
29
|
+
return {
|
|
30
|
+
kind: "replay",
|
|
31
|
+
response: JSON.parse(requiredJson(row.responseJson)),
|
|
32
|
+
};
|
|
33
|
+
if (row.lockedUntil && Date.parse(row.lockedUntil) > input.now)
|
|
34
|
+
return { kind: "in_progress", retryAt: Date.parse(row.lockedUntil) };
|
|
35
|
+
await tx
|
|
36
|
+
.update(idempotencyKeys)
|
|
37
|
+
.set({
|
|
38
|
+
status: "in_progress",
|
|
39
|
+
requestHash: input.fingerprint,
|
|
40
|
+
responseStatus: null,
|
|
41
|
+
responseJson: JSON.stringify({ leaseToken: input.leaseToken }),
|
|
42
|
+
lockedUntil: iso(input.leaseExpiresAt),
|
|
43
|
+
expiresAt: iso(input.recordExpiresAt),
|
|
44
|
+
updatedAt: sql `CURRENT_TIMESTAMP`,
|
|
45
|
+
})
|
|
46
|
+
.where(eq(idempotencyKeys.id, row.id));
|
|
47
|
+
return { kind: "acquired" };
|
|
48
|
+
}
|
|
49
|
+
await tx.insert(idempotencyKeys).values({
|
|
50
|
+
id: createId(),
|
|
51
|
+
principalType: "system",
|
|
52
|
+
principalId: "http",
|
|
53
|
+
scope: "request",
|
|
54
|
+
idempotencyKey: input.storageKey,
|
|
55
|
+
requestHash: input.fingerprint,
|
|
56
|
+
status: "in_progress",
|
|
57
|
+
responseJson: JSON.stringify({ leaseToken: input.leaseToken }),
|
|
58
|
+
lockedUntil: iso(input.leaseExpiresAt),
|
|
59
|
+
expiresAt: iso(input.recordExpiresAt),
|
|
60
|
+
});
|
|
61
|
+
return { kind: "acquired" };
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
async complete(input) {
|
|
65
|
+
return retrySqliteBusy(() => this.db.transaction(async (tx) => {
|
|
66
|
+
const row = await find(tx, input.storageKey);
|
|
67
|
+
if (!row || row.status !== "in_progress")
|
|
68
|
+
return false;
|
|
69
|
+
if (leaseToken(row.responseJson) !== input.leaseToken)
|
|
70
|
+
return false;
|
|
71
|
+
const changed = await tx
|
|
72
|
+
.update(idempotencyKeys)
|
|
73
|
+
.set({
|
|
74
|
+
status: "completed",
|
|
75
|
+
responseJson: JSON.stringify(input.response),
|
|
76
|
+
lockedUntil: null,
|
|
77
|
+
expiresAt: iso(input.recordExpiresAt),
|
|
78
|
+
updatedAt: sql `CURRENT_TIMESTAMP`,
|
|
79
|
+
})
|
|
80
|
+
.where(and(eq(idempotencyKeys.id, row.id), eq(idempotencyKeys.status, "in_progress")))
|
|
81
|
+
.returning({ id: idempotencyKeys.id });
|
|
82
|
+
return changed.length === 1;
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
async release(storageKey, token) {
|
|
86
|
+
return retrySqliteBusy(() => this.db.transaction(async (tx) => {
|
|
87
|
+
const row = await find(tx, storageKey);
|
|
88
|
+
if (!row || row.status !== "in_progress" || leaseToken(row.responseJson) !== token)
|
|
89
|
+
return false;
|
|
90
|
+
const changed = await tx
|
|
91
|
+
.delete(idempotencyKeys)
|
|
92
|
+
.where(and(eq(idempotencyKeys.id, row.id), eq(idempotencyKeys.status, "in_progress")))
|
|
93
|
+
.returning({ id: idempotencyKeys.id });
|
|
94
|
+
return changed.length === 1;
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
async purgeExpired(now, limit = 1_000) {
|
|
98
|
+
return retrySqliteBusy(() => this.db.transaction(async (tx) => {
|
|
99
|
+
const due = await tx
|
|
100
|
+
.select({ id: idempotencyKeys.id })
|
|
101
|
+
.from(idempotencyKeys)
|
|
102
|
+
.where(lte(idempotencyKeys.expiresAt, iso(now)))
|
|
103
|
+
.orderBy(asc(idempotencyKeys.expiresAt), asc(idempotencyKeys.id))
|
|
104
|
+
.limit(limit);
|
|
105
|
+
if (due.length === 0)
|
|
106
|
+
return 0;
|
|
107
|
+
return (await tx
|
|
108
|
+
.delete(idempotencyKeys)
|
|
109
|
+
.where(inArray(idempotencyKeys.id, due.map(({ id }) => id)))
|
|
110
|
+
.returning({ id: idempotencyKeys.id })).length;
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
close() {
|
|
114
|
+
if (this.ownsClient)
|
|
115
|
+
this.client.close();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function find(executor, storageKey) {
|
|
119
|
+
const rows = await executor.select().from(idempotencyKeys).where(requestKey(storageKey));
|
|
120
|
+
return rows[0];
|
|
121
|
+
}
|
|
122
|
+
function leaseToken(value) {
|
|
123
|
+
if (typeof value !== "string")
|
|
124
|
+
return undefined;
|
|
125
|
+
try {
|
|
126
|
+
const parsed = JSON.parse(value);
|
|
127
|
+
return typeof parsed.leaseToken === "string" ? parsed.leaseToken : undefined;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function requiredJson(value) {
|
|
134
|
+
if (value === null)
|
|
135
|
+
throw new Error("Idempotency response is missing");
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
function iso(value) {
|
|
139
|
+
return new Date(value).toISOString();
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=database-idempotency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-idempotency.js","sourceRoot":"","sources":["../../../sources/modules/request/database-idempotency.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type { AuthService } from "../auth/service.js";
|
|
3
|
+
import { type IdempotencyCoordinator } from "./idempotency.js";
|
|
4
|
+
export interface StoredHttpResponse {
|
|
5
|
+
statusCode: number;
|
|
6
|
+
contentType?: string;
|
|
7
|
+
payload: string;
|
|
8
|
+
encoding: "utf8" | "base64";
|
|
9
|
+
}
|
|
10
|
+
/** Adds optional Idempotency-Key support uniformly to authenticated JSON POST actions. */
|
|
11
|
+
export declare function registerIdempotencyHooks(app: FastifyInstance, auth: AuthService, coordinator: IdempotencyCoordinator<StoredHttpResponse>): void;
|
|
12
|
+
//# sourceMappingURL=idempotency-hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency-hook.d.ts","sourceRoot":"","sources":["../../../sources/modules/request/idempotency-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAKH,KAAK,sBAAsB,EAE9B,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,kBAAkB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC/B;AAED,0FAA0F;AAC1F,wBAAgB,wBAAwB,CACpC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,WAAW,EACjB,WAAW,EAAE,sBAAsB,CAAC,kBAAkB,CAAC,GACxD,IAAI,CAwFN"}
|