feat(deskcrew): add DeskCrew to the registry - #856
Conversation
DeskCrew is a support widget combining live chat, AI answers grounded in a
knowledge base, a help centre and a changelog.
Configured by data attributes, so it follows the Umami shape rather than a
programmatic init: `data-key` plus optional `board`, `color`, `position`,
`greeting` and `launcher`. `|| undefined` guards every optional because with
envDefaults an unset field resolves to '' and unhead would render an empty
attribute onto the tag.
Uses a synchronous `use()` rather than `resolve({ waitFor })`. desk.js is a
single synchronous IIFE: the queue stub and the real API are assigned at the same
nesting level with no async boundary between them, so the API exists by the time
the load event fires. The widget also assigns its methods onto the stub instead
of replacing the object, so the global keeps one identity for the life of the
page and a handle taken before load stays live.
`bundle` and `proxy` are deliberately absent, and the type reflects that via
RegistryScriptInput<..., false, false>. The widget derives its API origin from
the executing script's own `src`, so bundling to /_scripts/assets would repoint
every API call at the consuming site's origin, and proxying would put that site's
server in the path of live chat polling. A negative test in proxy-configs pins
it with the reason.
The facade mirrors ScriptCrisp, including its slot-ordering quirk so the two
support facades stay identical. Its readiness signal is the widget's Shadow DOM
host (#deskcrew-root) rather than script load, because load fires before anything
renders and would hide the facade over an empty screen.
Identity is deliberately not a schema field. It is a signed per-visitor token, and
everything in nuxt.config is a deploy-time constant, so baking one visitor's token
into a build would hand that identity to everyone. It goes through
proxy.identify({ token }) at runtime, documented on the docs page.
|
@webmilmind1 is attempting to deploy a commit to the Nuxt Team on Vercel. A member of the Team first needs to authorize it. |
commit: |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds DeskCrew as a supported script integration. The change defines typed options and API interfaces, registry metadata, schemas, and logos. It adds Estimated code review effort: 3 (Moderate) | ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/content/scripts/deskcrew.md`:
- Around line 18-19: Update the in-page links in the documentation sentence to
use valid fragments matching the renderer-generated heading IDs, or add explicit
stable IDs to the corresponding useScriptDeskCrew and ScriptDeskCrew headings.
Keep both links targeting their intended sections.
In `@packages/script/src/runtime/registry/schemas.ts`:
- Line 299: Update the schema field widgetKey to reject empty strings by
composing string() with nonEmpty(...) or minLength(1), while preserving
validation of non-empty string values.
In `@test/types/types.test-d.ts`:
- Around line 107-109: Update the type assertion for DeskCrewApi['embed'] to
verify its parameter matches DeskCrewEmbedOptions, rather than only checking
that parameter 0 is not any. Preserve the required single-argument contract so
the assertion fails if embed becomes optional.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1d6ab666-53b0-4709-b088-c9752d136ed0
📒 Files selected for processing (16)
docs/content/scripts/deskcrew.mdpackages/script/src/registry-logos.tspackages/script/src/registry-types.jsonpackages/script/src/registry.tspackages/script/src/runtime/components/ScriptDeskCrew.vuepackages/script/src/runtime/registry/deskcrew.tspackages/script/src/runtime/registry/schemas.tspackages/script/src/runtime/types.tspackages/script/src/script-meta.tsplayground/nuxt.config.tsplayground/pages/index.vueplayground/pages/third-parties/deskcrew/default.vueplayground/pages/third-parties/deskcrew/facade.vuetest/nuxt-runtime/chat-components-lifecycle.nuxt.test.tstest/types/types.test-d.tstest/unit/proxy-configs.test.ts
| Use [`useScriptDeskCrew()`{lang="ts"}](#usescriptdeskcrew){lang="ts"} for direct SDK calls, or | ||
| [`<ScriptDeskCrew>`{lang="html"}](#scriptdeskcrew){lang="html"} for a custom chat launcher. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Fix the in-page link fragments.
Markdownlint reports #usescriptdeskcrew and #scriptdeskcrew as invalid fragments. Add explicit stable heading IDs or update the fragments to match the IDs generated by the documentation renderer.
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 18-18: Link fragments should be valid
(MD051, link-fragments)
[warning] 19-19: Link fragments should be valid
(MD051, link-fragments)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/content/scripts/deskcrew.md` around lines 18 - 19, Update the in-page
links in the documentation sentence to use valid fragments matching the
renderer-generated heading IDs, or add explicit stable IDs to the corresponding
useScriptDeskCrew and ScriptDeskCrew headings. Keep both links targeting their
intended sections.
Source: Linters/SAST tools
Both from CodeRabbit review on nuxt#856. widgetKey was a bare string(), and envDefaults resolves an unset key to '', so an app with the module installed but nothing configured validated happily and rendered data-key="" onto the tag: a keyless widget talking to no workspace, in silence. pipe(string(), minLength(1)) fails it loudly in dev instead, matching the four schemas here that already guard ids this way. The embed type assertion only proved parameter 0 was not `any`, which still passes if the parameter later becomes optional. It now pins the full signature, because a portal with no host element renders nowhere at all and nothing would have caught it. Not taking the third comment: markdownlint MD051 flags the in-page fragments in the docs intro, but those two lines are the same shape crisp.md uses (#usescriptcrisp, #scriptcrisp). The rule does not understand the MDC syntax in those headings, and diverging would make this the only script page written differently. Happy to change it if the docs renderer really does generate different ids.
Adds DeskCrew, following up on #177. Thanks for the go-ahead @harlan-zw.
DeskCrew is a support widget combining live chat, AI answers grounded in a
knowledge base, a help centre and a changelog.
Shape
Data attributes, so it follows the Umami shape rather than a programmatic init:
data-keyplus optionalboard,color,position,greeting,launcher.|| undefinedguards every optional, because withenvDefaultsan unset fieldresolves to
''and unhead renders an empty attribute onto the tag.Synchronous
use()rather thanresolve({ waitFor }). I checked this againstthe widget source rather than assuming:
desk.jsis a single synchronous IIFEwith the queue stub and the real API assigned at the same nesting level and no
async boundary between them, so the API exists by the time the
loadeventfires. Crisp needs
resolve()because its API genuinely arrives after an asyncready callback; this does not.
On the stale-reference question I raised in #177
Fixed on our side before opening this, so nothing here depends on a pending
release. The widget now assigns its methods onto the early stub instead of
replacing the object, so
window.DeskCrewkeeps one identity for the life ofthe page and a handle taken before load stays live. It also sets a
loadedflaglast, if a readiness signal is ever wanted.
No bundle, no proxy, deliberately
The widget derives its API origin from the executing script's own
src.Bundling to
/_scripts/assetswould repoint every API call at the consumingsite's origin and break the widget; proxying would put that site's server in the
path of live chat polling. The type reflects this via
RegistryScriptInput<..., false, false>so the option is not even offered, andthere is a negative test in
proxy-configsnaming the reason.Identity is not a schema field
It is a signed per-visitor token, and everything in
nuxt.configis adeploy-time constant, so baking one visitor's token into a build would hand that
identity to every other visitor. It goes through
proxy.identify({ token })atruntime instead, documented on the docs page.
Facade
Mirrors
ScriptCrisp, including its slot-ordering quirk (thestatus === 'loading' || !isReadybranch making the named#errorslotunreachable) so the two support facades stay identical. Happy to fix both in a
follow-up, but I did not want to change Crisp's behaviour inside this PR.
Its readiness signal is the widget's Shadow DOM host (
#deskcrew-root) ratherthan script load, since load fires before anything renders and would hide the
facade over an empty screen.
Verification, honestly
pnpm lintpasses with zero warnings, including theai-deslop-*rules, whichcaught four things in my docs prose that I rewrote.
pnpm generate:typesran and picked the entry up.I could not run
typecheckor the test projects locally: the vitest configloads the built
@nuxt/scripts, andnuxt-module-buildfails in my environmenton
loadTSCompilerOptions. I confirmed that is not from this branch by stashingeverything and rebuilding a clean checkout, which fails identically. Relying on
CI here, and happy to fix whatever it finds.
Not included
The
:deskcrew-demolive component thatcrisp.mdandintercom.mduse. Thepublic repo's
docs/contains onlycontent/, and the app defining those demoblocks is not here, so a maintainer would need to add it. The page is written to
read correctly without it.