Skip to content

feat(deskcrew): add DeskCrew to the registry - #856

Open
webmilmind1 wants to merge 2 commits into
nuxt:mainfrom
webmilmind1:feat/deskcrew-registry
Open

feat(deskcrew): add DeskCrew to the registry#856
webmilmind1 wants to merge 2 commits into
nuxt:mainfrom
webmilmind1:feat/deskcrew-registry

Conversation

@webmilmind1

Copy link
Copy Markdown

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-key plus optional board, color, position, greeting, launcher.
|| undefined guards every optional, because with envDefaults an unset field
resolves to '' and unhead renders an empty attribute onto the tag.

Synchronous use() rather than resolve({ waitFor }). I checked this against
the widget source rather than assuming: desk.js is a single synchronous IIFE
with 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 load event
fires. Crisp needs resolve() because its API genuinely arrives after an async
ready 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.DeskCrew keeps one identity for the life of
the page and a handle taken before load stays live. It also sets a loaded flag
last, 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/assets would repoint every API call at the consuming
site'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, and
there is a negative test in proxy-configs naming the reason.

Identity is 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 every other visitor. It goes through proxy.identify({ token }) at
runtime instead, documented on the docs page.

Facade

Mirrors ScriptCrisp, including its slot-ordering quirk (the
status === 'loading' || !isReady branch making the named #error slot
unreachable) 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) rather
than script load, since load fires before anything renders and would hide the
facade over an empty screen.

Verification, honestly

pnpm lint passes with zero warnings, including the ai-deslop-* rules, which
caught four things in my docs prose that I rewrote.

pnpm generate:types ran and picked the entry up.

I could not run typecheck or the test projects locally: the vitest config
loads the built @nuxt/scripts, and nuxt-module-build fails in my environment
on loadTSCompilerOptions. I confirmed that is not from this branch by stashing
everything and rebuilding a clean checkout, which fails identically. Relying on
CI here, and happy to fix whatever it finds.

Not included

The :deskcrew-demo live component that crisp.md and intercom.md use. The
public repo's docs/ contains only content/, and the app defining those demo
blocks is not here, so a maintainer would need to add it. The page is written to
read correctly without it.

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.
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

@webmilmind1 is attempting to deploy a commit to the Nuxt Team on Vercel.

A member of the Team first needs to authorize it.

@pkg-pr-new

pkg-pr-new Bot commented Aug 8, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/scripts@856

commit: cdd725f

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6ff004f9-2b84-484b-af73-1fe8c75ba843

📥 Commits

Reviewing files that changed from the base of the PR and between b972071 and cdd725f.

📒 Files selected for processing (3)
  • packages/script/src/registry-types.json
  • packages/script/src/runtime/registry/schemas.ts
  • test/types/types.test-d.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/types/types.test-d.ts
  • packages/script/src/registry-types.json
  • packages/script/src/runtime/registry/schemas.ts

📝 Walkthrough

Walkthrough

Adds DeskCrew as a supported script integration. The change defines typed options and API interfaces, registry metadata, schemas, and logos. It adds useScriptDeskCrew() and the ScriptDeskCrew component with loading, readiness, error, trigger, and slot support. It documents configuration and API usage, adds playground examples, and covers lifecycle, type, and proxy behavior with tests.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: adding DeskCrew to the registry.
Description check ✅ Passed The description directly explains the DeskCrew integration, design decisions, testing status, and scope.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between d0324e7 and b972071.

📒 Files selected for processing (16)
  • docs/content/scripts/deskcrew.md
  • packages/script/src/registry-logos.ts
  • packages/script/src/registry-types.json
  • packages/script/src/registry.ts
  • packages/script/src/runtime/components/ScriptDeskCrew.vue
  • packages/script/src/runtime/registry/deskcrew.ts
  • packages/script/src/runtime/registry/schemas.ts
  • packages/script/src/runtime/types.ts
  • packages/script/src/script-meta.ts
  • playground/nuxt.config.ts
  • playground/pages/index.vue
  • playground/pages/third-parties/deskcrew/default.vue
  • playground/pages/third-parties/deskcrew/facade.vue
  • test/nuxt-runtime/chat-components-lifecycle.nuxt.test.ts
  • test/types/types.test-d.ts
  • test/unit/proxy-configs.test.ts

Comment on lines +18 to +19
Use [`useScriptDeskCrew()`{lang="ts"}](#usescriptdeskcrew){lang="ts"} for direct SDK calls, or
[`<ScriptDeskCrew>`{lang="html"}](#scriptdeskcrew){lang="html"} for a custom chat launcher.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 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

Comment thread packages/script/src/runtime/registry/schemas.ts Outdated
Comment thread test/types/types.test-d.ts Outdated
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.
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