Skip to content

Add UTS integration tests for REST and realtime#2212

Open
paddybyers wants to merge 1 commit intouts-realtimefrom
uts-integration
Open

Add UTS integration tests for REST and realtime#2212
paddybyers wants to merge 1 commit intouts-realtimefrom
uts-integration

Conversation

@paddybyers
Copy link
Copy Markdown
Member

@paddybyers paddybyers commented May 2, 2026

Summary

  • Adds 25 new integration test files covering REST and realtime against the Ably sandbox
  • REST integration tests: auth, publish, history, presence, pagination, push admin, revoke tokens, mutable messages, batch presence, time/stats
  • Realtime integration tests: auth, channels (attach/publish/subscribe/history), connection (lifecycle/failures), presence (lifecycle/sync), mutable messages (update/delete/append/annotations), delta decoding (vcdiff plugin, recovery, no-plugin failure)
  • Shared sandbox provisioning helpers for both REST and realtime suites
  • 116 integration tests total (74 REST + 42 realtime), all passing

Test plan

  • npm run test:uts -- --grep 'uts/rest/integration' --timeout 60000 — 74 passing, 2 pending
  • npm run test:uts -- --grep 'uts/realtime/integration' --timeout 60000 — 42 passing
  • Full suite npm run test:uts -- --timeout 30000 — no regressions

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Added comprehensive UTS integration test suite covering Realtime and REST client functionality, including authentication (JWT tokens, token renewal), channel operations (attach, publish, subscribe, history), presence synchronization, message operations (mutable messages, delta decoding), connections, push administration, token revocation, pagination, and utility helpers for sandbox setup and testing.

25 new test files covering REST integration (auth, publish, history,
presence, pagination, push admin, revoke tokens, mutable messages,
batch presence, time/stats) and realtime integration (auth, channels,
connection, presence, mutable messages, delta decoding).

Also updates deviations.md with integration test deviations:
RSC10 (token renewal infinite loop) and RSH1b2 (push pagination
missing Link headers).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

Walkthrough

This PR adds comprehensive UTS integration test suites for Realtime and REST client authentication, channels, connection, presence, messaging, and push admin functionality. It includes a shared sandbox infrastructure module for provisioning ephemeral test apps and establishing test clients, plus 17 test files that exercise end-to-end flows across both protocol implementations.

Changes

Integration Test Suite

Layer / File(s) Summary
Sandbox Infrastructure
test/uts/realtime/integration/sandbox.ts
Provisioning and teardown of ephemeral Ably sandbox apps via REST; manages client lifecycle; provides JWT generation, connection wait helpers, polling utilities, and key extraction.
REST Sandbox Re-export
test/uts/rest/integration/sandbox.ts
Re-exports realtime sandbox helpers for REST tests; adds getAppId() convenience function.
Realtime Auth Tests
test/uts/realtime/integration/auth/*.test.ts
JWT token auth, token renewal polling, and token request flow validation across connect/authorize lifecycle transitions.
Realtime Channel Tests
test/uts/realtime/integration/channels/*.test.ts
Channel attach/detach state transitions, history pagination, message publish round-trip (string/JSON/binary), targeted subscriptions, and extras metadata.
Realtime Connection Tests
test/uts/realtime/integration/connection/*.test.ts
Connection lifecycle (initialized → connected → closed/failed), reconnection cycles, and invalid/nonexistent key failure scenarios with error validation.
Realtime Advanced Features
test/uts/realtime/integration/delta_decoding.test.ts, test/uts/realtime/integration/mutable_messages.test.ts
Delta decoding with VCDiff plugin (success, failure recovery, dissimilar payloads); message mutations (update/delete/append) and annotations with protocol action validation.
Realtime Presence Tests
test/uts/realtime/integration/presence/*.test.ts
Presence lifecycle (enter/update/leave), bulk member delivery, and presence sync state across connections with data round-trip validation.
REST Auth Tests
test/uts/rest/integration/auth.test.ts
HTTP Basic auth, JWT token auth, native token requests, authCallback (JWT and TokenRequest), expired-JWT renewal, and capability-restricted publish enforcement.
REST Channel/History Tests
test/uts/rest/integration/history.test.ts, test/uts/rest/integration/pagination.test.ts, test/uts/rest/integration/publish.test.ts
Channel history ordering/filtering/pagination, publish serials and idempotency, and restricted-key error handling.
REST Mutable Messages & Annotations
test/uts/rest/integration/mutable_messages.test.ts
Message updates/deletions/appends with version tracking, annotation lifecycle (publish/subscribe/delete), and paginated annotation retrieval.
REST Presence Tests
test/uts/rest/integration/presence.test.ts
Presence accessibility, member retrieval with pagination/filtering, history with time-range filtering, data decoding (plain/JSON/encrypted), and auth validation.
REST Batch & Admin Tests
test/uts/rest/integration/batch_presence.test.ts, test/uts/rest/integration/push_admin.test.ts, test/uts/rest/integration/revoke_tokens.test.ts
Batch presence queries with per-channel success/failure, push device/subscription CRUD operations, and token revocation with connection disconnect verification.
REST Time & Stats
test/uts/rest/integration/time_stats.test.ts
Server time synchronization and stats pagination with parameter handling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Hopping through the tests with glee,
Auth and channels, one, two, three!
Presence dances, history flows,
Sandboxes and serials—coverage grows!
From realtime to REST, the suite's complete,
Integration tests make the protocol sweet! 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changeset: adding UTS integration tests for both REST and realtime APIs. It is clear, concise, and directly related to the primary content.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch uts-integration

Tip

💬 Introducing Slack Agent: Turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get your free trial and get 200 agent minutes per Slack user (a $50 value).


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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

Copy link
Copy Markdown

@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: 10

🧹 Nitpick comments (2)
test/uts/rest/integration/revoke_tokens.test.ts (2)

184-193: ⚡ Quick win

Avoid relying on result ordering in mixed success/failure assertions.

Index-based assertions are brittle if the API response order changes. Match entries by target (or by presence of error) before asserting.

🔍 Suggested change
-    const success = revokeResult.results[0] as any;
+    const success = revokeResult.results.find((r: any) => r.target === `clientId:${clientId}`) as any;
     expect(success.target).to.equal('clientId:' + clientId);
     expect(success.issuedBefore).to.be.a('number');
     expect(success.appliesAt).to.be.a('number');

-    const failure = revokeResult.results[1] as any;
+    const failure = revokeResult.results.find((r: any) => r.target === 'invalidType:abc') as any;
     expect(failure.target).to.equal('invalidType:abc');
     expect(failure.error).to.exist;
     expect(failure.error.statusCode).to.equal(400);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/uts/rest/integration/revoke_tokens.test.ts` around lines 184 - 193, The
test currently assumes ordering in revokeResult.results by indexing into
results[0] and results[1]; instead locate entries by their target or presence of
error (e.g., find entry where result.target === 'clientId:' + clientId and where
result.target === 'invalidType:abc' or result.error is present) and then run the
same assertions on those found objects (check success.issuedBefore/appliesAt are
numbers and failure.error.statusCode === 400) so the test no longer depends on
array order.

59-61: ⚡ Quick win

Add explicit timeout to disconnection waits to avoid long hangs.

If disconnect never arrives, these waits consume the full 60s test timeout and hide the immediate failure point. Wrap each wait with a short Promise.race timeout.

⏱️ Suggested change
-    const disconnectedPromise = new Promise<any>((resolve) => {
-      realtimeClient.connection.once('disconnected', resolve);
-    });
+    const disconnectedPromise = Promise.race([
+      new Promise<any>((resolve) => {
+        realtimeClient.connection.once('disconnected', resolve);
+      }),
+      new Promise<never>((_, reject) =>
+        setTimeout(() => reject(new Error('Timed out waiting for disconnected event')), 15000),
+      ),
+    ]);

Also applies to: 171-173

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

In `@test/uts/rest/integration/revoke_tokens.test.ts` around lines 59 - 61, The
disconnection wait uses an unbounded promise (disconnectedPromise created via
realtimeClient.connection.once('disconnected', resolve)) which can hang tests;
change the pattern to race that promise against a short timeout (e.g., 1-2s)
using Promise.race so the test fails fast if 'disconnected' never fires, and
apply the same change to the other occurrence that creates a disconnection wait
(the similar promise at the second instance around revoke flow). Ensure the
timeout path rejects or resolves with an informative error so the test surface
indicates a timeout rather than consuming the full suite timeout.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/uts/realtime/integration/sandbox.ts`:
- Around line 57-64: The deleteSandboxApp function currently ignores the DELETE
response; update it to capture the fetch Response (e.g., const res = await
fetch(...)), check res.ok (or res.status) and on non-2xx throw an Error or
reject with a message that includes the app.appId, res.status, and the response
body/text to surface why deletion failed so teardown doesn't silently leak
sandboxes.

In `@test/uts/rest/integration/auth.test.ts`:
- Line 45: The failing tests call client.request with only (method, path);
client.request requires six args including a mandatory version parameter, so
update each invocation of client.request in this test (the calls in auth.test.ts
that currently pass only method and path) to include the required version
argument (use the project constant like API_VERSION / DEFAULT_API_VERSION if
available, otherwise add the appropriate string such as 'v1'), preserving the
existing params, body and headers arguments (or pass null/undefined for
params/body/headers if they are not needed) so each call matches the signature
client.request(method, path, version, params, body, headers).

In `@test/uts/rest/integration/history.test.ts`:
- Line 49: Tests call the method channel.history() with no arguments but the
implementation signature requires params: RestHistoryParams | null; update each
test call (the ones at the noted call sites in
test/uts/rest/integration/history.test.ts) to pass an explicit null (i.e.,
channel.history(null)) so the calls match the typed signature and resolve
TS2554; look for usages of channel.history in this file (including the
occurrences around the earlier listed call sites) and change them to pass null.
- Around line 48-53: The variable history returned from pollUntil has type
HistoryResult | null; before dereferencing history.items in the assertions
(after the pollUntil call), narrow it to non-null (e.g., const nonNullHistory =
history!;) or perform a runtime null check, then use nonNullHistory.items for
the subsequent expects; update all assertions that currently use history.items
or history.items[index] (lines referencing history after pollUntil) to use the
narrowed symbol (nonNullHistory) or guarded access so TypeScript strict null
checks are satisfied.

In `@test/uts/rest/integration/mutable_messages.test.ts`:
- Around line 145-158: The callbacks passed to pollUntil return null on failure
which makes the result typed as T | null, but the tests (variables like
updatedMsg, deletedMsg, versions, annotations, result) are dereferenced without
narrowing; update each test to first guard that the pollUntil return value is
not null (e.g., if (!updatedMsg) throw or expect(updatedMsg).to.not.be.null) and
then use a non-null assertion or proceed after the check so subsequent property
accesses (name, data, action, version, description, etc.) are type-safe; apply
this same null-check-and-narrow pattern for the callbacks and usages at the
pollUntil sites (updatedMsg, deletedMsg, versions, annotations, result).

In `@test/uts/rest/integration/pagination.test.ts`:
- Around line 105-117: The test dereferences possible null results from
page1.next()/page2.next() (which return Promise<PaginatedResult<T> | null) and
pushes an optional item.id into allIds; add null checks after each await (e.g.,
assert/expect that page2 and page3 are not null or throw if null) before
accessing .items, and when iterating items add a type guard for item.id (skip or
assert when undefined) before calling allIds.push(item.id) so you never push
undefined and avoid the type error; update the same null-check pattern for the
other next() usages mentioned (page1.next(), page2.next(), page3.next()) and the
loop that inspects item.id.
- Around line 53-56: The tests call channel.history() with no arguments causing
TS2554; update every call to channel.history() (including those inside pollUntil
callbacks) to pass an explicit options object — use {} where no params are
needed (e.g., replace channel.history() with channel.history({})), ensuring the
method signature RestHistoryParams | null is satisfied; search for occurrences
in this file (e.g., the calls at lines referenced around channel.history and
inside pollUntil) and apply the same change consistently.

In `@test/uts/rest/integration/push_admin.test.ts`:
- Around line 152-167: The PushRecipient union in
src/common/lib/types/devicedetails.ts is missing APNS and GCM variants causing
TS2339 when tests access deviceToken/registrationToken; add APNSRecipient
(transportType: 'apns', deviceToken: string) and GCMRecipient (transportType:
'gcm', registrationToken: string) interfaces and include them in the
PushRecipient union (alongside WebPushRecipient and PushChannelRecipient), and
update the ably.d.ts declaration to use the new PushRecipient union instead of
any so typings reflect the added variants; update references in
functions/methods that consume PushRecipient accordingly (e.g.,
client.push.admin.deviceRegistrations types).

In `@test/uts/rest/integration/revoke_tokens.test.ts`:
- Around line 143-145: The test currently asserts
expect(result.appliesAt).to.be.greaterThan(serverTimeThirtySecondsLater) which
can be flaky on exact boundaries; change this assertion to accept equality by
using the non-strict form (e.g.,
expect(result.appliesAt).to.be.at.least(serverTimeThirtySecondsLater) or the
equivalent gte/greaterThanOrEqual form) in the revoke_tokens.test.ts test where
serverTimeThirtySecondsLater and result.appliesAt are compared.

In `@test/uts/rest/integration/time_stats.test.ts`:
- Line 66: The test calls to client.stats() must be updated to match the typed
signature requiring a RequestParams argument (Record<string,string> | null);
change the calls to pass either null or a params object with string values
(e.g., { limit: "100" }) instead of omitting the argument or passing numeric
values; update both occurrences referenced (the call at client.stats() and the
other at line ~90) so they pass valid RequestParams strings to satisfy the
types.

---

Nitpick comments:
In `@test/uts/rest/integration/revoke_tokens.test.ts`:
- Around line 184-193: The test currently assumes ordering in
revokeResult.results by indexing into results[0] and results[1]; instead locate
entries by their target or presence of error (e.g., find entry where
result.target === 'clientId:' + clientId and where result.target ===
'invalidType:abc' or result.error is present) and then run the same assertions
on those found objects (check success.issuedBefore/appliesAt are numbers and
failure.error.statusCode === 400) so the test no longer depends on array order.
- Around line 59-61: The disconnection wait uses an unbounded promise
(disconnectedPromise created via realtimeClient.connection.once('disconnected',
resolve)) which can hang tests; change the pattern to race that promise against
a short timeout (e.g., 1-2s) using Promise.race so the test fails fast if
'disconnected' never fires, and apply the same change to the other occurrence
that creates a disconnection wait (the similar promise at the second instance
around revoke flow). Ensure the timeout path rejects or resolves with an
informative error so the test surface indicates a timeout rather than consuming
the full suite timeout.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb8bcd61-47a5-46b8-815a-786bf86b4021

📥 Commits

Reviewing files that changed from the base of the PR and between 6eca0b0 and 2055b39.

📒 Files selected for processing (25)
  • test/uts/realtime/integration/auth/auth.test.ts
  • test/uts/realtime/integration/auth/token_renewal.test.ts
  • test/uts/realtime/integration/auth/token_request.test.ts
  • test/uts/realtime/integration/channels/channel_attach.test.ts
  • test/uts/realtime/integration/channels/channel_history.test.ts
  • test/uts/realtime/integration/channels/channel_publish.test.ts
  • test/uts/realtime/integration/channels/channel_subscribe.test.ts
  • test/uts/realtime/integration/connection/connection_failures.test.ts
  • test/uts/realtime/integration/connection/connection_lifecycle.test.ts
  • test/uts/realtime/integration/delta_decoding.test.ts
  • test/uts/realtime/integration/mutable_messages.test.ts
  • test/uts/realtime/integration/presence/presence_lifecycle.test.ts
  • test/uts/realtime/integration/presence/presence_sync.test.ts
  • test/uts/realtime/integration/sandbox.ts
  • test/uts/rest/integration/auth.test.ts
  • test/uts/rest/integration/batch_presence.test.ts
  • test/uts/rest/integration/history.test.ts
  • test/uts/rest/integration/mutable_messages.test.ts
  • test/uts/rest/integration/pagination.test.ts
  • test/uts/rest/integration/presence.test.ts
  • test/uts/rest/integration/publish.test.ts
  • test/uts/rest/integration/push_admin.test.ts
  • test/uts/rest/integration/revoke_tokens.test.ts
  • test/uts/rest/integration/sandbox.ts
  • test/uts/rest/integration/time_stats.test.ts

Comment on lines +57 to +64
async function deleteSandboxApp(app: SandboxApp): Promise<void> {
const url = `https://${SANDBOX_REST_HOST}/apps/${app.appId}`;
const credentials = Buffer.from(app.keys[0].keyStr).toString('base64');
await fetch(url, {
method: 'DELETE',
headers: { Authorization: `Basic ${credentials}` },
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Check DELETE response status during sandbox teardown.

deleteSandboxApp ignores non-2xx responses. That can silently leak sandbox apps and make test cleanup nondeterministic.

Proposed fix
 async function deleteSandboxApp(app: SandboxApp): Promise<void> {
   const url = `https://${SANDBOX_REST_HOST}/apps/${app.appId}`;
   const credentials = Buffer.from(app.keys[0].keyStr).toString('base64');
-  await fetch(url, {
+  const response = await fetch(url, {
     method: 'DELETE',
     headers: { Authorization: `Basic ${credentials}` },
   });
+  if (!response.ok) {
+    const body = await response.text();
+    throw new Error(`Sandbox app deletion failed (${response.status}): ${body}`);
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/uts/realtime/integration/sandbox.ts` around lines 57 - 64, The
deleteSandboxApp function currently ignores the DELETE response; update it to
capture the fetch Response (e.g., const res = await fetch(...)), check res.ok
(or res.status) and on non-2xx throw an Error or reject with a message that
includes the app.appId, res.status, and the response body/text to surface why
deletion failed so teardown doesn't silently leak sandboxes.

endpoint: SANDBOX_ENDPOINT,
});

const result = await client.request('GET', '/channels/' + channelName);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify expected Rest.request signature and affected callsites.
rg -n "request\\s*\\(" ably.d.ts -n -C3
rg -n "client\\.request\\(" test/uts/rest/integration/auth.test.ts -n -C1

Repository: ably/ably-js

Length of output: 648


🏁 Script executed:

# Find ably.d.ts and inspect Rest.request signature
fd "ably\\.d\\.ts" --type f

# Also search for request method in TypeScript definitions
rg "request\s*\(" --type ts -A 5 | head -50

Repository: ably/ably-js

Length of output: 4078


🏁 Script executed:

# Get file size and inspect specific lines in the test file
wc -l test/uts/rest/integration/auth.test.ts

# Check line 101 specifically
sed -n '99,103p' test/uts/rest/integration/auth.test.ts

Repository: ably/ably-js

Length of output: 241


🏁 Script executed:

# Read ably.d.ts to find Rest.request signature
cat ably.d.ts | grep -A 10 "class Rest\|interface Rest\|request\s*(" | head -80

Repository: ably/ably-js

Length of output: 2128


🏁 Script executed:

# Get full context around the mentioned lines in auth.test.ts
sed -n '40,50p' test/uts/rest/integration/auth.test.ts
sed -n '98,105p' test/uts/rest/integration/auth.test.ts
sed -n '128,138p' test/uts/rest/integration/auth.test.ts
sed -n '160,170p' test/uts/rest/integration/auth.test.ts
sed -n '182,192p' test/uts/rest/integration/auth.test.ts
sed -n '232,242p' test/uts/rest/integration/auth.test.ts

Repository: ably/ably-js

Length of output: 1750


🏁 Script executed:

# Search for the request method signature in Rest class
rg "request\s*\(" ably.d.ts -A 8 | grep -A 8 "request"

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Also check src/fragments/ably.d.ts
rg "request\s*\(" src/fragments/ably.d.ts -A 8 | head -60

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Search for "request" keyword in ably.d.ts files
rg "request" ably.d.ts -B 2 -A 5 | head -100

Repository: ably/ably-js

Length of output: 5748


🏁 Script executed:

# Also search in src/fragments
rg "request" src/fragments/ably.d.ts -B 2 -A 5 | head -100

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Search for method declarations in type definitions
rg "^\s+(request\s*\(|request\s*:)" ably.d.ts -A 3

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Search in fragments as well
rg "^\s+(request\s*\(|request\s*:)" src/fragments/ably.d.ts -A 3

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Look for TypeScript config and build logs
fd "tsconfig\|package.json" --type f | head -5

# Check if there are any build error files
fd "\.log$" --type f | head -10

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Try simpler pattern to find Rest class and its methods
rg "class Rest\|interface Rest" ably.d.ts -A 30 | head -100

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Get file size first
wc -l ably.d.ts src/fragments/ably.d.ts

# Search for "Rest" class/interface definition
grep -n "class Rest\|interface Rest" ably.d.ts

Repository: ably/ably-js

Length of output: 348


🏁 Script executed:

# Look for request method more broadly
grep -n "request" ably.d.ts | grep -v "^\s*\*" | head -20

Repository: ably/ably-js

Length of output: 5013


🏁 Script executed:

# Read RestClient interface to find request method signature
sed -n '1803,1900p' ably.d.ts

Repository: ably/ably-js

Length of output: 6723


🏁 Script executed:

# Read Rest class definition
sed -n '3568,3650p' ably.d.ts

Repository: ably/ably-js

Length of output: 2660


client.request calls are missing the required version parameter (build blocker).

The request method signature requires 6 parameters: method, path, version, params, body, and headers. The version parameter is mandatory (not optional). However, at lines 45, 72, 101, 132, 165, 186, and 235, request() is invoked with only 2 arguments (method and path), missing the required version parameter. This will cause TypeScript error TS2554 at compile time.

🧰 Tools
🪛 GitHub Actions: API Reference

[error] 45-45: TS2554: Expected 6 arguments, but got 2.

🪛 GitHub Actions: Bundle size report

[error] 45-45: TS2554: Expected 6 arguments, but got 2.

🪛 GitHub Actions: Lint

[error] 45-45: TS2554: Expected 6 arguments, but got 2.

🪛 GitHub Actions: Spec coverage report

[error] 45-45: TS2554: Expected 6 arguments, but got 2.

🪛 GitHub Actions: Test (react hooks)

[error] 45-45: TypeScript (TS2554): Expected 6 arguments, but got 2.

🪛 GitHub Actions: Test browser

[error] 45-235: Multiple TypeScript errors in auth tests, including TS2554 (expected 6 args but got 2; expected 2 args but got 1) at lines 45, 72, 101, 123, 132, 165, 186, 235.

🪛 GitHub Actions: Test NodeJS

[error] 45-45: TS2554: Expected 6 arguments, but got 2.

🪛 GitHub Actions: Test NPM package

[error] 45-45: TS2554: Expected 6 arguments, but got 2.

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

In `@test/uts/rest/integration/auth.test.ts` at line 45, The failing tests call
client.request with only (method, path); client.request requires six args
including a mandatory version parameter, so update each invocation of
client.request in this test (the calls in auth.test.ts that currently pass only
method and path) to include the required version argument (use the project
constant like API_VERSION / DEFAULT_API_VERSION if available, otherwise add the
appropriate string such as 'v1'), preserving the existing params, body and
headers arguments (or pass null/undefined for params/body/headers if they are
not needed) so each call matches the signature client.request(method, path,
version, params, body, headers).

Comment on lines +48 to +53
const history = await pollUntil(async () => {
const result = await channel.history();
return result.items.length === 3 ? result : null;
}, { interval: 500, timeout: 10000 });

expect(history.items).to.have.length(3);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n test/uts/rest/integration/history.test.ts | head -80

Repository: ably/ably-js

Length of output: 2829


🏁 Script executed:

rg -n "function pollUntil|const pollUntil|export.*pollUntil" test/uts/rest/integration/

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

fd -n sandbox.ts test/uts/rest/integration/

Repository: ably/ably-js

Length of output: 287


🏁 Script executed:

fd sandbox.ts test/uts/rest/integration/

Repository: ably/ably-js

Length of output: 93


🏁 Script executed:

cat -n test/uts/rest/integration/sandbox.ts

Repository: ably/ably-js

Length of output: 871


🏁 Script executed:

cat -n test/realtime/integration/sandbox.ts | grep -A 20 "pollUntil"

Repository: ably/ably-js

Length of output: 125


🏁 Script executed:

fd sandbox.ts test/realtime/

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

rg -l "function pollUntil|const pollUntil.*=" --type ts

Repository: ably/ably-js

Length of output: 97


🏁 Script executed:

cat -n test/uts/realtime/integration/sandbox.ts | grep -A 25 "pollUntil"

Repository: ably/ably-js

Length of output: 987


🏁 Script executed:

cat -n test/uts/rest/integration/history.test.ts | sed -n '48,70p'

Repository: ably/ably-js

Length of output: 1033


🏁 Script executed:

rg -n "tsconfig|strict" --type json test/uts/rest/integration/ | head -5

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

cat -n tsconfig.json | grep -A 5 "strict"

Repository: ably/ably-js

Length of output: 277


Narrow history before dereferencing to fix strict null checking error.

The pollUntil callback returns result | null, making the inferred return type Promise<HistoryResult | null>. With strict: true in tsconfig.json, TypeScript requires narrowing before accessing history.items at lines 53, 56–63, and 66.

Add a null assertion after the pollUntil call:

const history = await pollUntil(async () => {
  const result = await channel.history();
  return result.items.length === 3 ? result : null;
}, { interval: 500, timeout: 10000 });

const nonNullHistory = history!;

expect(nonNullHistory.items).to.have.length(3);
expect(nonNullHistory.items[0].name).to.equal('event3');
// ... update remaining assertions
🧰 Tools
🪛 GitHub Actions: API Reference

[error] 49-49: TS2554: Expected 1 arguments, but got 0.


[error] 53-53: TS18047: 'history' is possibly 'null'.

🪛 GitHub Actions: Bundle size report

[error] 49-49: TS2554: Expected 1 arguments, but got 0.


[error] 53-53: TS18047: 'history' is possibly 'null'.

🪛 GitHub Actions: Lint

[error] 49-49: TS2554: Expected 1 arguments, but got 0.


[error] 53-53: TS18047: 'history' is possibly 'null'.

🪛 GitHub Actions: Spec coverage report

[error] 49-49: TS2554: Expected 1 arguments, but got 0.


[error] 53-53: TS18047: 'history' is possibly 'null'.

🪛 GitHub Actions: Test (react hooks)

[error] 49-49: TypeScript (TS2554): Expected 1 arguments, but got 0.


[error] 53-53: TypeScript (TS18047): 'history' is possibly 'null'.

🪛 GitHub Actions: Test NodeJS

[error] 49-49: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test NPM package

[error] 49-49: TS2554: Expected 1 arguments, but got 0.


[error] 53-53: TS18047: 'history' is possibly 'null'.

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

In `@test/uts/rest/integration/history.test.ts` around lines 48 - 53, The variable
history returned from pollUntil has type HistoryResult | null; before
dereferencing history.items in the assertions (after the pollUntil call), narrow
it to non-null (e.g., const nonNullHistory = history!;) or perform a runtime
null check, then use nonNullHistory.items for the subsequent expects; update all
assertions that currently use history.items or history.items[index] (lines
referencing history after pollUntil) to use the narrowed symbol (nonNullHistory)
or guarded access so TypeScript strict null checks are satisfied.


// Poll until messages appear in history
const history = await pollUntil(async () => {
const result = await channel.history();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the test file exists and examine the relevant lines
fd -t f history.test.ts

Repository: ably/ably-js

Length of output: 311


🏁 Script executed:

# Read the test file to see the actual code at the specified lines
wc -l test/uts/rest/integration/history.test.ts

Repository: ably/ably-js

Length of output: 102


🏁 Script executed:

# Get the context around the specified lines
sed -n '40,60p' test/uts/rest/integration/history.test.ts
sed -n '85,105p' test/uts/rest/integration/history.test.ts
sed -n '115,135p' test/uts/rest/integration/history.test.ts
sed -n '160,180p' test/uts/rest/integration/history.test.ts
sed -n '200,220p' test/uts/rest/integration/history.test.ts

Repository: ably/ably-js

Length of output: 3270


🏁 Script executed:

# Find the channel type and history method definition
# First, let's search for imports and variable declarations
head -50 test/uts/rest/integration/history.test.ts

Repository: ably/ably-js

Length of output: 1355


🏁 Script executed:

# Search for the history method definition in the codebase
fd -t f -e ts -e js | xargs rg "history\s*\(" -B 2 -A 5 --max-count=20

Repository: ably/ably-js

Length of output: 50368


🏁 Script executed:

# Find the main source files (not test files)
fd -t f -e ts -e js 'src' | head -20

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Search for the history method definition in source code
fd -t f -e ts 'src' | xargs rg "history\s*\(" -B 3 -A 8 | head -100

Repository: ably/ably-js

Length of output: 7742


🏁 Script executed:

# Look for type definitions related to history
fd -t f -e ts -e d.ts | xargs rg "history.*\(.*\)" -B 2 -A 5 | grep -E "(history|interface|type|class)" | head -40

Repository: ably/ably-js

Length of output: 3474


🏁 Script executed:

# Look for source files in the repository structure
find . -type f -name "*.ts" -not -path "*/node_modules/*" -not -path "*/test/*" | head -30

Repository: ably/ably-js

Length of output: 1156


🏁 Script executed:

# Search for Channel class definition
rg "class.*Channel" -t ts --max-count=10

Repository: ably/ably-js

Length of output: 1181


🏁 Script executed:

# Search for the history method signature more broadly
rg "history\s*\(.*\)" -t ts --max-count=20 | grep -v test | grep -v "\.test\."

Repository: ably/ably-js

Length of output: 2451


🏁 Script executed:

# Check the actual lines in the test file
sed -n '45,55p' test/uts/rest/integration/history.test.ts
sed -n '87,97p' test/uts/rest/integration/history.test.ts
sed -n '118,128p' test/uts/rest/integration/history.test.ts
sed -n '162,172p' test/uts/rest/integration/history.test.ts
sed -n '205,215p' test/uts/rest/integration/history.test.ts

Repository: ably/ably-js

Length of output: 1913


🏁 Script executed:

# Check the RestHistoryParams type definition
rg "RestHistoryParams" -t ts -A 5 -B 2 | head -30

Repository: ably/ably-js

Length of output: 1628


Pass explicit null to history() to satisfy the typed method signature.

These call sites currently fail with TS2554 ("Expected 1 arguments, but got 0"). The implementation signature requires a parameter (params: RestHistoryParams | null) while the integration tests call channel.history() without arguments.

Proposed fix
-      const result = await channel.history();
+      const result = await channel.history(null);
@@
-      const result = await channel.history();
+      const result = await channel.history(null);
@@
-      const result = await channel.history();
+      const result = await channel.history(null);
@@
-      const result = await channel.history();
+      const result = await channel.history(null);
@@
-    const history = await channel.history();
+    const history = await channel.history(null);

Also applies to: 91-91, 122-122, 166-166, 209-209

🧰 Tools
🪛 GitHub Actions: API Reference

[error] 49-49: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Bundle size report

[error] 49-49: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Lint

[error] 49-49: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Spec coverage report

[error] 49-49: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test (react hooks)

[error] 49-49: TypeScript (TS2554): Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test browser

[error] 49-209: Multiple TypeScript errors in history tests: TS2554 (expected 1 argument but got 0) and TS18047 ('history' is possibly 'null') at lines 49, 53, 56, 57, 59, 60, 62, 63, 66, 91, 122, 166, 209.

🪛 GitHub Actions: Test NodeJS

[error] 49-49: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test NPM package

[error] 49-49: TS2554: Expected 1 arguments, but got 0.

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

In `@test/uts/rest/integration/history.test.ts` at line 49, Tests call the method
channel.history() with no arguments but the implementation signature requires
params: RestHistoryParams | null; update each test call (the ones at the noted
call sites in test/uts/rest/integration/history.test.ts) to pass an explicit
null (i.e., channel.history(null)) so the calls match the typed signature and
resolve TS2554; look for usages of channel.history in this file (including the
occurrences around the earlier listed call sites) and change them to pass null.

Comment on lines +145 to +158
const updatedMsg = await pollUntil(
async () => {
const msg = await channel.getMessage(serial);
if (msg.action === 'message.update') return msg;
return null;
},
{ interval: 500, timeout: 10000 },
);

expect(updatedMsg.name).to.equal('updated');
expect(updatedMsg.data).to.equal('updated-data');
expect(updatedMsg.action).to.equal('message.update');
expect(updatedMsg.version).to.be.an('object');
expect(updatedMsg.version!.description).to.equal('edited content');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all nullable pollUntil assignments are guarded before use.
rg -n "const (updatedMsg|deletedMsg|versions|annotations|result) = await pollUntil" test/uts/rest/integration/mutable_messages.test.ts -n -C2
rg -n "updatedMsg\\.|deletedMsg\\.|versions\\.|annotations\\.|result\\." test/uts/rest/integration/mutable_messages.test.ts -n -C1

Repository: ably/ably-js

Length of output: 3782


🏁 Script executed:

# Find the pollUntil function definition
rg -n "function pollUntil|const pollUntil|export.*pollUntil" --type ts --type tsx

Repository: ably/ably-js

Length of output: 84


🏁 Script executed:

# Check the return type and signature of pollUntil
rg -A 10 "pollUntil.*=" test/uts/rest/integration/mutable_messages.test.ts | head -20

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Search for pollUntil in test utilities
fd -name "*.ts" -o -name "*.tsx" | xargs rg -l "pollUntil" | grep -E "(setup|util|helper|common)" | head -5

Repository: ably/ably-js

Length of output: 287


🏁 Script executed:

# Search for pollUntil definition across all TypeScript files
rg "pollUntil" test/uts/ -l | head -10

Repository: ably/ably-js

Length of output: 538


🏁 Script executed:

# Look for import of pollUntil in the test file
head -50 test/uts/rest/integration/mutable_messages.test.ts | rg -n "import|pollUntil"

Repository: ably/ably-js

Length of output: 116


🏁 Script executed:

# Search for function definition of pollUntil
rg -B2 -A8 "^(export )?function pollUntil|const pollUntil = "

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Get the full import statement for pollUntil
sed -n '9,20p' test/uts/rest/integration/mutable_messages.test.ts

Repository: ably/ably-js

Length of output: 283


🏁 Script executed:

# Find pollUntil definition in sandbox.ts
rg -B2 -A10 "pollUntil" test/uts/rest/integration/sandbox.ts

Repository: ably/ably-js

Length of output: 306


🏁 Script executed:

# Find pollUntil definition in realtime sandbox
rg -B2 -A12 "^export.*function pollUntil|^function pollUntil|^export const pollUntil" test/uts/realtime/integration/sandbox.ts

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Broader search for pollUntil in the sandbox file
rg -A15 "pollUntil" test/uts/realtime/integration/sandbox.ts | head -40

Repository: ably/ably-js

Length of output: 712


🏁 Script executed:

# Check if there are type definitions or signatures
rg -B5 -A15 "pollUntil.*=" test/uts/realtime/integration/sandbox.ts

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Check for TS18047 or type errors in the codebase
rg "TS18047|error TS" --type ts

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Check if there's a TypeScript build or lint configuration
cat tsconfig.json | head -40

Repository: ably/ably-js

Length of output: 542


🏁 Script executed:

# Look for CI configuration that might report the errors
find . -maxdepth 2 -name "*.yml" -o -name "*.yaml" | head -5

Repository: ably/ably-js

Length of output: 107


🏁 Script executed:

# Check the GitHub workflow to see what TypeScript checks are run
cat .github/workflows/*.yml 2>/dev/null | grep -A10 -B5 "typescript\|tsc\|typecheck" | head -60

Repository: ably/ably-js

Length of output: 908


🏁 Script executed:

# List available workflows
ls -la .github/workflows/ 2>/dev/null

Repository: ably/ably-js

Length of output: 807


🏁 Script executed:

# Check if there are any recent build or lint configuration files
find . -maxdepth 3 -name "package.json" -exec grep -l "tsc\|typecheck" {} \;

Repository: ably/ably-js

Length of output: 1546


🏁 Script executed:

# Check the lint and test scripts in package.json
rg "\"lint\"|\"typecheck\"|\"tsc\"" package.json -A2

Repository: ably/ably-js

Length of output: 146


🏁 Script executed:

# Get the actual npm scripts section
jq '.scripts' package.json

Repository: ably/ably-js

Length of output: 2064


🏁 Script executed:

# Check if there's any TypeScript type checking for test files in the build process
rg "tsc.*test|typecheck" Gruntfile.js 2>/dev/null || echo "No matches or file not found"

Repository: ably/ably-js

Length of output: 113


🏁 Script executed:

# Look for how the test files are type-checked, if at all
cat .eslintrc* 2>/dev/null | grep -A5 -B5 "typescript\|parser" || echo "No eslint config found"

Repository: ably/ably-js

Length of output: 1374


🏁 Script executed:

# Now let's verify the actual type issue by checking what TypeScript infers for pollUntil return type
# when the callback can return T | null
cat > /tmp/test_types.ts << 'EOF'
// Simulating the pollUntil function signature
async function pollUntil<T>(
  fn: () => Promise<T> | T,
  opts?: { interval?: number; timeout?: number },
): Promise<T> {
  return null as any;
}

// Test case: callback can return string | null
async function testCase() {
  const result = await pollUntil(
    async () => {
      const x: string | null = Math.random() > 0.5 ? 'hello' : null;
      return x;
    }
  );
  
  // What type is result here?
  const x: typeof result = result;
}
EOF
cat /tmp/test_types.ts

Repository: ably/ably-js

Length of output: 546


🏁 Script executed:

# Verify the actual code to see if the callbacks in the test return T | null
sed -n '145,152p' test/uts/rest/integration/mutable_messages.test.ts

Repository: ably/ably-js

Length of output: 305


🏁 Script executed:

# Check what the Gruntfile does for typecheck
grep -B10 -A10 "typecheck" Gruntfile.js 2>/dev/null | head -40

Repository: ably/ably-js

Length of output: 796


🏁 Script executed:

# Look for CI configuration that runs typecheck on tests
find . -name "*.yml" -o -name "*.yaml" | xargs grep -l "typecheck\|tsc.*test" 2>/dev/null

Repository: ably/ably-js

Length of output: 40


🏁 Script executed:

# Check if the test files are included in the main tsconfig
rg "test/" tsconfig.json

Repository: ably/ably-js

Length of output: 199


🏁 Script executed:

# Check the actual current state of all 5 problem locations
echo "=== LINE 145-160 (updatedMsg) ==="
sed -n '145,160p' test/uts/rest/integration/mutable_messages.test.ts

echo -e "\n=== LINE 187-200 (deletedMsg) ==="
sed -n '187,200p' test/uts/rest/integration/mutable_messages.test.ts

echo -e "\n=== LINE 228-245 (versions) ==="
sed -n '228,245p' test/uts/rest/integration/mutable_messages.test.ts

Repository: ably/ably-js

Length of output: 1579


🏁 Script executed:

# Check lines 300-315 (annotations)
echo "=== LINE 300-315 (annotations) ==="
sed -n '300,315p' test/uts/rest/integration/mutable_messages.test.ts

echo -e "\n=== LINE 357-370 (result) ==="
sed -n '357,370p' test/uts/rest/integration/mutable_messages.test.ts

Repository: ably/ably-js

Length of output: 1075


🏁 Script executed:

# Run TypeScript compiler on the test file to see actual errors
cd test/uts/rest/integration && npx tsc --noEmit mutable_messages.test.ts 2>&1 | head -50 || true

Repository: ably/ably-js

Length of output: 7715


🏁 Script executed:

# Check if there's a way to run tsc on just the test files from root
npx tsc --noEmit test/uts/rest/integration/mutable_messages.test.ts 2>&1 | head -50 || true

Repository: ably/ably-js

Length of output: 7139


🏁 Script executed:

# Try checking what the actual inferred type of updatedMsg is with strict null checks
cat > /tmp/check_inference.ts << 'EOF'
interface Message {
  action: string;
  name?: string;
  data?: string;
  version?: { description?: string };
}

async function pollUntil<T>(
  fn: () => Promise<T> | T,
  opts?: { interval?: number; timeout?: number }
): Promise<T> {
  const interval = opts?.interval || 500;
  const timeout = opts?.timeout || 10000;
  const start = Date.now();
  while (true) {
    const result = await fn();
    if (result) return result;
    if (Date.now() - start > timeout) {
      throw new Error(`pollUntil timed out after ${timeout}ms`);
    }
    await new Promise((r) => setTimeout(r, interval));
  }
}

async function test() {
  // Simulating the actual code from the test file
  const updatedMsg = await pollUntil(
    async () => {
      const msg: Message = { action: 'message.update' };
      if (msg.action === 'message.update') return msg;
      return null;
    }
  );
  
  // This line should produce an error if msg could be null
  console.log(updatedMsg.name); // <-- Type error here?
}
EOF
npx tsc --strict --noEmit /tmp/check_inference.ts 2>&1 || true

Repository: ably/ably-js

Length of output: 144


🏁 Script executed:

# Verify if tests are actually type-checked in the main CI pipeline
cat .github/workflows/check.yml

Repository: ably/ably-js

Length of output: 1258


🏁 Script executed:

# Check if the test-node workflow runs type checking
cat .github/workflows/test-node.yml

Repository: ably/ably-js

Length of output: 1369


🏁 Script executed:

# Check what "npm run test:uts" actually does and if it type-checks
grep -A5 "test:uts" package.json

Repository: ably/ably-js

Length of output: 470


Nullability from pollUntil must be narrowed before dereference.

At lines 145, 187, 228, 300, and 357, the callbacks passed to pollUntil() explicitly return null on condition failure, making the return type T | null. The subsequent property dereferences without null checks will trigger TypeScript TS18047 errors.

Suggested fix pattern
 const updatedMsg = await pollUntil(
   async () => {
     const msg = await channel.getMessage(serial);
     if (msg.action === 'message.update') return msg;
     return null;
   },
   { interval: 500, timeout: 10000 },
 );
+expect(updatedMsg, 'Timed out waiting for message.update').to.not.be.null;

-expect(updatedMsg.name).to.equal('updated');
+expect(updatedMsg!.name).to.equal('updated');

Apply the same guard+non-null assertion pattern for deletedMsg, versions, annotations, and result.

Also applies to lines 187–196, 228–243, 300–312, 357–368.

🧰 Tools
🪛 GitHub Actions: API Reference

[error] 154-154: TS18047: 'updatedMsg' is possibly 'null'.


[error] 155-155: TS18047: 'updatedMsg' is possibly 'null'.


[error] 156-156: TS18047: 'updatedMsg' is possibly 'null'.


[error] 157-157: TS18047: 'updatedMsg' is possibly 'null'.


[error] 158-158: TS18047: 'updatedMsg' is possibly 'null'.

🪛 GitHub Actions: Bundle size report

[error] 154-154: TS18047: 'updatedMsg' is possibly 'null'.


[error] 155-155: TS18047: 'updatedMsg' is possibly 'null'.


[error] 156-156: TS18047: 'updatedMsg' is possibly 'null'.


[error] 157-157: TS18047: 'updatedMsg' is possibly 'null'.


[error] 158-158: TS18047: 'updatedMsg' is possibly 'null'.

🪛 GitHub Actions: Lint

[error] 154-154: TS18047: 'updatedMsg' is possibly 'null'.


[error] 155-155: TS18047: 'updatedMsg' is possibly 'null'.


[error] 156-156: TS18047: 'updatedMsg' is possibly 'null'.


[error] 157-157: TS18047: 'updatedMsg' is possibly 'null'.


[error] 158-158: TS18047: 'updatedMsg' is possibly 'null'.

🪛 GitHub Actions: Spec coverage report

[error] 154-154: TS18047: 'updatedMsg' is possibly 'null'.


[error] 155-155: TS18047: 'updatedMsg' is possibly 'null'.


[error] 156-156: TS18047: 'updatedMsg' is possibly 'null'.


[error] 157-157: TS18047: 'updatedMsg' is possibly 'null'.


[error] 158-158: TS18047: 'updatedMsg' is possibly 'null'.

🪛 GitHub Actions: Test (react hooks)

[error] 154-154: TypeScript (TS18047): 'updatedMsg' is possibly 'null'.


[error] 155-155: TypeScript (TS18047): 'updatedMsg' is possibly 'null'.


[error] 156-156: TypeScript (TS18047): 'updatedMsg' is possibly 'null'.


[error] 157-157: TypeScript (TS18047): 'updatedMsg' is possibly 'null'.


[error] 158-158: TypeScript (TS18047): 'updatedMsg' is possibly 'null'.

🪛 GitHub Actions: Test NodeJS

[error] 154-158: TS18047: 'updatedMsg' is possibly 'null'.

🪛 GitHub Actions: Test NPM package

[error] 154-154: TS18047: 'updatedMsg' is possibly 'null'.


[error] 155-155: TS18047: 'updatedMsg' is possibly 'null'.


[error] 156-156: TS18047: 'updatedMsg' is possibly 'null'.


[error] 157-157: TS18047: 'updatedMsg' is possibly 'null'.


[error] 158-158: TS18047: 'updatedMsg' is possibly 'null'.

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

In `@test/uts/rest/integration/mutable_messages.test.ts` around lines 145 - 158,
The callbacks passed to pollUntil return null on failure which makes the result
typed as T | null, but the tests (variables like updatedMsg, deletedMsg,
versions, annotations, result) are dereferenced without narrowing; update each
test to first guard that the pollUntil return value is not null (e.g., if
(!updatedMsg) throw or expect(updatedMsg).to.not.be.null) and then use a
non-null assertion or proceed after the check so subsequent property accesses
(name, data, action, version, description, etc.) are type-safe; apply this same
null-check-and-narrow pattern for the callbacks and usages at the pollUntil
sites (updatedMsg, deletedMsg, versions, annotations, result).

Comment on lines +53 to +56
await pollUntil(
async () => {
const result = await channel.history();
return result.items.length === 15 ? result : null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify zero-arg history() calls in this test file
rg -nP 'channel\.history\(\)' test/uts/rest/integration/pagination.test.ts

# Inspect history()/pagination-related signatures in client code
rg -nP '\bhistory\s*\(' src/common/lib/client -g '*.ts' -C2

Repository: ably/ably-js

Length of output: 3835


🏁 Script executed:

rg -nP 'type\s+RestHistoryParams|interface\s+RestHistoryParams' src/

Repository: ably/ably-js

Length of output: 138


🏁 Script executed:

rg -nP 'RestHistoryParams' src/common/lib/types/index.ts -A 10 | head -30

Repository: ably/ably-js

Length of output: 126


🏁 Script executed:

sed -n '12,40p' src/common/lib/client/restchannelmixin.ts

Repository: ably/ably-js

Length of output: 976


🏁 Script executed:

rg -nP 'channel\.history\(' test/uts/rest/integration/pagination.test.ts | head -20

Repository: ably/ably-js

Length of output: 605


Pass an explicit options object to channel.history(...) calls to fix TS2554 error blocking CI.

Lines 55, 98, 148, 192, and 246 call history() with zero arguments, but the method requires a parameter of type RestHistoryParams | null. Passing an empty object {} resolves the TypeScript error and aligns with the pattern used elsewhere in the test file.

Suggested patch
-        const result = await channel.history();
+        const result = await channel.history({});
@@
-        const result = await channel.history();
+        const result = await channel.history({});
@@
-        const result = await channel.history();
+        const result = await channel.history({});
@@
-        const result = await channel.history();
+        const result = await channel.history({});
@@
-        const result = await channel.history();
+        const result = await channel.history({});
🧰 Tools
🪛 GitHub Actions: API Reference

[error] 55-55: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Bundle size report

[error] 55-55: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Lint

[error] 55-55: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Spec coverage report

[error] 55-55: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test (react hooks)

[error] 55-55: TypeScript (TS2554): Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test NodeJS

[error] 55-55: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test NPM package

[error] 55-55: TS2554: Expected 1 arguments, but got 0.

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

In `@test/uts/rest/integration/pagination.test.ts` around lines 53 - 56, The tests
call channel.history() with no arguments causing TS2554; update every call to
channel.history() (including those inside pollUntil callbacks) to pass an
explicit options object — use {} where no params are needed (e.g., replace
channel.history() with channel.history({})), ensuring the method signature
RestHistoryParams | null is satisfied; search for occurrences in this file
(e.g., the calls at lines referenced around channel.history and inside
pollUntil) and apply the same change consistently.

Comment on lines +105 to +117
const page2 = await page1.next();
const page3 = await page2.next();

expect(page1.items.length).to.equal(5);
expect(page2.items.length).to.equal(5);
expect(page3.items.length).to.equal(2);

// Verify no duplicate messages across pages
const allIds: string[] = [];
for (const page of [page1, page2, page3]) {
for (const item of page.items) {
expect(allIds).to.not.include(item.id);
allIds.push(item.id);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify next() nullable contract
rg -nP 'async\s+next\(\):\s*Promise<[^>]+\|\s*null>' src/common/lib/client/paginatedresource.ts -C2

# Verify call sites that dereference next() directly in this file
rg -nP 'await\s+page\d*\.next\(\)|page\s*=\s*await\s+page\.next\(\)' test/uts/rest/integration/pagination.test.ts -C2

# Verify message id typing in declarations
rg -nP '\bid\??\s*:\s*string' ably.d.ts -C2

Repository: ably/ably-js

Length of output: 2111


🏁 Script executed:

# Find the PaginatedResource class and next() method definition
fd "paginatedresource" --type f

Repository: ably/ably-js

Length of output: 99


🏁 Script executed:

# Search for next() method in common lib
rg -n "next\(\)" src/common/lib/client/ -A 3 --type ts

Repository: ably/ably-js

Length of output: 375


🏁 Script executed:

# Get the exact type definition for the Page/PaginatedResult returned by next()
rg -n "interface.*Page|class.*Page|type.*Page" ably.d.ts -A 5

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

# Read the test file to see actual context at the problematic lines
cat -n test/uts/rest/integration/pagination.test.ts | sed -n '100,120p'

Repository: ably/ably-js

Length of output: 788


🏁 Script executed:

# Read another problematic section
cat -n test/uts/rest/integration/pagination.test.ts | sed -n '150,160p'

Repository: ably/ably-js

Length of output: 443


🏁 Script executed:

# Read the third section with the while loop
cat -n test/uts/rest/integration/pagination.test.ts | sed -n '195,215p'

Repository: ably/ably-js

Length of output: 681


🏁 Script executed:

# Find Message interface and id field definition
rg -n "interface Message" ably.d.ts -A 20

Repository: ably/ably-js

Length of output: 4666


🏁 Script executed:

# Verify the complete Message interface to confirm id is optional
rg -n "interface Message" ably.d.ts -A 50 | head -60

Repository: ably/ably-js

Length of output: 2368


Add null checks for next() calls and type guards for optional id field.

The next() method returns Promise<PaginatedResult<T> | null>, but lines 105-106 and 154-156 dereference the result without null checking. Additionally, line 117 pushes item.id (which is optional: id?: string) to the array without narrowing, causing a type error.

Suggested fix
     const page2 = await page1.next();
+    if (!page2) throw new Error('Expected page2 to exist');
     const page3 = await page2.next();
+    if (!page3) throw new Error('Expected page3 to exist');

     const allIds: string[] = [];
     for (const page of [page1, page2, page3]) {
       for (const item of page.items) {
+        if (!item.id) continue;
         expect(allIds).to.not.include(item.id);
         allIds.push(item.id);
       }
     }

Apply the same null check pattern to lines 154-156:

     const page2 = await page1.next();
+    if (!page2) throw new Error('Expected page2 to exist');
     const firstPage = await page2.first();

Also applies to: 154-156

🧰 Tools
🪛 GitHub Actions: API Reference

[error] 106-106: TS18047: 'page2' is possibly 'null'.


[error] 109-109: TS18047: 'page2' is possibly 'null'.


[error] 110-110: TS18047: 'page3' is possibly 'null'.


[error] 115-115: TS18047: 'page' is possibly 'null'.


[error] 117-117: TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.

🪛 GitHub Actions: Bundle size report

[error] 106-106: TS18047: 'page2' is possibly 'null'.


[error] 109-109: TS18047: 'page2' is possibly 'null'.


[error] 110-110: TS18047: 'page3' is possibly 'null'.


[error] 115-115: TS18047: 'page' is possibly 'null'.


[error] 117-117: TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string' (undefined not allowed).

🪛 GitHub Actions: Lint

[error] 106-106: TS18047: 'page2' is possibly 'null'.


[error] 109-109: TS18047: 'page2' is possibly 'null'.


[error] 110-110: TS18047: 'page3' is possibly 'null'.


[error] 115-115: TS18047: 'page' is possibly 'null'.


[error] 117-117: TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string' (undefined not allowed).

🪛 GitHub Actions: Spec coverage report

[error] 106-106: TS18047: 'page2' is possibly 'null'.


[error] 109-109: TS18047: 'page2' is possibly 'null'.


[error] 110-110: TS18047: 'page3' is possibly 'null'.


[error] 115-115: TS18047: 'page' is possibly 'null'.


[error] 117-117: TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.

🪛 GitHub Actions: Test (react hooks)

[error] 106-106: TypeScript (TS18047): 'page2' is possibly 'null'.


[error] 109-109: TypeScript (TS18047): 'page2' is possibly 'null'.


[error] 110-110: TypeScript (TS18047): 'page3' is possibly 'null'.


[error] 115-115: TypeScript (TS18047): 'page' is possibly 'null'.


[error] 117-117: TypeScript (TS2345): Argument of type 'string | undefined' is not assignable to parameter of type 'string'.

🪛 GitHub Actions: Test NodeJS

[error] 106-106: TS18047: 'page2' is possibly 'null'.


[error] 109-109: TS18047: 'page2' is possibly 'null'.


[error] 110-110: TS18047: 'page3' is possibly 'null'.


[error] 115-115: TS18047: 'page' is possibly 'null'.


[error] 117-117: TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.

🪛 GitHub Actions: Test NPM package

[error] 106-106: TS18047: 'page2' is possibly 'null'.


[error] 109-109: TS18047: 'page2' is possibly 'null'.


[error] 110-110: TS18047: 'page3' is possibly 'null'.


[error] 115-115: TS18047: 'page' is possibly 'null'.


[error] 117-117: TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.

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

In `@test/uts/rest/integration/pagination.test.ts` around lines 105 - 117, The
test dereferences possible null results from page1.next()/page2.next() (which
return Promise<PaginatedResult<T> | null) and pushes an optional item.id into
allIds; add null checks after each await (e.g., assert/expect that page2 and
page3 are not null or throw if null) before accessing .items, and when iterating
items add a type guard for item.id (skip or assert when undefined) before
calling allIds.push(item.id) so you never push undefined and avoid the type
error; update the same null-check pattern for the other next() usages mentioned
(page1.next(), page2.next(), page3.next()) and the loop that inspects item.id.

Comment on lines +152 to +167
const updated = await client.push.admin.deviceRegistrations.save({
id: deviceId,
platform: 'ios',
formFactor: 'phone',
push: {
recipient: { transportType: 'apns', deviceToken: 'token-v2' },
},
});

expect(updated.id).to.equal(deviceId);
expect(updated.push!.recipient!.deviceToken).to.equal('token-v2');

// Verify via get
const retrieved = await client.push.admin.deviceRegistrations.get(deviceId);
expect(retrieved.push!.recipient!.deviceToken).to.equal('token-v2');
} finally {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the failing property access sites
rg -nP 'recipient!\.deviceToken|recipient\?\.deviceToken' test/uts/rest/integration/push_admin.test.ts -C2

# Inspect push recipient type declarations
rg -nP 'type\s+PushRecipient|interface\s+.*PushRecipient|deviceToken|registrationToken|transportType' ably.d.ts -C2

Repository: ably/ably-js

Length of output: 478


🏁 Script executed:

#!/bin/bash
# Find and inspect PushRecipient type definition
rg -n 'type\s+PushRecipient|interface\s+PushRecipient' --type ts --type tsx

Repository: ably/ably-js

Length of output: 84


🏁 Script executed:

#!/bin/bash
# Look for deviceRegistrations related type definitions
rg -n 'deviceRegistrations|DeviceRegistration' --type ts --type tsx -A 5 | head -100

Repository: ably/ably-js

Length of output: 84


🏁 Script executed:

#!/bin/bash
# Check if ably.d.ts exists and inspect PushRecipient definition
find . -name "*.d.ts" -type f | head -20

Repository: ably/ably-js

Length of output: 797


🏁 Script executed:

#!/bin/bash
# Search for PushRecipient type definition
rg -n 'PushRecipient' ably.d.ts push.d.ts -A 10

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Check the test file to understand context and imports
head -30 test/uts/rest/integration/push_admin.test.ts

Repository: ably/ably-js

Length of output: 705


🏁 Script executed:

#!/bin/bash
# Look at the full test method to understand the context
sed -n '140,175p' test/uts/rest/integration/push_admin.test.ts

Repository: ably/ably-js

Length of output: 1145


🏁 Script executed:

#!/bin/bash
# Search in push.d.ts for PushRecipient
cat push.d.ts | head -200

Repository: ably/ably-js

Length of output: 1368


🏁 Script executed:

#!/bin/bash
# Search for PushRecipient in ably.d.ts more carefully
rg -n 'PushRecipient' ably.d.ts -A 15

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Look for recipient type definition in broader context
rg -n 'recipient' push.d.ts -B 2 -A 2

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Search for deviceToken in type definitions
rg -n 'deviceToken' ably.d.ts -B 5 -A 5

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Search for recipient in ably.d.ts
rg -n 'recipient' ably.d.ts -B 3 -A 3

Repository: ably/ably-js

Length of output: 862


🏁 Script executed:

#!/bin/bash
# Look for APNS or FCM related types
rg -n 'APNS|FCM|GCM' ably.d.ts -B 2 -A 5

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Search for deviceRegistrations and its type definition
rg -n 'deviceRegistrations' ably.d.ts -B 5 -A 10

Repository: ably/ably-js

Length of output: 860


🏁 Script executed:

#!/bin/bash
# Search for DeviceRegistration interface/type
rg -n 'DeviceRegistration|interface.*Registration' ably.d.ts -B 2 -A 10

Repository: ably/ably-js

Length of output: 4070


🏁 Script executed:

#!/bin/bash
# Look at the full context around line 1320
sed -n '1300,1350p' ably.d.ts

Repository: ably/ably-js

Length of output: 1296


🏁 Script executed:

#!/bin/bash
# Search for DeviceDetails interface
rg -n 'interface DeviceDetails|export.*DeviceDetails' ably.d.ts -B 2 -A 20

Repository: ably/ably-js

Length of output: 2222


🏁 Script executed:

#!/bin/bash
# Check the actual TypeScript compilation errors by looking at CI logs or tsconfig
cat tsconfig.json

Repository: ably/ably-js

Length of output: 542


🏁 Script executed:

#!/bin/bash
# Check if there's a build or test output showing the actual error
find . -name "*.log" -o -name "tsconfig*.json" | head -10

Repository: ably/ably-js

Length of output: 466


🏁 Script executed:

#!/bin/bash
# Get the full DeviceDetails interface definition
sed -n '1259,1310p' ably.d.ts

Repository: ably/ably-js

Length of output: 1483


🏁 Script executed:

#!/bin/bash
# Search specifically for push property in DeviceDetails context
rg -n 'export interface DeviceDetails' ably.d.ts -A 60 | head -70

Repository: ably/ably-js

Length of output: 2058


🏁 Script executed:

#!/bin/bash
# Confirm DevicePushDetails.recipient type one more time
sed -n '1313,1330p' ably.d.ts

Repository: ably/ably-js

Length of output: 513


🏁 Script executed:

#!/bin/bash
# Check if there have been recent changes to type definitions
git log -n 5 --oneline ably.d.ts

Repository: ably/ably-js

Length of output: 113


🏁 Script executed:

#!/bin/bash
# Try to compile the test file and see if there are actual TypeScript errors
npx tsc --noEmit test/uts/rest/integration/push_admin.test.ts 2>&1 | head -50

Repository: ably/ably-js

Length of output: 7139


🏁 Script executed:

#!/bin/bash
# Search for any PushRecipient or similar union types that might be the intended type
rg -n 'type.*Recipient|interface.*Recipient' ably.d.ts -B 2 -A 5

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Look for APNS or FCM recipient types
rg -n 'APNSRecipient|FCMRecipient|GCMRecipient' ably.d.ts -B 2 -A 5

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Search in TypeScript source files (not .d.ts) for potential type definitions
find src -name "*.ts" -type f | xargs grep -l "recipient" | head -5

Repository: ably/ably-js

Length of output: 239


🏁 Script executed:

#!/bin/bash
# Check the source file for device details type definitions
cat src/common/lib/types/devicedetails.ts

Repository: ably/ably-js

Length of output: 3880


🏁 Script executed:

#!/bin/bash
# Also check push.ts for recipient-related types
cat src/common/lib/client/push.ts | head -100

Repository: ably/ably-js

Length of output: 3426


🏁 Script executed:

#!/bin/bash
# Check if there's an APNS recipient type defined anywhere
rg -n 'apns|APNS' src/ -i

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Check the full devicedetails.ts file to see all recipient types
cat src/common/lib/types/devicedetails.ts | grep -A 20 "interface.*Recipient"

Repository: ably/ably-js

Length of output: 638


🏁 Script executed:

#!/bin/bash
# Look at the test to see what recipient type it's actually trying to use
sed -n '145,175p' test/uts/rest/integration/push_admin.test.ts

Repository: ably/ably-js

Length of output: 1009


🏁 Script executed:

#!/bin/bash
# Search for APNSRecipient or any APNS-related type definitions
find . -name "*.ts" -o -name "*.d.ts" | xargs grep -l "APNSRecipient" 2>/dev/null

Repository: ably/ably-js

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Check the git diff or recent changes to devicedetails.ts to see if APNSRecipient was removed
git log --oneline -n 20 src/common/lib/types/devicedetails.ts

Repository: ably/ably-js

Length of output: 113


🏁 Script executed:

#!/bin/bash
# Search for transportType: 'apns' in source code
rg -n "transportType.*apns|apns.*transportType" -i

Repository: ably/ably-js

Length of output: 2527


🏁 Script executed:

#!/bin/bash
# Search the commit that added the test to understand the intended APNS type
git show 2055b397 --stat | head -20

Repository: ably/ably-js

Length of output: 940


🏁 Script executed:

#!/bin/bash
# Check if APNSRecipient or similar type should exist
git show 2055b397 -- src/common/lib/types/devicedetails.ts | head -150

Repository: ably/ably-js

Length of output: 4777


🏁 Script executed:

#!/bin/bash
# Check what transportType values the test expects to work
rg -n "transportType" test/uts/rest/integration/push_admin.test.ts

Repository: ably/ably-js

Length of output: 776


🏁 Script executed:

#!/bin/bash
# Check what properties the test expects on APNS and GCM recipients
rg -n "transportType.*apns|transportType.*gcm" test/uts/rest/integration/push_admin.test.ts -A 1 -B 1 -i

Repository: ably/ably-js

Length of output: 1139


🏁 Script executed:

#!/bin/bash
# Check if there are APNS or GCM recipient types defined elsewhere
find . -name "*.ts" -o -name "*.d.ts" | xargs grep -l "APNSRecipient\|GCMRecipient\|deviceToken" 2>/dev/null | grep -v node_modules

Repository: ably/ably-js

Length of output: 206


🏁 Script executed:

#!/bin/bash
# Check the .d.ts exports to see if APNS/GCM types are exported
grep -n "APNSRecipient\|GCMRecipient\|registrationToken" ably.d.ts

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Let's verify what the union type currently includes and what properties it has
cat src/common/lib/types/devicedetails.ts | grep -A 50 "type PushRecipient"

Repository: ably/ably-js

Length of output: 1779


🏁 Script executed:

#!/bin/bash
# Check if APNSRecipient or GCMRecipient should be added to the union
grep -r "interface.*APNSRecipient\|interface.*GCMRecipient" . --include="*.ts" --include="*.d.ts" 2>/dev/null | grep -v node_modules

Repository: ably/ably-js

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Check what the spec says about recipient types by looking at the test description
head -20 test/uts/rest/integration/push_admin.test.ts

Repository: ably/ably-js

Length of output: 503


Add missing APNS and GCM recipient types to the PushRecipient union.

Lines 162 and 166 access deviceToken on a recipient that is typed as PushRecipient, a union of WebPushRecipient | PushChannelRecipient. However, the test uses APNS and GCM recipients with deviceToken and registrationToken properties respectively. These types are missing from the union definition in src/common/lib/types/devicedetails.ts, causing TS2339 errors. Add APNSRecipient and GCMRecipient interfaces with their respective properties to the union:

interface APNSRecipient {
  transportType: 'apns';
  deviceToken: string;
}

interface GCMRecipient {
  transportType: 'gcm';
  registrationToken: string;
}

type PushRecipient = WebPushRecipient | PushChannelRecipient | APNSRecipient | GCMRecipient;

Also update the ably.d.ts declaration to reflect the union type instead of any.

🧰 Tools
🪛 GitHub Actions: API Reference

[error] 162-162: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on 'WebPushRecipient').


[error] 166-166: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on 'WebPushRecipient').

🪛 GitHub Actions: Bundle size report

[error] 162-162: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on WebPushRecipient).


[error] 166-166: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on WebPushRecipient).

🪛 GitHub Actions: Lint

[error] 162-162: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on WebPushRecipient).


[error] 166-166: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on WebPushRecipient).

🪛 GitHub Actions: Spec coverage report

[error] 162-162: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on WebPushRecipient).


[error] 166-166: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on WebPushRecipient).

🪛 GitHub Actions: Test (react hooks)

[error] 162-162: TypeScript (TS2339): Property 'deviceToken' does not exist on type 'PushRecipient' (missing on WebPushRecipient).


[error] 166-166: TypeScript (TS2339): Property 'deviceToken' does not exist on type 'PushRecipient' (missing on WebPushRecipient).

🪛 GitHub Actions: Test browser

[error] 162-166: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (WebPushRecipient).

🪛 GitHub Actions: Test NodeJS

[error] 162-162: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on WebPushRecipient).


[error] 166-166: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (not on WebPushRecipient).

🪛 GitHub Actions: Test NPM package

[error] 162-162: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (missing on 'WebPushRecipient').


[error] 166-166: TS2339: Property 'deviceToken' does not exist on type 'PushRecipient' (missing on 'WebPushRecipient').

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

In `@test/uts/rest/integration/push_admin.test.ts` around lines 152 - 167, The
PushRecipient union in src/common/lib/types/devicedetails.ts is missing APNS and
GCM variants causing TS2339 when tests access deviceToken/registrationToken; add
APNSRecipient (transportType: 'apns', deviceToken: string) and GCMRecipient
(transportType: 'gcm', registrationToken: string) interfaces and include them in
the PushRecipient union (alongside WebPushRecipient and PushChannelRecipient),
and update the ably.d.ts declaration to use the new PushRecipient union instead
of any so typings reflect the added variants; update references in
functions/methods that consume PushRecipient accordingly (e.g.,
client.push.admin.deviceRegistrations types).

Comment on lines +143 to +145
const serverTimeThirtySecondsLater = serverTime + 30 * 1000;
expect(result.appliesAt).to.be.greaterThan(serverTimeThirtySecondsLater);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use non-strict boundary for appliesAt threshold to prevent flakiness.

greaterThan can fail on exact boundary values; this assertion should accept equality.

✅ Suggested change
-    expect(result.appliesAt).to.be.greaterThan(serverTimeThirtySecondsLater);
+    expect(result.appliesAt).to.be.at.least(serverTimeThirtySecondsLater);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/uts/rest/integration/revoke_tokens.test.ts` around lines 143 - 145, The
test currently asserts
expect(result.appliesAt).to.be.greaterThan(serverTimeThirtySecondsLater) which
can be flaky on exact boundaries; change this assertion to accept equality by
using the non-strict form (e.g.,
expect(result.appliesAt).to.be.at.least(serverTimeThirtySecondsLater) or the
equivalent gte/greaterThanOrEqual form) in the revoke_tokens.test.ts test where
serverTimeThirtySecondsLater and result.appliesAt are compared.

endpoint: SANDBOX_ENDPOINT,
});

const result = await client.stats();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "time_stats.test.ts" -type f

Repository: ably/ably-js

Length of output: 103


🏁 Script executed:

cat -n ./test/uts/rest/integration/time_stats.test.ts | head -100

Repository: ably/ably-js

Length of output: 3482


🏁 Script executed:

find . -name "*.ts" -not -path "./node_modules/*" -type f | xargs rg -l "stats.*:" | head -20

Repository: ably/ably-js

Length of output: 233


🏁 Script executed:

rg "stats\s*\(" ./src/common/lib/client/rest.ts -A 5 -B 2

Repository: ably/ably-js

Length of output: 431


🏁 Script executed:

rg "interface RequestParams|type RequestParams" -A 10

Repository: ably/ably-js

Length of output: 682


Align stats calls with the typed API signature (current code does not compile).

Line 66 and Line 90 cause TS2554/TS2322 errors in CI. The stats method requires a params argument of type RequestParams (which is Record<string, string> | null), and all values including limit must be strings, not numbers.

Proposed fix
-    const result = await client.stats();
+    const result = await client.stats({});
@@
-      limit: 5,
+      limit: '5',
       direction: 'forwards',
       unit: 'hour',
🧰 Tools
🪛 GitHub Actions: API Reference

[error] 66-66: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Bundle size report

[error] 66-66: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Lint

[error] 66-66: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Spec coverage report

[error] 66-66: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test (react hooks)

[error] 66-66: TypeScript (TS2554): Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test browser

[error] 66-90: Multiple TypeScript errors: TS2554 (expected 1 argument but got 0) at line 66; TS2322 (number not assignable to string) at line 90.

🪛 GitHub Actions: Test NodeJS

[error] 66-66: TS2554: Expected 1 arguments, but got 0.

🪛 GitHub Actions: Test NPM package

[error] 66-66: TS2554: Expected 1 arguments, but got 0.

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

In `@test/uts/rest/integration/time_stats.test.ts` at line 66, The test calls to
client.stats() must be updated to match the typed signature requiring a
RequestParams argument (Record<string,string> | null); change the calls to pass
either null or a params object with string values (e.g., { limit: "100" })
instead of omitting the argument or passing numeric values; update both
occurrences referenced (the call at client.stats() and the other at line ~90) so
they pass valid RequestParams strings to satisfy the types.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant