Skip to content

client SDK drops the precise spec types at its boundary: 32 methods return Promise< any > on a package that already depends on @objectstack/spec #8140

Description

@huangyiirene

Noticed while completing the ISecurityService contract test for #7831 (PR #8139) — recorded, not fixed, and deliberately kept outside that PR's two-file scope. Filed unassigned.

The observation

packages/client/src/index.ts declares 32 methods returning Promise< any >, on a package that already depends on @objectstack/spec ("@objectstack/spec": "workspace:*" in its dependencies) — so the precise contract types are reachable, and the any is not forced by a decoupling constraint.

The worked example that surfaced it, security.describeDelegableScope:

describeDelegableScope: async(): Promise<any>=>{constres=awaitthis.fetch(`${this.baseUrl}/api/v1/security/my-delegable-scope`);returnthis.unwrapResponse<any>(res);},

Its own TSDoc, immediately above, names placeableBusinessUnitIds, assignablePositions, the adminScopes they derive from, and isTenantAdmin: true — that is, the comment describes exactly the shape DelegableScope already declares in packages/spec/src/contracts/security-service.ts, and that the route really returns. The type is written, published and reachable, then dropped at the SDK boundary.

Why it may be worth grading

  • packages/client*/** is the "Public API, DX, type safety" lane in AGENTS.md's Context Routing table, and it is the surface customer projects actually hold.
  • It is the check:exported-any shape one layer out. That gate exists in packages/spec precisely because the api-surface snapshot records that an export exists, never what it resolves to; the client has no equivalent gate, and 32 of its methods currently resolve to any.
  • Same divergence FAMILY as client SDK types the invitation status union by hand, and it is missing expired (same divergence family as #7726) #7781 (the client SDK hand-typing an invitation status union that spec already declared, then drifting from it). That one was a hand-copy that rotted; this is the other half — no type at all.

Explicitly NOT claimed

I did not measure whether each of the 32 has a precise spec type available — only that describeDelegableScope does. The count is therefore not a severity claim: some are likely genuinely open shapes (the contract deliberately types AudienceBindingSuggestion as Record< string, unknown >, for one), and separating those from the real gaps is exactly what a triage round is for.

Related: #7831, PR #8139, #7781.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions