Skip to content

refactor(platform)!: source the organization from the SDK instance - #691

Draft
vnaren23 wants to merge 4 commits into
mainfrom
naren/platform-org-from-sdk
Draft

refactor(platform)!: source the organization from the SDK instance#691
vnaren23 wants to merge 4 commits into
mainfrom
naren/platform-org-from-sdk

Conversation

@vnaren23

@vnaren23 vnaren23 commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Methods Changed

The organization is no longer a call-site argument on either method — both read it from the SDK instance they were constructed with.

Layer Method Signature before Signature after
Service platform.getUserSettings() getUserSettings(keys: PlatformSettingKey[], userId: string, options?: PlatformSettingGetOptions): Promise<PlatformSetting[]> getUserSettings(keys: PlatformSettingKey[], userId: string): Promise<PlatformSetting[]>
Service platform.updateUserSettings() updateUserSettings(settings: PlatformSettingUpsert[], userId: string, organizationId: string): Promise<PlatformSetting[]> updateUserSettings(settings: PlatformSettingUpsert[], userId: string): Promise<PlatformSetting[]>

Warning

Breaking. Both methods shipped in 1.6.1. updateUserSettings() loses a required positional argument and getUserSettings() loses its options argument; the PlatformSettingGetOptions type is removed from the public API.

Endpoint Called

Unchanged — no new endpoints, so no Cloudflare whitelist update was needed.

Method HTTP Endpoint OAuth Scope
getUserSettings() GET ../identity_/api/Setting PM.Setting / PM.Setting.Read
updateUserSettings() PUT ../identity_/api/Setting PM.Setting / PM.Setting.Write
  • Extends BaseService, unchanged. The organization reaches the API through the request path alone — ApiClient builds {baseUrl}/{orgName}/identity_/api/Setting from the SDK's own config — so the methods no longer send an organization of their own.
  • Both operations stay bulk and user-scoped: userId is always sent, so a call never reads or writes across an organization.
  • The Platform integration suite was the only consumer of the UIPATH_ORGANIZATION_ID test secret, so its config field and README row are removed with it.

Note

One follow-up left: .github/workflows/coverage.yml still plumbs the now-unused UIPATH_ORGANIZATION_ID secret through (lines 87 and 124). Nothing reads it any more, so it is inert, but it should be dropped — it could not be pushed from here without the workflow OAuth scope.

Example Usage

import { UiPath } from '@uipath/uipath-typescript/core';
import { Platform, PlatformSettingKey } from '@uipath/uipath-typescript/platform';

const sdk = new UiPath(config);
await sdk.initialize();
const platform = new Platform(sdk);

// Basic usage
const settings = await platform.getUserSettings([PlatformSettingKey.UserTheme], '<userId>');
const theme = settings.find(s => s.key === PlatformSettingKey.UserTheme)?.value;

// Several keys at once
const all = await platform.getUserSettings(
  [
    PlatformSettingKey.UserTheme,
    PlatformSettingKey.UserAccessibility,
    PlatformSettingKey.UserCasePinnedInstancesByTenant,
  ],
  '<userId>'
);

// Structured settings arrive as a JSON string
const pinned = all.find(s => s.key === PlatformSettingKey.UserCasePinnedInstancesByTenant);
const parsed = pinned ? JSON.parse(pinned.value) : {};

// Write — no organization argument
await platform.updateUserSettings(
  [{ key: PlatformSettingKey.UserTheme, value: 'dark' }],
  '<userId>'
);

API Response vs SDK Response

No response change. The transform pipeline and every field mapping are untouched:

Transform pipeline

transformData(data, PlatformSettingMap)

Field mapping

API Response SDK Response Change Reason
partitionGlobalId organizationId Rename Identity calls the organization a "partition" on the wire; the SDK exposes the platform-facing name
id, key, value, userId unchanged Already camelCase

What changed is the request, not the response:

Wire param Before After
partitionGlobalId (GET query) Sent when the caller passed options.organizationId Not sent — the organization is already the {orgName} segment of the request path
partitionGlobalId (PUT body) The caller's required organizationId argument Not sent — same reason

Every PlatformSetting still carries organizationId, so callers who need the organization back can still read it off any row.

Important

Needs a live check before merge. When this endpoint was onboarded (#629), omitting the scope was observed to fall back to the host partition and return 403 — and {orgName} was already on the path then, since ApiClient always inserts it. If that still holds, dropping partitionGlobalId will 403 and the last commit should be reverted. The integration suite in tests/integration/shared/platform/ covers exactly this; it has not been run here (no live credentials in the authoring environment).

Sample SDK Response

No sample captured for this PR — the response shape is unchanged from #629, and there are no live credentials in this environment to re-run the E2E app against. Unit tests assert the wire params and the response transform on both methods; the integration suite exercises the live round-trip.

Files

Area Files
Service src/services/platform/platform.ts
Types src/models/platform/platform.types.ts (removed PlatformSettingGetOptions)
Models src/models/platform/platform.models.ts (JSDoc + signatures)
Barrel exports src/services/platform/index.ts (module @example)
Unit tests tests/unit/services/platform/platform.test.ts (30 tests)
Integration tests tests/integration/shared/platform/platform.integration.test.ts (8 tests)
Test config tests/integration/config/test-config.ts, tests/integration/README.md (removed the now-unused UIPATH_ORGANIZATION_ID)

Verification

npm run typecheck clean · npm run lint 0 errors · npm run test:unit 2467 passed · npm run build OK · npm run docs:validate 0 errors (2 pre-existing warnings in conversational-agent/protocol.types.ts)

Integration tests were not run — no live credentials in this environment.

🤖 Auto-generated using onboarding skills

Comment on lines 141 to 143
expect(spec.params.userId).toBe(PLATFORM_TEST_CONSTANTS.USER_ID);
expect(spec.params).not.toHaveProperty('partitionGlobalId');
// The SDK name never reaches the wire — only the API's own `partitionGlobalId`
expect(spec.params).not.toHaveProperty('organizationId');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The test name says "alongside the organization" but the body only asserts userId is present and that the SDK alias organizationId doesn't leak to the wire. It never checks that partitionGlobalId itself IS included, so removing the partitionGlobalId: this.config.orgName line from getUserSettings would leave this test green.

The sibling test above ("should scope the read to the SDK's organization…") does verify the full param object, but the intent of this test — an "always" invariant covering both user and org — is incomplete without the positive assertion.

Suggested change
expect(spec.params.userId).toBe(PLATFORM_TEST_CONSTANTS.USER_ID);
expect(spec.params).not.toHaveProperty('partitionGlobalId');
// The SDK name never reaches the wire — only the API's own `partitionGlobalId`
expect(spec.params).not.toHaveProperty('organizationId');
expect(spec.params.userId).toBe(PLATFORM_TEST_CONSTANTS.USER_ID);
expect(spec.params.partitionGlobalId).toBe(PLATFORM_TEST_CONSTANTS.ORGANIZATION_ID);
// The SDK name never reaches the wire — only the API's own `partitionGlobalId`
expect(spec.params).not.toHaveProperty('organizationId');

@claude

claude Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Review summary: one finding posted this run — the test 'should always send userId alongside the organization' (platform.test.ts L141-143) doesn't assert that partitionGlobalId IS included, only that userId is present and the SDK alias is absent. Suggestion posted inline. Everything else looks good: BaseService.config typing is correct (Zod enforces orgName non-empty at SDK construction), the write-path test at L262-270 implicitly covers partitionGlobalId via Object.keys(), and the overall refactor is clean.

@claude

claude Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

✅ No issues found. Checked for bugs and CLAUDE.md compliance.

@kittyyueli kittyyueli left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is it possible to get the userId from the SDK instance as well? Or because it can be an external app, that's not possible?

@vnaren23

Copy link
Copy Markdown
Collaborator Author

Is it possible to get the userId from the SDK instance as well? Or because it can be an external app, that's not possible?

Right, external app, backend usage and cli usage means we might not have user id at all times.

@vnaren23
vnaren23 marked this pull request as ready for review August 26, 2026 06:01
@vnaren23
vnaren23 requested a review from a team August 26, 2026 06:01
@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

✅ No issues found. Checked for bugs and CLAUDE.md compliance.

vnaren23 and others added 3 commits August 26, 2026 11:39
Platform settings are scoped to an (organization, user) pair, but the
organization was passed in per call — as an option on getUserSettings and
a required positional argument on updateUserSettings. The SDK already
knows which organization it was initialized against, so both methods now
read it from the instance and callers only supply the user.

BREAKING CHANGE: updateUserSettings() no longer takes an organizationId
argument and getUserSettings() no longer takes an options argument.
PlatformSettingGetOptions is removed. Both shipped in 1.6.1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Remove the integration-test organizationId config, orphaned when the
Platform suite stopped needing it; drop the stale README row; stop the
module @example deriving userId from a read result that may omit the key.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restore the service class comment and drop the per-method scoping notes,
so the module, service class, and ServiceModel comments all read as they
did before. The signature change alone drives the remaining JSDoc edits.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vnaren23
vnaren23 force-pushed the naren/platform-org-from-sdk branch from 5d76286 to be8d5c8 Compare August 26, 2026 06:09
The organization is already on the request path — ApiClient builds
{baseUrl}/{orgName}/identity_/api/Setting — so sending it again as
partitionGlobalId on the read and in the body on the write is redundant.

Reverts the BaseService.config.orgName accessor added earlier on this
branch: Platform was its only consumer, and nothing reads it now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

✅ No issues found. Checked for bugs and CLAUDE.md compliance.

@vnaren23
vnaren23 marked this pull request as draft August 27, 2026 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants