Skip to content

[APPS][Connections Part 3] Resolve same-module backend connection IDs#340

Draft
sdkennedy2 wants to merge 1 commit intosdkennedy2/apps-inline-connection-id-manifestfrom
sdkennedy2/apps-same-module-connection-id-analysis
Draft

[APPS][Connections Part 3] Resolve same-module backend connection IDs#340
sdkennedy2 wants to merge 1 commit intosdkennedy2/apps-inline-connection-id-manifestfrom
sdkennedy2/apps-same-module-connection-id-analysis

Conversation

@sdkennedy2
Copy link
Copy Markdown
Collaborator

@sdkennedy2 sdkennedy2 commented May 6, 2026

Motivation

This is part 3 of the connection ID manifest stack. Inline string literals are too narrow for realistic backend functions, where authors commonly name connection IDs or group them in a local object.

Changes

Extends same-file extraction to resolve static values declared in the backend module. The extractor now supports top-level const string identifiers, const-to-const chains, static template literals without interpolations, and one-level object member reads from same-file const object literals.

Examples now supported:

const HTTP_CONNECTION_ID = 'conn-id';
request({ connectionId: HTTP_CONNECTION_ID, inputs: {} });
const CONNECTIONS = { HTTP: 'conn-id' };
request({ connectionId: CONNECTIONS.HTTP, inputs: {} });

The PR preserves fail-closed behavior for mutable bindings, unresolved identifiers, imported values, dynamic templates, computed/spread object forms, function calls, env reads, and nested member chains. Imported module traversal remains deferred to part 4.

QA Instructions

  • Run NODE_OPTIONS=--experimental-vm-modules ~/.yarn/switch/bin/yarn workspace @dd/tests jest --config jest.config.ts ../plugins/apps/src/backend/discovery.test.ts ../plugins/apps/src/backend/extract-connection-ids.test.ts ../plugins/apps/src/index.test.ts ../plugins/apps/src/vite/index.test.ts ../plugins/apps/src/vite/dev-server.test.ts ../plugins/apps/src/upload.test.ts --runInBand.
  • Run ~/.yarn/switch/bin/yarn workspace @dd/apps-plugin typecheck.
  • Run ~/.yarn/switch/bin/yarn workspace @dd/tests typecheck.
  • Confirm imported identifier/object member cases still fail until part 4.

Blast Radius

This affects static analysis inside a single backend entry module. It does not load or resolve imported modules, so behavior remains bounded to files already being transformed by the apps plugin.

Documentation

Copy link
Copy Markdown
Collaborator Author

sdkennedy2 commented May 6, 2026

@sdkennedy2 sdkennedy2 changed the title [APPS] Resolve same-module backend connection IDs [APPS][Part 3 of 4] Resolve same-module backend connection IDs May 6, 2026
@sdkennedy2
Copy link
Copy Markdown
Collaborator Author

@codex review
@cursor review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8000ecd7eb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +320 to +324
const init = bindings.consts.get(name);
if (!init) {
fail(
`Unsupported connectionId expression in ${filePath}: identifier '${name}' is not a top-level same-file const binding.`,
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Respect local shadowing before resolving constants

When a backend function declares a local CONNECTION_ID that shadows a top-level const, this lookup still resolves the identifier from the module-wide top-level map because the walker visits calls in nested scopes without checking local bindings. For example, const CONNECTION_ID = 'prod'; function run() { const CONNECTION_ID = getId(); request({ connectionId: CONNECTION_ID }); } would emit prod instead of failing closed for the dynamic local value, producing an incorrect connection manifest.

Useful? React with 👍 / 👎.

@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from 8000ecd to b3ebcdc Compare May 6, 2026 00:47
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch from b9320d3 to 3e1b24d Compare May 6, 2026 00:47
@sdkennedy2
Copy link
Copy Markdown
Collaborator Author

@codex review
@cursor review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b3ebcdc55e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

);
}

const init = bindings.consts.get(name);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Check lexical scope before resolving consts

When a backend function has a local binding that shadows a top-level connection constant, this lookup still resolves the identifier from the module-level consts map because the AST walk does not track lexical scope. For example, with const CONNECTION_ID = 'prod' at the top level and function run() { const CONNECTION_ID = getConnectionId(); request({ connectionId: CONNECTION_ID }); }, the manifest records 'prod' even though the call uses the inner dynamic value; the fail-closed behavior should reject the scoped binding instead of emitting a wrong connection ID.

Useful? React with 👍 / 👎.

@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch from 3e1b24d to 97a160d Compare May 6, 2026 00:54
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from b3ebcdc to a367b98 Compare May 6, 2026 00:54
@sdkennedy2
Copy link
Copy Markdown
Collaborator Author

@codex review
@cursor review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a367b98b6f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +280 to +281
if (node.type === 'Identifier') {
return resolveConnectionIdIdentifier(node.name, bindings, filePath, resolutionStack);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Respect shadowed connectionId identifiers

When a backend call is inside a nested scope that declares the same name as a top-level const, this resolves the connectionId from the module-level map rather than the binding that is actually in scope. For example, with const CONNECTION_ID = 'prod' at the top level and function run() { const CONNECTION_ID = 'dev'; request({ connectionId: CONNECTION_ID }); }, the manifest records prod even though the runtime call uses dev, so the generated backend-function metadata can omit the connection that is actually required.

Useful? React with 👍 / 👎.

Comment on lines +389 to +395
if (objectInit.type !== 'ObjectExpression') {
fail(
`Unsupported connectionId expression in ${filePath}: object '${objectName}' must be initialized to an object literal.`,
);
}

return resolveObjectMemberValue(objectInit, propertyName, bindings, filePath, resolutionStack);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fail closed when const connection maps are mutated

This treats any top-level const object literal as immutable, but const only freezes the binding, not its properties. In modules that update the map before or around the backend call, e.g. const CONNECTIONS = { HTTP: 'old' }; CONNECTIONS.HTTP = 'new'; request({ connectionId: CONNECTIONS.HTTP });, the extractor records old while runtime uses new; the existing checks fail closed for spreads/computed keys because they can hide members, and property assignments can hide them in the same way.

Useful? React with 👍 / 👎.

@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from a367b98 to a735063 Compare May 6, 2026 13:35
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch from 97a160d to 9bcbfc1 Compare May 6, 2026 13:35
@sdkennedy2
Copy link
Copy Markdown
Collaborator Author

@codex review
@cursor review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a735063a8d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +280 to +281
if (node.type === 'Identifier') {
return resolveConnectionIdIdentifier(node.name, bindings, filePath, resolutionStack);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid resolving shadowed IDs from top-level consts

When a call is inside an inner scope that declares a local CONNECTION_ID, walk still visits that call but collectSameModuleBindings only recorded top-level bindings; this branch then resolves the identifier by name from the top-level map without checking lexical shadowing. In the inspected backend extraction flow, const CONNECTION_ID = 'prod'; function run() { const CONNECTION_ID = 'dev'; request({ connectionId: CONNECTION_ID }); } records prod even though runtime sends dev, corrupting the manifest; please fail closed on shadowed identifiers or track scopes before resolving.

Useful? React with 👍 / 👎.

@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch from 9bcbfc1 to a0cea42 Compare May 6, 2026 13:45
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from a735063 to 397f9ba Compare May 6, 2026 13:45
@sdkennedy2 sdkennedy2 changed the title [APPS][Part 3 of 4] Resolve same-module backend connection IDs [APPS][Connections Part 3] Resolve same-module backend connection IDs May 6, 2026
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch from a0cea42 to 806c29a Compare May 6, 2026 13:48
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch 2 times, most recently from 1b589d7 to e56eae5 Compare May 6, 2026 13:49
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch 2 times, most recently from 61615b2 to 5e1d743 Compare May 6, 2026 17:44
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from e56eae5 to e8fff5b Compare May 6, 2026 17:44
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch from 5e1d743 to c5c7d75 Compare May 6, 2026 18:10
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from e8fff5b to e142b33 Compare May 6, 2026 18:10
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from e142b33 to 883e8e4 Compare May 6, 2026 18:28
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch 2 times, most recently from 0affdd3 to a013be2 Compare May 6, 2026 20:42
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from 883e8e4 to 638ffe0 Compare May 6, 2026 20:42
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch from a013be2 to 5c281d2 Compare May 6, 2026 20:53
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from 638ffe0 to 705b4da Compare May 6, 2026 20:53
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-inline-connection-id-manifest branch from 5c281d2 to c3c12a6 Compare May 6, 2026 21:10
@sdkennedy2 sdkennedy2 force-pushed the sdkennedy2/apps-same-module-connection-id-analysis branch from 705b4da to c3a5e2c Compare May 6, 2026 21:10
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