Skip to content

[SQL Connect / Data Connect] adminNodeSdk TypeScript codegen references enum type names without declaring or exporting them in index.d.ts #10416

@mafreud

Description

@mafreud

[REQUIRED] Environment info

firebase-tools: 15.15.0

Platform: macOS 25.4.0 (darwin)

Node.js version: v22.22.2

firebase-admin version: 13.x

TypeScript version: 5.5.x

[REQUIRED] Test case

Generate the Node Admin SDK (adminNodeSdk) for a connector whose schema
contains a user-defined enum that is selected by a query.

dataconnect/schema/schema.gql:

enum InvitationStatus {
  PENDING
  ACCEPTED
  EXPIRED
}

type Invitation @table(key: "id") {
  id: UUID! @default(expr: "uuidV4()")
  email: String! @index
  token: String! @col(dataType: "text") @unique
  status: InvitationStatus! @default(value: PENDING)
  expiresAt: Timestamp!
  createdAt: Timestamp! @default(expr: "request.time")
}

dataconnect/connector/queries.gql:

query GetInvitationByToken($token: String!) @auth(level: USER) {
  invitations(where: { token: { eq: $token } }, limit: 1) {
    id
    email
    status
    expiresAt
    createdAt
  }
}

dataconnect/connector/connector.yaml:

connectorId: default
generate:
  adminNodeSdk:
    outputDir: ../../ts_functions/src/generated/dataconnect
    package: "@example/dataconnect-admin"
    packageJsonDir: ../../ts_functions

[REQUIRED] Steps to reproduce

  1. rm -rf ts_functions/src/generated/dataconnect
  2. npx firebase-tools@15.15.0 dataconnect:sdk:generate
  3. Open the generated ts_functions/src/generated/dataconnect/index.d.ts.
  4. Search the file for InvitationStatus.

[REQUIRED] Expected behavior

The generated index.d.ts should declare and export a TypeScript type for
every user-defined enum referenced in a query selection set, similar to how
scalar aliases are emitted today. For example:

export type InvitationStatus = "PENDING" | "ACCEPTED" | "EXPIRED";

so that the enum name referenced inside generated *Data interfaces
resolves correctly and can be imported by user code.

[REQUIRED] Actual behavior

The generated index.d.ts references InvitationStatus but never
declares or exports it. The only occurrence in the whole file is the
following line inside the query's Data interface:

export interface GetInvitationByTokenData {
  invitations: ({
    id: UUIDString;
    email: string;
    status: InvitationStatus;   // <-- name is not defined anywhere
    expiresAt: TimestampString;
    createdAt: TimestampString;
    // ...
  } & Invitation_Key)[];
}

Header of the file (for context) shows scalar aliases are exported, but no
enum alias / union is emitted:

import { ConnectorConfig, DataConnect, OperationOptions, ExecuteOperationResponse } from 'firebase-admin/data-connect';

export const connectorConfig: ConnectorConfig;

export type TimestampString = string;
export type UUIDString = string;
export type Int64String = string;
export type DateString = string;
// <-- no `export type InvitationStatus = ...` anywhere

InvitationStatus is also not re-exported from
firebase-admin/data-connect, so any consumer importing the generated
module gets TS2304 (Cannot find name 'InvitationStatus') when the
field is actually referenced, and downstream code is forced to
redeclare the union by hand, duplicating the schema.

Notes:

Minimal suggested fix

For every enum type that appears in any generated *Data interface
(or *Variables interface), emit a corresponding

export type <EnumName> = "<Value1>" | "<Value2>" | ...;

near the other exported type aliases (UUIDString, TimestampString,
etc.) at the top of index.d.ts, and emit the matching string-literal
values in index.cjs.js / esm/index.esm.js if a runtime object form
is also desired (otherwise the .d.ts alias alone is enough to resolve
the reference).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions