Skip to content

feat(widget): userToken can be a function that returns a fresh token - #476

Merged
anurag629 merged 1 commit into
codercops:devfrom
Saifjafri212213:feat/widget-user-token-provider
Oct 30, 2026
Merged

anurag629 merged 1 commit into
codercops:devfrom
Saifjafri212213:feat/widget-user-token-provider

Conversation

@Saifjafri212213

Copy link
Copy Markdown
Collaborator

Summary

userToken can now be a function (sync or async) that returns a fresh signed token. The widget calls it right before it asks the server for a session, so a page that stays open for hours no longer sends an expired token. A string still works as before.

Closes #461

What changed

  • packages/widget/src/api/client.ts: new UserToken type (string | (() => string | undefined | Promise<string | undefined>)). The client resolves it in the /session request only, so it runs once per session request and never per message. If the function throws, rejects, returns something that is not a non-empty string, or takes over 5 seconds, the session starts without an identity, and the first two and the timeout log a console.warn. The timer is cleared when the function answers.
  • userToken in WidgetConfig takes the new type, and UserToken is exported. ChatCops.setUser({ token }) still sets a fixed string, and replaces the function (as it replaced the old string). setUser(null) signs out as before.
  • Docs: widget/api.mdx next to setUser, a new "A fresh token for each session" section in server/setup.mdx, and the type in the configuration.mdx listing.
  • api/widget.api.md regenerated, and a changeset for @chatcops/widget (minor).

Notes for review

  • The 5 second limit is a constant (USER_TOKEN_TIMEOUT). I picked it so a stuck token endpoint does not leave the visitor waiting for the whole 30 second request timeout. Say if you want another value, or an option.
  • A function that returns a number or an empty string does not log. Only a throw, a rejection and the timeout do.
  • The data attribute data-user-token stays a string, since a script tag cannot hold a function.
  • Panel size: 17.15 kB of 18 kB (about +130 B). The single file is 19.24 kB of 20 kB.

How I Tested This

  • Wrote the tests first: 9 of the new client tests failed on the old code, and the rest were guards.
  • tests/api/session.test.ts (client): the provider's token reaches /session; sync and async; not called when the server has no sessions; once per session request across three messages; a new call for the next session once the session token expired; undefined for a signed-out visitor; throws, rejects, non-string and empty string; the error being logged; the timeout (at 4.9 s it still waits, at 5.1 s it goes on) and no timer left behind; a fixed string as before; setUserToken replacing the function and being set later.
  • tests/user-token.test.ts (widget): called on the first message and not when the page loads, through ChatCops.init(), replaced by setUser, setUser(null), and a fixed string.
  • Type test for the config in api.test-d.ts.
  • Mutated the client in 7 ways (no timeout, timer not cleared, no string check, no empty check, no log, a 6 s limit, function ignored); a test fails for each.
  • New e2e tests against the real server with identity on: the page signs a token only when the session is requested (0 calls on load and on opening, 1 call after two messages) and the server accepts it; a token that is not valid gets the error message.
  • 769 widget tests pass, typecheck is clean, lint is at 39 warnings (the same as dev), size is within the limits, and pnpm docs:check finds no errors in the widget docs or my new section. The whole e2e suite passes except the three S7 reply with sources tests, which fail on a clean dev too. Other packages' docs samples fail the check here for missing builds.

AI assistance

An AI coding assistant helped write the change and the tests. I ran the checks listed above, including the real-server e2e in Chrome.

…odercops#461)

The widget calls it once each time it asks the server for a session, not per
message. A function that throws, rejects, returns a non-string or takes over
5 seconds means the session starts without the visitor, with a console
warning. A string still works as before, and setUser() replaces the function.

@anurag629 anurag629 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Saifjafri212213, this is what #461 asked for. The function is called once per /session request (client.ts:177), a failure or a call that takes over 5 s starts the session without the identity and logs it, the string form works as before, and UserToken is exported. With current dev merged in: build, typecheck, test:coverage, lint (same as dev), api:check, docs:check, size (panel 17.15 of 18 kB) and the full e2e suite (76, in Chrome, with your real-server test) pass.

One optional follow-up for consistency: setUser({ token }) still takes only a string (widget.ts:501), so a site that uses setUser can't hand over a function. Widening its type to UserToken would make the two ways of giving a token match. That's a separate small PR if you want it.

Merging once CI is green.

@anurag629
anurag629 merged commit 991839f into codercops:dev Oct 30, 2026
5 checks passed
@anurag629 anurag629 added the hacktoberfest-accepted PR counts for Hacktoberfest label Oct 30, 2026
@anurag629

Copy link
Copy Markdown
Member

Merged, thanks @Saifjafri212213.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hacktoberfest-accepted PR counts for Hacktoberfest

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Widget: fetch signed-in visitor tokens when a session is requested

2 participants