Repository navigation
Conversation
🎉 All green!🧪 All tests passed 🔗 Commit SHA: cac186d | Docs | View more details | Give us feedback! |
tyffical
force-pushed
the
tiffany.trinh/apps-2947-debug-bundle-connection-ids
branch
from
October 14, 2026 21:45
5126f2b to
5c7bf06
Compare
tyffical
marked this pull request as ready for review
October 16, 2026 01:06
tyffical
requested review from
Chau-DDOG,
duncanista,
oliverli and
sdkennedy2
and removed request for
a team
October 16, 2026 01:06
tyffical
force-pushed
the
tiffany.trinh/apps-2947-debug-bundle-connection-ids
branch
from
October 16, 2026 02:08
5c7bf06 to
43bb75f
Compare
oliverli
approved these changes
Oct 16, 2026
oliverli
left a comment
Collaborator
There was a problem hiding this comment.
The implementation looks correct. I found no correctness or security problems. The inline comments are about test coverage only, and they do not block this PR.
tyffical
force-pushed
the
tiffany.trinh/apps-2947-debug-bundle-connection-ids
branch
from
October 21, 2026 04:05
4a5e676 to
5f22e12
Compare
This was referenced Oct 21, 2026
POST /__dd/debugBundle answers with { code, allowedConnectionIds } when
the Accept header lists application/json without q=0, and keeps the
plain-text bundle otherwise. The route path and response type live in
the shared backend protocol so the browser client can use them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tyffical
force-pushed
the
tiffany.trinh/apps-2947-debug-bundle-connection-ids
branch
from
October 23, 2026 05:20
403cc08 to
2e8c7d4
Compare
A dev client, built as apps-dev-client, installs a hook the postMessage
transport calls before each run-query. When the page is framed by a
Datadog page, found through ancestorOrigins or, on Firefox, from the
origin of the parent's answer to a ping, the hook fetches the function's
bundle from /__dd/debugBundle and returns it with the parent's exact
origin. A hook that fails, throws or stalls never stops the call. A
parent with an opaque ("null") origin gets the call without a bundle,
and the page warns once.
The Vite plugin prepends a module script for virtual:dd-apps-dev-client
to served HTML, ahead of Vite's base rewrite, and loads the built
apps-dev-client file for it. The virtual id resolves only for client
requests while the dev server runs.
The transport posts a bundle only to an exact origin and accepts a
run-query response only from window.parent and, when it posted to an
exact origin, only from that origin. It copies the bundle's
allowedConnectionIds by index into a plain array before checking them,
so an array subclass can't choose what gets posted through
Symbol.species.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tyffical
force-pushed
the
tiffany.trinh/apps-2947-debug-bundle-connection-ids
branch
from
October 23, 2026 14:52
2e8c7d4 to
cac186d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
preview-asyncas the viewer, and its connection checks and consent prompt need that function's allowed connection IDs./__dd/debugBundle, then drops them; the endpoint returns only plain-text code.Architecture
flowchart LR subgraph frame["Preview frame (dev-served page)"] T["postMessageTransport"] DC["apps-dev-client hook"] end DS["Dev server: POST /__dd/debugBundle"] P["Parent: Live Preview pane"] T -- "hook installed? await it, max 120s" --> DC DC -- "Accept: application/json" --> DS DS -- "code + allowedConnectionIds" --> DC DC -- "targetOrigin + bundle" --> T T -- "run-query + bundle, exact origin only" --> P P -- "run-query:response, from window.parent only" --> Trun-queryto'*'as before. The hook is untrusted: a missing, failing, stuck (120s), throwing or malformed result posts the call without a bundle, and a bundle goes only to an exact target origin.apps-dev-clientsub-build is served asvirtual:dd-apps-dev-client, and a pre-ordertransformIndexHtmladds its base-prefixed script tag only to dev-served pages.https, the default port, and a hostname@dd/core'sparseSiteaccepts.location.ancestorOrigins[0]. Firefox has none, so the frame pings and uses the origin of the answer fromwindow.parent, which App Builder's bridge sends; with no answer within 2s the call goes out without a bundle and the page warns once.window.parentstill sets the origin. An opaque ("null") origin gets no bundle and one warning.Acceptlistsapplication/json(notq=0); anything else keeps the plain-text response byte-for-byte./__dd/executeActionViaCloudsends topreview-async, so they always matchcode.window.parent, and from the exact origin when the frame knows it; a malformed one rejects the call with aBackendFunctionError./__dd/debugBundle, bounded at 60s; any failure sends the call withoutbundleand warns. On the Edge route that absolute path falls outside the/api/unstable/live-preview/<host>/prefix, which the Live Preview backend already tracks.Changes
11 changes across the protocol, dev server, Vite plugin, dev client, transport and tests
DebugBundleResponse,DEBUG_BUNDLE_PATH, the message-type constants and the dev-client hook typespackages/plugins/apps/src/backend/protocol.ts{ code, allowedConnectionIds }as JSON whenAcceptlistsapplication/json; plain text otherwisepackages/plugins/apps/src/vite/dev-server.tsvirtual:dd-apps-dev-clientonly while a dev server runs, and link it from dev-served HTMLpackages/plugins/apps/src/vite/index.tsapps-dev-clientsub-build and its entrypackages/plugins/apps/package.json,packages/plugins/apps/src/built/apps-dev-client.tspackages/plugins/apps/src/backend/client/dev-client/dev-client.tspackages/plugins/apps/src/backend/client/transports/post-message-transport/post-message-transport.ts,types.tspackages/plugins/apps/src/backend/client/guards.ts,packages/plugins/apps/src/backend/client/request-id.tsdev-client.test.ts,post-message-transport.test.tsbasepackages/plugins/apps/src/vite/index.test.ts,dev-server.test.ts,dev-server.integration.test.ts,dev-client-build.test.tspackages/tests/src/_jest/helpers/fakeWindow.tspackages/plugins/apps/src/backend/client/execute-backend-function.test.tsQA Instructions
qa-server.cjsandqa-server-base.cjsbelow, with theactionCatalogCall.backend.tsfixture under the app root and no auth.QA_BROWSER=chromiumorQA_BROWSER=firefox. Playwright fulfills the parent page locally, so no request reaches the named host; the page answersapp-builder:pingas App Builder's bridge does.apps-runtime.mjsevery deployed app loads is 3496 bytes, andapps-dev-client.mjs, which only dev-served pages load, is 3414 bytes.Captured dev server, browser and build output
3.3.2-dev.N) from this head.@datadog/vite-pluginto it, reinstall, and fully restart Vite./@id/virtual:dd-apps-dev-clientis served and the*.backend.tsfiles load as proxy stubs.run-querycarriesbundle.allowedConnectionIds, and thepreview-asyncrun succeeds as the viewer (staging audit events).3.3.2-dev.4, published from an earlier head of this branch; the ADR page records it.@datadog/create-appsapp is pending on this head too; the staging run above covers the same path.QA harness source (dev servers, app and parent pages, browser and build scripts)
qa-app/holdsindex.html,nested/index.html(a copy),main.js,multi.html,multi.js,parent.html,parent-ping.html,backend/actionCatalogCall.backend.tsandnode_modules/@datadog/action-catalog(both copied withcp -RLfrompackages/tests/src/_jest/fixtures/apps_backend_project).Wis this repo's checkout andSthe harness directory, both passed as environment variables;QA_BROWSERpickschromium(default) orfirefox.Blast Radius
run-queryto'*'. It now ignores replies from windows other thanwindow.parentand rejects a malformed reply instead of hanging; App Builder's bridge always replies from the frame's parent./__dd/debugBundlereturns JSON only toAccept: application/json(Axios's default would get JSON; no such caller was found), and dev pages load one extra module.Out of Scope / Follow-ups
11 items deferred
bundleas untrusted app input: any script in the frame can post arbitrarycodeandallowedConnectionIdsallow-same-origingrant, and areferrerpolicythat masksancestorOrigins[0]as"null"would skip the bundle, since that case doesn't fall back to a pingsandboxorreferrerpolicychangeswwwanddocs) are accepted as the parent, to keep custom org subdomains workingacceptsJsonhonorsq=0but not relative q-values, and the JSON response sets noVary: AcceptpostMessagethrow rejects with the raw error, not aBackendFunctionError(pre-existing)'*', so its reply is checked against the parent window and request id but not an originDocumentation
packages/core/src/constants.ts(SITES) andpackages/core/src/helpers/site.ts(parseSite)🤖 Generated with Claude Code