Skip to content

feat: add @adobe/spacecat-shared-drs-client package (LLMO-1819)#1398

Merged
dzehnder merged 3 commits intomainfrom
feat/drs-client-package
Mar 4, 2026
Merged

feat: add @adobe/spacecat-shared-drs-client package (LLMO-1819)#1398
dzehnder merged 3 commits intomainfrom
feat/drs-client-package

Conversation

@dzehnder
Copy link
Contributor

@dzehnder dzehnder commented Mar 2, 2026

Summary

  • New shared package @adobe/spacecat-shared-drs-client providing an HTTP client for the Data Retrieval Service (DRS) API
  • Enables both spacecat-api-service and spacecat-audit-worker to interact with DRS for prompt generation and brand presence re-analysis
  • Methods: createFrom(), isConfigured(), submitJob(), submitPromptGenerationJob(), triggerBrandDetection(), getJob()
  • 17 unit tests, 100% coverage

Context

As part of the migration from Mystique to DRS for brand presence execution, both api-service (onboarding) and audit-worker (config-change triggers) need to call DRS. The client was previously a local file in api-service only.

Dependent PRs

  • spacecat-api-service: Migrates from local drs-client.js to this shared package
  • spacecat-audit-worker: Uses this package to replace Mystique brand presence triggers with DRS calls

Test plan

  • 17 unit tests with nock HTTP mocking
  • 100% line, branch, function, and statement coverage
  • E2E: verify DRS job submission after shared package is published

Made with Cursor

Shared HTTP client for the Data Retrieval Service (DRS) API, enabling
both spacecat-api-service and spacecat-audit-worker to interact with DRS
for prompt generation and brand presence re-analysis.

Methods: createFrom(), isConfigured(), submitJob(), submitPromptGenerationJob(),
triggerBrandDetection(), getJob()

17 unit tests, 100% coverage.

Made-with: Cursor
@dzehnder dzehnder force-pushed the feat/drs-client-package branch from cdf8056 to 5367f0f Compare March 2, 2026 17:16
@github-actions
Copy link

github-actions bot commented Mar 2, 2026

This PR will trigger a minor release when merged.

…ex (LLMO-1819)

- Send `brand` instead of `brand_name` (DRS validates `parameters.brand`)
- Default numPrompts to 50 instead of 42
- Guard regex against null apiBaseUrl to resolve CodeQL polynomial regex alert

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@AndreiAlexandruParaschiv
Copy link
Contributor

AndreiAlexandruParaschiv commented Mar 2, 2026

There's a parallel effort on #1382 that also introduces a DRS client package. The two PR's have different use cases for DRS but create the same package. Maybe the two PRs can find a common ground? @rarescheseli

@dzehnder
Copy link
Contributor Author

dzehnder commented Mar 4, 2026

Thanks @AndreiAlexandruParaschiv! I was not aware of that. However @rarescheseli seems off today and I need this right away. So I propose that after I merge, @rarescheseli can add all the other functionalities that is needed afterwards.

Copy link
Contributor

@danieljchuser danieljchuser left a comment

Choose a reason for hiding this comment

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

PR Review: @adobe/spacecat-shared-drs-client

Overall: Clean, well-structured new package that follows established monorepo patterns. 17 tests with 100% coverage thresholds. A few issues to address:


Issues

1. MEDIUM — Missing context caching in createFrom()

src/index.js:26-27 — The BrandClient (and other shared clients) cache the newly created instance back onto context so subsequent calls reuse it:

// BrandClient pattern:
const client = new BrandClient({ apiBaseUrl, apiKey }, log);
context.brandClient = client;   // <-- caches it
return client;

DrsClient checks for a cached instance but never caches a newly created one:

if (context.drsClient) return context.drsClient;
return new DrsClient({ apiBaseUrl, apiKey }, log);  // not cached

This means every call to createFrom() creates a new instance unless the caller pre-populates context.drsClient manually. Suggest adding context.drsClient = client; before returning, consistent with BrandClient.

2. LOW — CodeQL polynomial regex alert still active

src/index.js:31 — The second commit says it "guards regex against null apiBaseUrl to resolve CodeQL polynomial regex alert", but both CodeQL bot comments are still present. The regex /\/+$/ is technically fine (not truly polynomial), but CodeQL flags it. A non-regex alternative would silence it:

let url = apiBaseUrl || '';
while (url.endsWith('/')) url = url.slice(0, -1);
this.apiBaseUrl = url || undefined;

Or simply mark it as a false positive in CodeQL if the team prefers.

3. LOW — model: 'gpt-5-nano' hardcoded

src/index.js:117 — The model name is hardcoded in submitPromptGenerationJob. If DRS supports different models, this should probably be a parameter (with a default). If it's intentionally fixed, a comment explaining why would help future readers.

4. LOW — TypeScript declaration inconsistency

src/index.d.ts:44triggerBrandDetection returns Promise<unknown> while other methods return typed results (Promise<DrsJobResult>, Promise<Record<string, unknown>>). Consider Promise<Record<string, unknown>> or a dedicated interface for consistency.

5. NITS

  • package.json — Missing bugs and homepage fields that other packages (e.g. brand-client) include. Very minor but keeps things consistent.
  • src/index.js:82submitJob accesses result.job_id unconditionally in the log. If the response doesn't contain job_id (e.g., unexpected response shape), this would log undefined. A guard or optional chain would be safer.

Cross-Repository Impact Assessment

Specialist Impact Notes
API (api-service) LOW — Additive New dependency to adopt. Dependent PR exists. No breaking changes to existing contracts.
AUDIT (audit-worker) LOW — Additive New dependency to adopt. Dependent PR exists. No breaking changes.
INFRA (infrastructure) NONE No new queues, buckets, or IAM changes needed. DRS is an external HTTP service.
All others NONE Pure addition, no impact on existing packages or contracts.

Positive Notes

  • Follows existing monorepo conventions well (.nycrc.json, .releaserc.cjs, .mocha-multi.json, test setup)
  • Good use of tracingFetch from spacecat-shared-utils for observability
  • Clean separation: generic submitJob for extensibility + specialized submitPromptGenerationJob
  • 100% coverage thresholds enforced
  • Non-JSON response handling is a nice touch (204 responses)

Verdict

Approve with minor suggestions — The missing context caching (#1) is the most impactful item. The rest are low/nit-level. No breaking changes to any existing cross-repo contracts.

1. Cache newly created client on context (consistent with BrandClient)
2. Replace regex with while loop for trailing slash removal (CodeQL)
3. Add comment explaining hardcoded model name
4. Fix TypeScript return type for triggerBrandDetection
5. Add bugs/homepage to package.json, guard result.job_id access

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dzehnder dzehnder merged commit 186a544 into main Mar 4, 2026
7 checks passed
@dzehnder dzehnder deleted the feat/drs-client-package branch March 4, 2026 13:14
solaris007 pushed a commit that referenced this pull request Mar 4, 2026
# @adobe/spacecat-shared-drs-client-v1.0.0 (2026-03-04)

### Features

* add @adobe/spacecat-shared-drs-client package (LLMO-1819) ([#1398](#1398)) ([186a544](186a544))
@solaris007
Copy link
Member

🎉 This PR is included in version @adobe/spacecat-shared-drs-client-v1.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

dzehnder added a commit to adobe/spacecat-api-service that referenced this pull request Mar 5, 2026
…819) (#1892)

## Summary
- Replace local `src/support/drs-client.js` with
`@adobe/spacecat-shared-drs-client`
- Update `llmo-onboarding.js` to use `DrsClient.createFrom(context)`
(class pattern)
- Delete local client and its tests (now covered by the shared package)

## Dependencies
- **Blocked by**:
[spacecat-shared#1398](adobe/spacecat-shared#1398)
— shared package must be published first
- Add `@adobe/spacecat-shared-drs-client` to `package.json` after it's
published

## Test plan
- [x] Updated esmock mocks for class-based `createFrom()` pattern
- [ ] CI will fail on `import/no-unresolved` until shared package is
published
- [ ] E2E: verify LLMO onboarding still triggers DRS prompt generation

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
dzehnder added a commit to adobe/spacecat-audit-worker that referenced this pull request Mar 5, 2026
…2061)

## Summary
- Remove dead `triggerMystiqueCategorization` code (DRS config writer
already populates categories via LLMO-1819)
- Replace `triggerGeoBrandPresence` / `triggerGeoBrandPresenceRefresh`
calls in `llmo-customer-analysis` with
`DrsClient.triggerBrandDetection()` for config-change flows
- Remove `isAdobe` guard — DRS now handles all sites uniformly (Adobe
and external)
- Keep old Mystique trigger functions for backward compatibility (manual
Slack triggers)

## What changed in llmo-customer-analysis
| Trigger | Before | After |
|---|---|---|
| First-time onboarding (categorization) | Mystique API call | Removed
(DRS already writes categories) |
| No config version (first setup) | `triggerGeoBrandPresence` → Mystique
| `triggerBrandDetection` → DRS |
| Topics/categories/entities change | `triggerGeoBrandPresence` →
Mystique (non-Adobe only) | `triggerBrandDetection` → DRS (all sites) |
| Brands/competitors change | `triggerGeoBrandPresenceRefresh` →
Mystique (non-Adobe only) | `triggerBrandDetection` → DRS (all sites) |

## Dependencies
- **Blocked by**:
[spacecat-shared#1398](adobe/spacecat-shared#1398)
— shared DRS client package
- Add `@adobe/spacecat-shared-drs-client` to `package.json` after it's
published
- **Infrastructure**: `DRS_API_URL` and `DRS_API_KEY` env vars must be
added to audit-worker deployment (spacecat-infrastructure)

## Test plan
- [ ] CI will fail on `import/no-unresolved` until shared package is
published
- [ ] Update unit tests for `llmo-customer-analysis` handler
- [ ] E2E: verify config changes trigger DRS brand detection instead of
Mystique

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants