Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 12 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,24 @@ module.exports = {
},
},
{
files: ['ably.d.ts', 'modular.d.ts'],
files: ['packages/core/ably.d.ts', 'packages/core/modular.d.ts'],
extends: ['plugin:jsdoc/recommended'],
rules: {
'jsdoc/check-tag-names': ['warn', { definedTags: ['experimental'] }],
},
},
],
ignorePatterns: ['build', 'test', 'tools', 'scripts', 'typedoc/generated', 'react', 'Gruntfile.js', 'grunt'],
ignorePatterns: [
'build',
'packages/*/dist',
'test',
'tools',
'scripts',
'typedoc/generated',
'/packages/core/react',
'Gruntfile.js',
'grunt',
],
settings: {
jsdoc: {
tagNamePreference: {
Expand Down
33 changes: 28 additions & 5 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,44 @@ jobs:
- run: npm ci
- run: npm run lint
- run: npm run format:check
- run: npx tsc --noEmit ably.d.ts modular.d.ts
- run: npx tsc --noEmit packages/core/ably.d.ts packages/core/modular.d.ts
# Redundant today: `npm ci` above runs `prepare`, which builds `webpack:all`, and its
# ts-loader already typechecks this same tsconfig program - so a type error fails that
# step first. Kept explicit so the guarantee does not rest on that incidental side
# effect: adding `transpileOnly` or dropping the webpack bundles would silently remove
# it, and nothing would tell us.
- run: npx tsc --noEmit -p packages/core/tsconfig.json
# The core's program no longer covers scripts/; the root tsconfig is what does.
- run: npx tsc --noEmit -p tsconfig.json
# The error-code union is generated from the ably-common submodule at its pinned
# commit; fail if the committed copy has drifted from the registry.
- run: npm run generate:errorcodes-ts
- run: git diff --exit-code -- src/common/lib/types/errorcodes.ts
- run: git diff --exit-code -- packages/core/src/common/lib/types/errorcodes.ts
# The three packages release in lockstep; fail if any version site has drifted (the
# workspace package.json files, the wrappers' exact core peer pins, or the react-hooks
# agent constant). scripts/release.js is the authority on the site list.
- run: npm run check:versions
# Type-checks the wrapper packages' sources and their hand-written declaration files
# together, against the core resolved through the tsconfig's `paths`. The React hooks'
# declaration files are generated rather than hand-written, so the `/react` subpath can only
# be checked against them once they exist — and checking against the generated types is the
# right thing to do anyway, since they are what a consumer resolves.
- run: npm run build:react
- run: npm run check:packages
# Every package is built explicitly rather than relying on the root `npm ci` above having
# run `prepare`, so that packing does not depend on a side effect of an earlier step. None
# of the packages has a `prepare` of its own to build it.
- run: npm run build
# for some reason, this doesn't work in CI using `npx attw --pack .`
- run: npm pack
- run: npx attw ably-$(node -e "console.log(require('./package.json').version)").tgz --summary --exclude-entrypoints 'ably/modular'
- run: npm pack ./packages/core ./packages/device ./packages/server
- run: npx attw ably-pubsub-core-$(node -e "console.log(require('./packages/core/package.json').version)").tgz --summary --exclude-entrypoints '@ably/pubsub-core/modular'
# see https://github.com/ably/ably-js/issues/1546 for why we ignore 'false-cjs' currently.
# should remove when switched to auto-generated type declaration files for modular variant of the library.
- run: npx attw ably-$(node -e "console.log(require('./package.json').version)").tgz --summary --entrypoints 'ably/modular' --ignore-rules false-cjs
- run: npx attw ably-pubsub-core-$(node -e "console.log(require('./packages/core/package.json').version)").tgz --summary --entrypoints '@ably/pubsub-core/modular' --ignore-rules false-cjs
# `@ably/pubsub-device/modular` is deliberately ESM-only, mirroring the core's modular
# variant, so `require()` of it is expected not to resolve. Checked separately with that one
# rule ignored, rather than left unchecked.
- run: npx attw ably-pubsub-device-$(node -e "console.log(require('./packages/device/package.json').version)").tgz --summary --exclude-entrypoints '@ably/pubsub-device/modular'
- run: npx attw ably-pubsub-device-$(node -e "console.log(require('./packages/device/package.json').version)").tgz --summary --entrypoints '@ably/pubsub-device/modular' --ignore-rules no-resolution
- run: npx attw ably-pubsub-server-$(node -e "console.log(require('./packages/server/package.json').version)").tgz --summary
- run: npm audit --production
8 changes: 8 additions & 0 deletions .github/workflows/test-node-uts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ jobs:
matrix:
# tsx (used to run the TypeScript UTS suite) requires Node >= 18, so 16.x is excluded.
node-version: [18.x, 20.x]
# Which package's entry points the suite constructs clients through (see the UTS_SIDE
# handling in packages/core/test/uts/helpers.ts): the core constructors, or the
# side-declaring factories of @ably/pubsub-device / @ably/pubsub-server. The factories
# stamp an agent entry and pass everything else through, so conformance must be
# identical on every leg; side_modes.test.ts fails a leg whose stamp does not match.
side: [core, device, server]
timeout-minutes: 15
steps:
- uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2
Expand All @@ -36,7 +42,9 @@ jobs:
run: npm run test:uts:unit
env:
CI: true
UTS_SIDE: ${{ matrix.side }}
- name: Run UTS integration tests
run: npm run test:uts:integration
env:
CI: true
UTS_SIDE: ${{ matrix.side }}
12 changes: 9 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ ably-pubsub-js.iml
node_modules
npm-debug.log
.tool-versions
liveobjects.d.mts
packages/core/liveobjects.d.mts
build/
react/
packages/*/dist/
*.tgz
/packages/core/react/
typedoc/generated/
junit/
private-api-usage/
private-api-usage-reports/
test/support/mocha_junit_reporter/build/
packages/core/test/support/mocha_junit_reporter/build/
.claude
# Generated from the sibling index.d.ts by `grunt build:packages:types`.
packages/*/index.d.mts
packages/*/*/index.d.mts
packages/*/*/*/index.d.mts
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "spec/common/ably-common"]
path = test/common/ably-common
path = packages/core/test/common/ably-common
url = https://github.com/ably/ably-common.git
16 changes: 12 additions & 4 deletions .mocharc.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
// The core's test suite lives in packages/core, but mocha runs from this monorepo root so that
// one node_modules and one set of dev dependencies serve every package.
const core = 'packages/core';

const config = {
require: ['source-map-support/register', 'test/support/modules_helper.js', 'test/support/test_helper.js'],
file: ['test/support/root_hooks.js'],
reporter: 'test/support/mocha_reporter.js',
require: [
'source-map-support/register',
`${core}/test/support/modules_helper.js`,
`${core}/test/support/test_helper.js`,
],
file: [`${core}/test/support/root_hooks.js`],
reporter: `${core}/test/support/mocha_reporter.js`,
};

// mocha has a ridiculous issue (https://github.com/mochajs/mocha/issues/4100) that command line
// specs don't override config specs; they are merged instead, so you can't run a single test file
// if you've defined specs in your config. therefore we work around it by only adding specs to the
// config if none are passed as arguments
if (!process.argv.slice(2).some(isTestFile)) {
config.spec = ['test/realtime/*.test.js', 'test/rest/*.test.js', 'test/unit/*.test.js'];
config.spec = [`${core}/test/realtime/*.test.js`, `${core}/test/rest/*.test.js`, `${core}/test/unit/*.test.js`];
}

function isTestFile(arg) {
Expand Down
4 changes: 2 additions & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
test/common/ably-common/
packages/core/test/common/ably-common/

# Generated by `npm run generate:errorcodes-ts`; the generator is the only thing that
# should change it, and CI diffs it against the registry.
src/common/lib/types/errorcodes.ts
packages/core/src/common/lib/types/errorcodes.ts
19 changes: 13 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,25 @@ Guidance for coding agents (and humans) working in this repository.

## Repository Overview

ably-js is the Ably realtime and REST client library for JavaScript/TypeScript, targeting browsers, Node.js, and React Native. The public API surface is defined in [ably.d.ts](./ably.d.ts). Source lives in `src/` (`common/` for shared client logic, `platform/` for platform-specific code and React hooks).
ably-js is a monorepo. The published packages live under `packages/`:

- `packages/core` — the Ably realtime and REST client library for JavaScript/TypeScript, published as `@ably/pubsub-core`, targeting browsers, Node.js and React Native. Its public API surface is defined in [ably.d.ts](./packages/core/ably.d.ts), and its source lives in `packages/core/src/` (`common/` for shared client logic, `platform/` for platform-specific code and React hooks).
- `packages/device` and `packages/server` — thin per-side wrappers over the core, published as `@ably/pubsub-device` and `@ably/pubsub-server`. See [Per-side packages](./CONTRIBUTING.md#per-side-packages).
- `packages/shared` — private helpers bundled into the two wrappers rather than published.

All three published packages are npm workspaces, so `node_modules/@ably/pubsub-core` is a symlink to `packages/core`. The build tooling (Gruntfile, `grunt/`, `webpack.config.js`, `scripts/`) and every dev dependency live at the repo root and serve all packages, so run every command below from there.

## Commands

```bash
npm run build # Full build (webpack; slow). Platform-specific: build:node, build:browser, ...
npm test # Build + run the Mocha test suite
npm run test:node -- test/realtime/auth.test.js # Run one test file
npm run test:node -- packages/core/test/realtime/auth.test.js # Run one test file
npm run test:node -- --grep=test_name_here # Run tests matching a pattern
npm run lint # ESLint (lint:fix to autofix)
npm run format # Prettier write (format:check to verify)
npm run docs # Generate TypeDoc from ably.d.ts
npm run docs # Generate TypeDoc from packages/core/ably.d.ts
npm run check:packages # Typecheck the per-side wrapper packages against the core
```

See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full test-suite, debugging, and release documentation.
Expand All @@ -24,7 +31,7 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full test-suite, debugging, and

### Error codes

`ErrorInfo.code` is typed as `ErrorCode`, a union of every code registered in [ably-common](https://github.com/ably/ably-common/tree/main/errors/codes). It is generated into [errorcodes.ts](./src/common/lib/types/errorcodes.ts) from the pinned `ably-common` submodule and committed. CI regenerates it at that pin and fails on a diff, so never hand-edit it.
`ErrorInfo.code` is typed as `ErrorCode`, a union of every code registered in [ably-common](https://github.com/ably/ably-common/tree/main/errors/codes). It is generated into [errorcodes.ts](./packages/core/src/common/lib/types/errorcodes.ts) from the pinned `ably-common` submodule and committed. CI regenerates it at that pin and fails on a diff, so never hand-edit it.

Pick the registered code whose `identifier` matches the failure, and pair it with the HTTP status that code's registry entry documents. `statusCode` is a plain `number`, so a wrong status still compiles — check it against the registry rather than copying a neighbouring call.

Expand All @@ -37,14 +44,14 @@ error TS2345: Argument of type '40199' is not assignable to parameter of type 'E
That means the code is not registered. Do not cast around it. Instead:

1. Add the code under `errors/codes/` in [ably-common](https://github.com/ably/ably-common) and get that merged.
2. Bump the `test/common/ably-common` submodule pin here to a commit that contains it.
2. Bump the `packages/core/test/common/ably-common` submodule pin here to a commit that contains it.
3. Run `npm run generate:errorcodes-ts` and commit the regenerated `errorcodes.ts`.

Errors decoded from the server are exempt: the server chose the code and may use one this client version does not know about, so build those with `ErrorInfo.fromWireValues` instead of `ErrorInfo.fromValues`.

### Error messages and remediations

Errors constructed by the SDK (`ErrorInfo` / `PartialErrorInfo`) carry a `message` and, in most cases, a `remediation` (see the `ErrorInfo.remediation` docstring in [ably.d.ts](./ably.d.ts)). The two fields have distinct jobs:
Errors constructed by the SDK (`ErrorInfo` / `PartialErrorInfo`) carry a `message` and, in most cases, a `remediation` (see the `ErrorInfo.remediation` docstring in [ably.d.ts](./packages/core/ably.d.ts)). The two fields have distinct jobs:

- `message` says **what went wrong**: the failure and the condition that triggered it, written declaratively.
- `remediation` says **how to fix it**: the first thing the developer (or coding agent) reading the error should do, written imperatively. It must be actionable without further lookup.
Expand Down
Loading
Loading