Skip to content

[PLT-106969]feat(buckets): accept bucket id or name on file ops; add folderKey/folderPath to getAll#607

Open
deepeshrai-tech wants to merge 2 commits into
mainfrom
feat/buckets-name-support
Open

[PLT-106969]feat(buckets): accept bucket id or name on file ops; add folderKey/folderPath to getAll#607
deepeshrai-tech wants to merge 2 commits into
mainfrom
feat/buckets-name-support

Conversation

@deepeshrai-tech

Copy link
Copy Markdown
Contributor

Summary

  • Widens 5 BucketService file-op methods (deleteFile, getFileMetaData, getFiles, getReadUri, uploadFile) to accept bucket: number | string — either a numeric Id or a bucket Name. Names are resolved via a lean OData $filter=Name eq '…'&$select=Id&$top=1 lookup on the folder-scoped Buckets collection.
  • Extends BucketGetAllOptions with folderKey?: string and folderPath?: string so getAll() can be scoped by any of the three folder refs. getAll() with no folder options remains a cross-folder query — deliberately does not fall back to the SDK init-time meta-tag folderKey (non-breaking).
  • Extracts shared name-lookup logic into a private findByNameInFolder helper on FolderScopedService; both getByNameLookup (full-resource fetch) and the new resolveIdByName (Id-only projection) delegate to it.

Public API surface

// Before
buckets.deleteFile(bucketId: number, path, options?);
buckets.uploadFile(bucketId: number, path, content, options?);
buckets.getAll(options?: { folderId?: number, ...odata });

// After
buckets.deleteFile(bucket: number | string, path, options?);
buckets.uploadFile(bucket: number | string, path, content, options?);
buckets.getAll(options?: {
  folderId?: number,
  folderKey?: string,
  folderPath?: string,
  ...odata,
});

Positional forms are the primary API. Deprecated options-only overloads (uploadFile({ bucketId, ... }), getReadUri({ bucketId, ... })) remain numeric-only for bucketId — they're already on the way out.

Design notes

  • Numeric ids skip the resolver entirely — no extra API call.
  • Name resolution runs inside the same folder scope the caller provides (folderId / folderKey / folderPath); missing name → NotFoundError with folder hint.
  • Resolver is not @track-decorated; the outer public method's @track fires once (avoids the delegation double-telemetry anti-pattern).
  • coerceBucketId distinguishes missing-value from invalid-value error messages (bucket is required vs bucket must be a positive numeric Id).
  • getAll() picks the endpoint based on whether any folder ref is in options — not on folderId alone — so folderKey/folderPath correctly trigger the folder-scoped endpoint. Endpoint constants unchanged.

Test plan

  • Unit: 87 tests in buckets.test.ts (all passing). New coverage: bucket-name resolution for all 5 methods, NotFoundError propagation, numeric id skips name lookup regression guard, positive-Id validation, folderKey/folderPath on getAll, cross-folder-default preserved when SDK has init-time folderKey.
  • Integration: added File operations - by bucket name block exercising all 5 methods end-to-end + folderKey scoping on the by-name path; added folderKey/folderPath cases to the getAll describe.
  • Typecheck + lint clean.
  • Full unit-test suite: 2071/2071 passing.
  • Rollup build produces dist/ cleanly.
  • Verified locally against alpha Orchestrator via a React sample app (kept local; not shipped with this PR).

🤖 Generated with Claude Code

…lderPath to getAll

Extends 5 BucketService file-operation methods so their first parameter
accepts `bucket: number | string` — either a numeric bucket Id or a
bucket Name. When a name is supplied the SDK resolves it to an Id via
an OData `$filter=Name eq '…'&$select=Id&$top=1` lookup on the
folder-scoped Buckets collection.

Methods updated:
- `deleteFile`
- `getFileMetaData`
- `getFiles`
- `getReadUri`
- `uploadFile`

Also extends `BucketGetAllOptions` with `folderKey?: string` and
`folderPath?: string` so `getAll()` can be scoped by any of the three
folder refs. `getAll()` with no folder options deliberately remains a
cross-folder query — it does not fall back to the SDK init-time
meta-tag folderKey (documented, non-breaking).

Shared name-lookup logic (name validation + folder header resolution +
OData filter + empty-result → NotFoundError) is extracted into a
private `findByNameInFolder` helper on `FolderScopedService`; both
`getByNameLookup` (full-resource fetch) and the new `resolveIdByName`
(Id-only projection) delegate to it.

Unit and integration coverage added for all name-path scenarios and
for `folderKey` / `folderPath` on `getAll()`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@deepeshrai-tech
deepeshrai-tech requested a review from a team July 15, 2026 18:04
Comment thread src/services/orchestrator/buckets/buckets.ts Outdated
Comment thread tests/unit/services/orchestrator/buckets.test.ts Outdated
Comment thread tests/integration/shared/orchestrator/buckets.integration.test.ts Outdated
@claude

claude Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review findings

Three issues found this run:

1. Regression in coerceBucketId — invalid Id escapes validation (link)
The check bucket <= 0 does not catch non-finite values. A caller passing parseInt('bad', 10) gets a silent pass-through to the API URL. Old guard (!bucketId) caught this; new one does not. Fix: !Number.isFinite(bucket) || bucket <= 0.

2. Missing regression guard for 4 of 5 sibling methods (link)
The "numeric id skips name lookup" test only covers deleteFile. Per convention, each sibling method needs its own test for shared configuration patterns.

3. (f: any) in integration test (link)
metadata.items is typed — use BlobItem instead of any.

- `coerceBucketId`: reject `NaN` / `Infinity` via `Number.isFinite`, not
  just `<= 0`. `parseInt('bad', 10)` and similar no longer leak into the
  API URL.
- Add "numeric id skips name lookup" regression guard for all four
  sibling methods (`uploadFile`, `getReadUri`, `getFileMetaData`,
  `getFiles`) — previously only `deleteFile` was covered.
- Widen the NaN/Infinity validation test alongside the existing 0/-5
  cases.
- Type integration-test callbacks as `BlobItem` instead of `any`.

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

Copy link
Copy Markdown

@claude

claude Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

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

* Uploads a file to a bucket — options-only form.
*
* @deprecated Use the positional form: `uploadFile(bucketId, path, content, options?)`. See {@link BucketUploadFileRequestOptions} for the supported options.
* @deprecated Use the positional form: `uploadFile(bucket, path, content, options?)`. See {@link BucketUploadFileRequestOptions} for the supported options.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This shouldnt be changing right?

({ folderId, folderKey, folderPath, ...restOptions } = opts);
}

const bucketId = await this.coerceBucketId(

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.

this extra would need OR.Buckets.Read. Pls update oauth-scopes.md


const { folderId, folderKey, folderPath } = options ?? {};

const bucketId = await this.coerceBucketId(

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.

This would require OR.Buckets.Read permission. Pls verify/update oauth-scopes.md

throw new ValidationError({ message: `bucket is required for ${callerLabel}` });
}
if (typeof bucket === 'number') {
if (!Number.isFinite(bucket) || bucket <= 0) {

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.

Suggested change
if (!Number.isFinite(bucket) || bucket <= 0) {
if (!Number.isInteger(bucket) || bucket <= 0) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants