Skip to content

New v4.9.0 created automatically from CircleCI#140

Merged
MikeDev75015 merged 7 commits into
mainfrom
develop
May 25, 2026
Merged

New v4.9.0 created automatically from CircleCI#140
MikeDev75015 merged 7 commits into
mainfrom
develop

Conversation

@MikeDev75015

Copy link
Copy Markdown
Owner
  • feat(presence): add DynamicApiPresenceModule with pluggable adapters
    Implement WebSocket presence tracking plugin with:

    • PresenceAdapter interface + DYNAMIC_API_PRESENCE_ADAPTER injection token
    • InMemoryPresenceAdapter (Map-based, multi-tab support)
    • RedisPresenceAdapter (ioredis, atomic Lua SREM+DEL, configurable TTL)
    • PresenceGateway (createPresenceGateway factory, shared namespace/Option B)
      emits user:online / user:offline events
    • PresenceController (GET /presence[?room=], opt-in via enableController)
    • DynamicApiPresenceModule.register({ adapter, redisUrl?, redisTtlSeconds?, enableController? })
    • 72 unit tests, 100% coverage on all presence files
    • E2E spec: presence.e2e-spec.ts (real MongoDB + NestJS)
    • README/presence.md documentation

    ioredis added as direct dependency (v5.10.1).

  • fix(presence): add @public() to PresenceController and fix e2e race conditions
    The global DynamicApiJwtAuthGuard was blocking GET /presence (401)
    because the route lacked the @public() decorator. Added @public() to
    getOnlineUsers so the endpoint is accessible without a JWT token.

    Also fixed two e2e race conditions where waitForEvent(user:online) was
    registered after the event had already fired:

    • user:offline test: register listener before authenticated socket connects
    • GET /presence test: same pattern, then await confirmation before HTTP call

    Added jest.setTimeout(20000) for the full e2e suite to avoid flaky timeouts
    during slow CI app initialisation.

    All 6 presence e2e tests now pass, unit coverage remains 100% (73 tests).

  • docs(presence): document GET /presence as public endpoint (no JWT required)
    Add a note explaining that GET /presence is decorated with @public()
    and therefore bypasses DynamicApiJwtAuthGuard.

  • fix(presence): break circular dependency by moving presence out of modules barrel
    Export presence module directly from src/index.ts instead of modules/index.ts.
    The cycle was: interfaces/dynamic-api-options → ../modules → presence.module
    → dynamic-api.module → ./modules (already loading), causing DYNAMIC_API_PRESENCE_ADAPTER
    to be undefined at decorator application time (TypeError: decorator is not a function).

  • refactor(presence): remove unnecessary non-null assertion in InMemoryPresenceAdapter
    Replace get()! pattern with a local variable + nullish coalescing to avoid
    the redundant assertion warning.

  • fix(presence): replace String(err) with JSON.stringify in gateway error handler
    Avoids '[object Object]' default stringification for non-Error thrown values.

  • chore(release): 4.9.0

Mickael N. and others added 7 commits May 25, 2026 07:06
Implement WebSocket presence tracking plugin with:
- PresenceAdapter interface + DYNAMIC_API_PRESENCE_ADAPTER injection token
- InMemoryPresenceAdapter (Map-based, multi-tab support)
- RedisPresenceAdapter (ioredis, atomic Lua SREM+DEL, configurable TTL)
- PresenceGateway (createPresenceGateway factory, shared namespace/Option B)
  emits user:online / user:offline events
- PresenceController (GET /presence[?room=], opt-in via enableController)
- DynamicApiPresenceModule.register({ adapter, redisUrl?, redisTtlSeconds?, enableController? })
- 72 unit tests, 100% coverage on all presence files
- E2E spec: presence.e2e-spec.ts (real MongoDB + NestJS)
- README/presence.md documentation

ioredis added as direct dependency (v5.10.1).
…onditions

The global DynamicApiJwtAuthGuard was blocking GET /presence (401)
because the route lacked the @public() decorator. Added @public() to
getOnlineUsers so the endpoint is accessible without a JWT token.

Also fixed two e2e race conditions where waitForEvent(user:online) was
registered after the event had already fired:
- user:offline test: register listener before authenticated socket connects
- GET /presence test: same pattern, then await confirmation before HTTP call

Added jest.setTimeout(20000) for the full e2e suite to avoid flaky timeouts
during slow CI app initialisation.

All 6 presence e2e tests now pass, unit coverage remains 100% (73 tests).
…uired)

Add a note explaining that GET /presence is decorated with @public()
and therefore bypasses DynamicApiJwtAuthGuard.
…dules barrel

Export presence module directly from src/index.ts instead of modules/index.ts.
The cycle was: interfaces/dynamic-api-options → ../modules → presence.module
→ dynamic-api.module → ./modules (already loading), causing DYNAMIC_API_PRESENCE_ADAPTER
to be undefined at decorator application time (TypeError: decorator is not a function).
…PresenceAdapter

Replace get()! pattern with a local variable + nullish coalescing to avoid
the redundant assertion warning.
…or handler

Avoids '[object Object]' default stringification for non-Error thrown values.
Copilot AI review requested due to automatic review settings May 25, 2026 05:52
@sonarqubecloud

sonarqubecloud Bot commented May 25, 2026

Copy link
Copy Markdown

@MikeDev75015 MikeDev75015 merged commit 00aaae9 into main May 25, 2026
7 of 9 checks passed
@MikeDev75015 MikeDev75015 removed the request for review from Copilot May 25, 2026 06:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant