Skip to content

refactor(uploads): remove statusCallback in favor of maxStatusChecks#188

Merged
wesleyschlenker merged 1 commit intomainfrom
deps-and-eslint
Feb 26, 2026
Merged

refactor(uploads): remove statusCallback in favor of maxStatusChecks#188
wesleyschlenker merged 1 commit intomainfrom
deps-and-eslint

Conversation

@wesleyschlenker
Copy link
Collaborator

@wesleyschlenker wesleyschlenker commented Feb 24, 2026

There was actually one more unaddressed callback after I reviewed this morning. setting maxStatusChecks as a static parameter seemed like the most logical resolution for this, but let me know if you'd prefer a different approach.

Summary by CodeRabbit

  • Documentation

    • Clarified upload behavior: uploads now resolve immediately with the initial response by default; use maxStatusChecks to enable polling until processing completes and control poll limits/intervals.
  • Breaking Changes

    • Polling is opt-in via the new maxStatusChecks option; the previous statusCallback streaming option has been removed.
  • Tests

    • Tests updated to assert returned result objects and to cover the optional polling flow via maxStatusChecks.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

📝 Walkthrough

Walkthrough

Replaces callback-based upload status polling with promise-based behavior: statusCallback and CallbackError removed; post() resolves immediately by default and polls until completion only when maxStatusChecks is set. README, type defs, implementation, and tests updated accordingly.

Changes

Cohort / File(s) Summary
Documentation & README
README.md
Updated "Uploading files" to state immediate resolve by default and show optional polling via maxStatusChecks; removed examples using statusCallback.
Type Definitions
index.d.ts
Removed exported CallbackError type and removed statusCallback property from UploadRouteArgs.
Upload Implementation
lib/uploads.js
Converted callback-based polling to promise-based. post() now returns the initial response when maxStatusChecks <= 0; when maxStatusChecks > 0 it calls internal _check(args) (no callback) to poll until completion or timeout. _check signature and internals simplified; callback semantics removed; JSDoc updated.
Tests
test/uploads.js
Updated tests to await strava.uploads.post(...) and assert on returned result fields; removed status-callback mocks and added maxStatusChecks in relevant tests.

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant post as post()
    participant _check as _check()
    participant API as Upload API

    Client->>post: post(uploadData, { maxStatusChecks: N })
    post->>API: POST /uploads
    API-->>post: initial Upload response

    alt maxStatusChecks > 0
        post->>_check: _check({ uploadId, maxStatusChecks: N })
        loop Poll until done or maxChecks reached
            _check->>API: GET /uploads/:id/status
            API-->>_check: status response
            _check->>_check: evaluate status (done? / continue)
        end
        _check-->>post: final Upload or throw timeout
    end

    post-->>Client: resolve/reject promise with Upload result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through code in the moonlight's glow,
Callbacks tucked away where soft carrots grow.
Promises hum steady, polling when asked,
Return at once, or wait till the task—
Hooray for clean hops and fewer woe! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main refactoring change: removing statusCallback in favor of maxStatusChecks. The title is specific, clear, and directly reflects the primary objective of the changeset across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch deps-and-eslint

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/uploads.js`:
- Around line 19-20: The JSDoc for maxStatusChecks is ambiguous about its
default: update the comment for maxStatusChecks near the post() API to
explicitly state that the function returns immediately when maxStatusChecks is
omitted or set to 0, and only uses the 300-attempts (~5 min at 1s) behavior when
a positive number is provided (e.g., "If > 0, poll until upload is done or up to
the provided number of attempts (commonly 300 ≈ 5 min at 1s). If omitted or 0,
post() returns immediately after posting."). Mention both the immediate-return
default and the positive-number polling behavior and reference maxStatusChecks
and post() in the JSDoc so callers aren’t misled.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0db212b and a7a0eff.

📒 Files selected for processing (4)
  • README.md
  • index.d.ts
  • lib/uploads.js
  • test/uploads.js
💤 Files with no reviewable changes (1)
  • index.d.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
lib/uploads.js (1)

19-20: JSDoc for maxStatusChecks now clearly states both behaviors — past concern addressed.

The updated wording at line 19 explicitly states the immediate-return default and the positive-number polling behavior, resolving the ambiguity flagged in the prior review.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/uploads.js` around lines 19 - 20, The review comment is a duplicate
noting that the JSDoc for maxStatusChecks now clarifies behavior; no code change
required—remove the duplicated review comment or mark it "resolved" to avoid
noise in the PR; reference the JSDoc entry for maxStatusChecks (and adjacent
formData) in lib/uploads.js when confirming resolution.
🧹 Nitpick comments (3)
lib/uploads.js (1)

57-57: var self = this is unnecessary in async methods.

Both post() (line 57) and _check() (line 99) declare var self = this, but since both are async functions, this is lexically stable — no callback escapes the async context that would rebind it.

♻️ Proposed cleanup

In post():

 uploads.prototype.post = async function (args) {
-  var self = this
   // ...
-  return await self._check(checkArgs)
+  return this._check(checkArgs)
 }

In _check():

 uploads.prototype._check = async function (args) {
   var endpoint = 'uploads/' + args.id
-  var self = this
   // ...
-    if (self._uploadIsDone(response)) {
+    if (this._uploadIsDone(response)) {

Also applies to: 97-99

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/uploads.js` at line 57, Remove the redundant "var self = this"
declarations in the async methods post() and _check() and update any references
that use self to use this directly (since async functions preserve lexical
this); specifically edit the functions post() and _check() to delete the var
self = this line and replace occurrences of self.something with this.something
so behavior remains identical.
test/uploads.js (2)

71-84: Real 1-second sleep makes this test slow and potentially brittle on constrained CI.

_check in lib/uploads.js has a hardcoded await setTimeout(1000) between retries, so this test always takes ≥ 1 second. With mocha's default 2-second timeout, there's a narrow margin for CI overhead. Consider either:

  • Making the inter-poll delay injectable in _check (e.g. via args.delayMs, defaulting to 1000) so tests can pass delayMs: 0, or
  • Using fake timers (e.g. sinon.useFakeTimers) to tick through the delay without real wall-clock time.
♻️ Sketch of an injectable-delay approach in lib/uploads.js
 /**
  * `@typedef` {Object} CheckArgs
  * `@property` {string} id
  * `@property` {string | undefined} [access_token]
  * `@property` {number} [maxChecks]
+ * `@property` {number} [delayMs] - Polling interval in ms. Defaults to 1000.
  */

 // In _check():
-    await setTimeout(1000)
+    await setTimeout(args.delayMs != null ? args.delayMs : 1000)

Then in the test:

         maxStatusChecks: 2,
+        delayMs: 0
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/uploads.js` around lines 71 - 84, The test is slowed by a hardcoded 1s
sleep inside _check in lib/uploads.js; modify _check to accept an optional delay
parameter (e.g. args.delayMs) that defaults to 1000 and use that instead of the
fixed setTimeout(1000), and propagate this option through the uploads.post call
(respecting existing maxStatusChecks) so tests can call uploads.post(..., {
delayMs: 0 }) to eliminate the real sleep; alternatively, add support to
uploads.post to accept delayMs and pass it down to _check so existing callers
are unaffected.

20-85: No test coverage for the timeout path.

When maxStatusChecks is exhausted before the upload completes, _check throws 'Upload status check timed out after N attempts...'. Consider adding a test that mocks only "still processing" responses and asserts the returned promise rejects with that error.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/uploads.js` around lines 20 - 85, Add a new test for the timeout path
where strava.uploads.post exhausts maxStatusChecks and rejects: mock the initial
POST to /api/v3/uploads returning id_str and then mock the subsequent GET
/api/v3/uploads/:id to always return status "Your activity is still being
processed." for N times, call strava.uploads.post with maxStatusChecks set to N
(or lower) and assert the returned promise rejects with the exact timeout
message thrown by _check (e.g., "Upload status check timed out after N
attempts..."); reference strava.uploads.post and the internal _check timeout
behavior when creating the test so it specifically exercises the maxStatusChecks
timeout branch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@lib/uploads.js`:
- Around line 19-20: The review comment is a duplicate noting that the JSDoc for
maxStatusChecks now clarifies behavior; no code change required—remove the
duplicated review comment or mark it "resolved" to avoid noise in the PR;
reference the JSDoc entry for maxStatusChecks (and adjacent formData) in
lib/uploads.js when confirming resolution.

---

Nitpick comments:
In `@lib/uploads.js`:
- Line 57: Remove the redundant "var self = this" declarations in the async
methods post() and _check() and update any references that use self to use this
directly (since async functions preserve lexical this); specifically edit the
functions post() and _check() to delete the var self = this line and replace
occurrences of self.something with this.something so behavior remains identical.

In `@test/uploads.js`:
- Around line 71-84: The test is slowed by a hardcoded 1s sleep inside _check in
lib/uploads.js; modify _check to accept an optional delay parameter (e.g.
args.delayMs) that defaults to 1000 and use that instead of the fixed
setTimeout(1000), and propagate this option through the uploads.post call
(respecting existing maxStatusChecks) so tests can call uploads.post(..., {
delayMs: 0 }) to eliminate the real sleep; alternatively, add support to
uploads.post to accept delayMs and pass it down to _check so existing callers
are unaffected.
- Around line 20-85: Add a new test for the timeout path where
strava.uploads.post exhausts maxStatusChecks and rejects: mock the initial POST
to /api/v3/uploads returning id_str and then mock the subsequent GET
/api/v3/uploads/:id to always return status "Your activity is still being
processed." for N times, call strava.uploads.post with maxStatusChecks set to N
(or lower) and assert the returned promise rejects with the exact timeout
message thrown by _check (e.g., "Upload status check timed out after N
attempts..."); reference strava.uploads.post and the internal _check timeout
behavior when creating the test so it specifically exercises the maxStatusChecks
timeout branch.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7a0eff and f8464b3.

📒 Files selected for processing (4)
  • README.md
  • index.d.ts
  • lib/uploads.js
  • test/uploads.js
💤 Files with no reviewable changes (1)
  • index.d.ts

Copy link
Collaborator

@markstos markstos left a comment

Choose a reason for hiding this comment

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

Seems reasonable to me. I'm approving, but there was one nit I picked for possible refinements before self-merge.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
test/uploads.js (1)

87-87: Consider updating test name for clarity.

The test name "should upload a GPX file without status callback" references the removed statusCallback concept. Consider renaming to something like "should upload a GPX file without polling" or "should return immediately without maxStatusChecks" to better reflect the current API design.

✏️ Suggested rename
-    it('should upload a GPX file without status callback', async () => {
+    it('should return immediately when maxStatusChecks is not set', async () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/uploads.js` at line 87, Update the test's description string to reflect
the current API by renaming the `it` block whose title currently reads "should
upload a GPX file without status callback" to a clearer name such as "should
upload a GPX file without polling" or "should return immediately without
maxStatusChecks"; locate the `it` test case with that exact old title in the
test file and replace the string only (no behavior changes).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/uploads.js`:
- Line 87: Update the test's description string to reflect the current API by
renaming the `it` block whose title currently reads "should upload a GPX file
without status callback" to a clearer name such as "should upload a GPX file
without polling" or "should return immediately without maxStatusChecks"; locate
the `it` test case with that exact old title in the test file and replace the
string only (no behavior changes).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f8464b3 and a2de421.

📒 Files selected for processing (4)
  • README.md
  • index.d.ts
  • lib/uploads.js
  • test/uploads.js
💤 Files with no reviewable changes (1)
  • index.d.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
lib/uploads.js (1)

78-79: Consider using <= 0 for robustness.

While the past discussion concluded to use === 0 for readability, a negative value (e.g., user error) would currently proceed to _check() and make one API call before timing out. Using <= 0 would handle this edge case more gracefully by returning immediately.

♻️ Suggested change
  const maxChecks = args.maxStatusChecks != null ? args.maxStatusChecks : 0
- if (maxChecks === 0) {
+ if (maxChecks <= 0) {
    return response
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/uploads.js` around lines 78 - 79, The check for maxChecks should treat
negative or zero values the same to avoid making an unnecessary API call; change
the conditional that uses maxChecks (computed from args.maxStatusChecks) from
testing === 0 to <= 0 so the branch returns immediately instead of calling
_check(), thereby preventing a single unwanted API request when a negative value
is passed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/uploads.js`:
- Around line 78-79: The check for maxChecks should treat negative or zero
values the same to avoid making an unnecessary API call; change the conditional
that uses maxChecks (computed from args.maxStatusChecks) from testing === 0 to
<= 0 so the branch returns immediately instead of calling _check(), thereby
preventing a single unwanted API request when a negative value is passed.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2de421 and 5e5687a.

📒 Files selected for processing (4)
  • README.md
  • index.d.ts
  • lib/uploads.js
  • test/uploads.js
💤 Files with no reviewable changes (1)
  • index.d.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/uploads.js

@wesleyschlenker
Copy link
Collaborator Author

@markstos the AI overlord disagrees with you. Now, who to trust: the artificial or the organic? lol

@wesleyschlenker wesleyschlenker merged commit a399263 into main Feb 26, 2026
3 checks passed
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.

2 participants