Skip to content

Proposal: Break circular dependency by extracting aio-lib-ims-core #79

Description

@itavy

Problem

There's a circular dependency between aio-lib-ims and aio-lib-ims-jwt:

aio-lib-ims
  ├── imports: aio-lib-ims-jwt (as plugin)
  
aio-lib-ims-jwt
  ├── peerDependency: aio-lib-ims (needs ims instance)
  └── calls: ims.getApiUrl(), ims.exchangeJwtToken()

This causes:

  • npm to install nested old copies (audit false positives)
  • Confusing dependency graph
  • Difficulty maintaining version compatibility

Analysis

What aio-lib-ims-jwt needs from aio-lib-ims:

  • ims.getApiUrl(path) - Get IMS API URL with path
  • ims.exchangeJwtToken(clientId, clientSecret, jwtToken) - Exchange JWT for access token

What aio-lib-ims needs from aio-lib-ims-jwt:

  • Plugin interface: supports(config), canSupport(config), imsLogin(ims, config)

Proposed Solution: Extract @adobe/aio-lib-ims-core

Create a new core package that both packages depend on:

aio-lib-ims-core (NEW)
├── ImsCore class (API URLs, token exchange)
├── Plugin interface definitions
└── Shared types/utilities

aio-lib-ims-jwt
├── depends on: aio-lib-ims-core
└── implements: ImsPlugin interface

aio-lib-ims
├── depends on: aio-lib-ims-core
├── depends on: aio-lib-ims-jwt (as plugin)
└── extends: ImsCore with plugin management

What goes in aio-lib-ims-core:

class ImsCore {
  constructor(env) { ... }
  
  // API URL helpers
  getApiUrl(path) { ... }
  
  // Token exchange (no plugin dependencies)
  exchangeJwtToken(clientId, clientSecret, jwtToken) { ... }
  getAccessToken(refreshToken, clientId, clientSecret, scope) { ... }
  invalidateToken(token, clientId, clientSecret) { ... }
}

// Plugin interface
interface ImsPlugin {
  canSupport(config): Promise<boolean>
  supports(config): boolean
  imsLogin(ims: ImsCore, config): Promise<string>
}

Benefits

No circular dependency - clean dependency graph
Architecturally correct - separation of concerns
Extensible - easier to add new auth plugins (SAML, API key, etc.)
Reusable - other packages can use core without full ims
Type safety - shared interfaces/types in one place
No audit false positives - no nested old copies

Implementation Strategy

Phase 1: Create core (beta)

  1. Create @adobe/aio-lib-ims-core@1.0.0-beta.1
  2. Extract: ImsCore class, plugin interfaces, token exchange
  3. Publish beta

Phase 2: Update jwt (beta)

  1. Release @adobe/aio-lib-ims-jwt@6.0.0-beta.1
  2. Depend on aio-lib-ims-core instead of peer on aio-lib-ims
  3. Publish beta

Phase 3: Update ims (beta)

  1. Release @adobe/aio-lib-ims@9.0.0-beta.1
  2. Extend ImsCore
  3. Depend on aio-lib-ims-jwt@^6.0.0-beta
  4. Publish beta

Phase 4: Stable release

Once validated in beta, release stable versions

Effort Estimate

  • Core extraction: 2-3 days
  • JWT refactor: 1 day
  • IMS refactor: 2-3 days
  • Testing: 2-3 days
  • Total: ~1-2 weeks

Alternative Considered

Make jwt a peer dependency in aio-lib-ims:

  • Simpler but doesn't solve architectural issues
  • Makes jwt plugin "special" vs other auth plugins
  • Consumers must install both packages manually

Related

Questions

  1. Is the Adobe team interested in this architectural refactor?
  2. What's the timeline/priority for this work?
  3. Should we coordinate with other auth plugin maintainers?

cc @dthampy for visibility

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions