feat(apps): set @datadog/apps backend context - #457
Conversation
86682ae to
145ec69
Compare
145ec69 to
d982beb
Compare
There was a problem hiding this comment.
Pull request overview
Friend, this PR updates the Apps build plugin’s backend virtual-entry code generation to initialize the @datadog/apps backend runtime context ($) inside generated backend function bundles, aligning the generated entries with how the SDK expects helpers to run.
Changes:
- Add conditional detection of
@datadog/apps/backend/internal(via Node module resolution) and generate an optional import forsetBackendContext. - Emit a generated snippet to call
setBackendContext($)afterglobalThis.$ = $and before action-catalog registration / handler execution. - Extend unit tests to cover presence/absence of the backend-internal import and validate call ordering.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/plugins/apps/src/backend/virtual-entry.ts | Adds conditional SDK import and injects backend-context initialization into generated main($) entry. |
| packages/plugins/apps/src/backend/virtual-entry.test.ts | Adds coverage for the new conditional import and ordering constraints. |
| packages/plugins/apps/src/backend/shared.ts | Introduces reusable “is export installed” resolver + new import/snippet constants for Apps backend context. |
| packages/plugins/apps/src/backend/shared.test.ts | Adds unit tests for the new backend-context snippet behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
🎉 All green!🧪 All tests passed 🔗 Commit SHA: 1b2142d | Docs | Datadog PR Page | Give us feedback! |
Suggestion: add a real SDK integration test for #457I tested this end-to-end and the implementation works, but the manual test highlighted an important coverage gap: the current tests mock the SDK boundary and/or assert against generated source strings. They do not prove that a bundled backend importing the real I think we should add an integration test that:
That test would exercise the actual contract this PR introduces: Manual integration-test resultsFor validation, I scaffolded a real Vite React High Code App using the local
Published test app: https://dd.datad0g.com/app-builder/apps/4549e2d0-228a-438a-a923-fbba155763b8 Two QA-instruction corrections found while running this:
|
Follows the @datadog/apps-backend runtime entry-point split: the apps plugin now sets the JS-Function-with-Actions backend context and gates it on SDK availability, using the new backend-internal SDK entry and resolving published package exports to built dist output. Adds an integration test that exercises the real (non-mocked) @datadog/apps-backend SDK end-to-end through an actual Vite build via a new fixture project. Building that test surfaced and fixed a pre-existing bug: the Vite plugin destructured context.buildRoot once at setup time, before Vite's configResolved hook overwrites it with the resolved build root, so every downstream use (proxy codegen, backend function builds, dev-server middleware) could use a stale root when the bundler's resolved root differs from process.cwd() at setup time. Fixed by reading context.buildRoot live at each use site. That fix also exposed a second, previously dormant bug: the E2E appsPlugin fixture's @datadog/action-catalog stub was missing a package.json, so Node's require.resolve reported it as installed while Vite/Rollup failed to resolve the bare-specifier subpath import at build time. Fixed by adding the missing package.json. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4a040dc to
1b2142d
Compare
What and why?
Backend functions using
@datadog/apps-backendneed the runtime$context before SDK helpers run. Generated backend entries already receive that context, so the build plugin should initialize the SDK rather than requiring customer-authored handlers to wire it manually.This follows the existing action-catalog integration pattern while keeping the import optional for projects that do not expose the new SDK backend-internal entry point.
How?
@datadog/apps-backend/backend/internalfrom the customer project using Node module resolution.setBackendContextinto generated backend entries.setBackendContext($)after the runtime global is assigned and before action-catalog registration or the customer handler.The paired SDK change emits
@datadog/apps-backend/backend/internaland public backend modules against one shared code-split module, so this setter updates the same context read by SDK helpers.Related SDK work
QA
Prerequisites:
~/dd/web-uiand~/dd/build-pluginschecked out locally, logged into Datadog (OAuth is fine — no API/app keys needed unless yours lack "Actions API Access" scope).1. Check out the branches
2. Build the SDK packages and pack them as tarballs
3. Build the vite plugin and prepare it for external linking
4. Scaffold a new user app
5. Point the app at your local builds — in
package.json, add/change:6. Add a backend function that returns the invoking user — create
src/getUser.backend.ts:Edit
src/App.tsxto add a button that calls it and renders the result:7. Run it locally and verify
Open the printed
localhostURL in a browser, click Who am I?, confirm it renders your real Datadog user identity (email, id, name, organizationId).8. Upload and verify the published app
Open the printed
https://app.datadoghq.com/app-builder/apps-backend/...URL in a browser, click Who am I? again, confirm the same real user data renders.Cleanup:
yarn cli prepare-link --revertin~/dd/build-pluginsto restore the repo, and delete the test app from App Builder's app list.Blast radius
Limited to generated Datadog Apps backend entries when the customer project exposes
@datadog/apps-backend/backend/internal. Existing action-catalog initialization and projects without that SDK entry point retain their current behavior.Automated test coverage (added)
Manual QA above is now backed by an automated integration test that exercises the real, non-mocked
@datadog/apps-backendSDK end-to-end through an actual Vite build:packages/tests/src/_jest/fixtures/apps_backend_project/— a fixture project with@datadog/apps-backend@0.0.1as a real dependency (not mocked), including a backend function that callsgetExecutionUser/getInitiatingUserand one that doesn't use the SDK at all.packages/plugins/apps/src/backend/integration.test.ts— runs a real (unmocked) Vite build of the fixture through the apps plugin, dynamically imports the emitted backend bundle, and asserts: real SDK user resolution matches the invoking context, arguments forward correctly, a backend not using the SDK still works, and an invalid context is rejected.Building this test surfaced and fixed a real pre-existing bug:
packages/plugins/apps/src/vite/index.tsdestructuredcontext.buildRootonce at plugin-setup time, before Vite'sconfigResolvedhook overwrites it with the resolved build root — so every downstream use (proxy codegen, backend function builds, dev-server middleware) could use a stale root whenever the bundler's resolved root differs fromprocess.cwd()at setup time (e.g. monorepos, CI wrappers thatcdbefore invoking the bundler). This was invisible in every prior test because they all mockvite.build. Fixed by readingcontext.buildRootlive at each use site, matching the existing pattern ininjection/outputplugins. No behavior change for the common case where the two roots already match; corrects behavior when they don't.