diff --git a/callbacks.d.ts b/callbacks.d.ts new file mode 100644 index 0000000000..0f11b3297d --- /dev/null +++ b/callbacks.d.ts @@ -0,0 +1,10 @@ +/** + * @deprecated `'ably/callbacks'` was the v1 callback API entry point and has been removed in ably-js v2. + * v2 is promise-only — import from `'ably'` directly and switch to `await` / `.then()`. + * + * Importing this subpath throws at module load with the migration link. + * + * @see https://github.com/ably/ably-js/blob/main/docs/migration-guides/v2/lib.md + */ +declare const ablyCallbacksV1EntryPointRemoved: never; +export = ablyCallbacksV1EntryPointRemoved; diff --git a/callbacks.js b/callbacks.js new file mode 100644 index 0000000000..db806f6077 --- /dev/null +++ b/callbacks.js @@ -0,0 +1,6 @@ +'use strict'; + +const err = new Error("'ably/callbacks' was the v1 callback API entry point and is no longer available."); +err.hint = + "ably-js v2 is promise-only — import from 'ably' directly and switch to await / .then(). See https://github.com/ably/ably-js/blob/main/docs/migration-guides/v2/lib.md"; +throw err; diff --git a/package.json b/package.json index 85781a3802..459a81bf7e 100644 --- a/package.json +++ b/package.json @@ -39,14 +39,26 @@ "types": "./liveobjects.d.ts", "default": "./build/liveobjects.js" } + }, + "./promises": { + "types": "./promises.d.ts", + "default": "./promises.js" + }, + "./callbacks": { + "types": "./callbacks.d.ts", + "default": "./callbacks.js" } }, "files": [ "build/**", "ably.d.ts", + "callbacks.d.ts", + "callbacks.js", "liveobjects.d.ts", "liveobjects.d.mts", "modular.d.ts", + "promises.d.ts", + "promises.js", "push.d.ts", "resources/**", "src/**", diff --git a/promises.d.ts b/promises.d.ts new file mode 100644 index 0000000000..fc242ebcba --- /dev/null +++ b/promises.d.ts @@ -0,0 +1,10 @@ +/** + * @deprecated `'ably/promises'` was the v1 entry point and is no longer available in ably-js v2. + * v2 is promise-only — import from `'ably'` directly. + * + * Importing this subpath throws at module load with the migration link. + * + * @see https://github.com/ably/ably-js/blob/main/docs/migration-guides/v2/lib.md + */ +declare const ablyPromisesV1EntryPointRemoved: never; +export = ablyPromisesV1EntryPointRemoved; diff --git a/promises.js b/promises.js new file mode 100644 index 0000000000..1139c364f3 --- /dev/null +++ b/promises.js @@ -0,0 +1,6 @@ +'use strict'; + +const err = new Error("'ably/promises' was the v1 entry point and is no longer available."); +err.hint = + "ably-js v2 is promise-only — import from 'ably' directly. See https://github.com/ably/ably-js/blob/main/docs/migration-guides/v2/lib.md"; +throw err; diff --git a/test/unit/legacy-import-shims.test.js b/test/unit/legacy-import-shims.test.js new file mode 100644 index 0000000000..501e251308 --- /dev/null +++ b/test/unit/legacy-import-shims.test.js @@ -0,0 +1,68 @@ +'use strict'; + +define(['chai'], function (chai) { + const { expect } = chai; + const fs = require('fs'); + const path = require('path'); + const repoRoot = path.resolve(__dirname, '..', '..'); + + describe('legacy v1 import-path shims', function () { + function loadShim(relPath) { + const abs = path.join(repoRoot, relPath); + delete require.cache[abs]; + require(abs); + } + + it("'ably/promises' shim throws naming the v1 entry point, with a hint pointing at the migration guide", function () { + let caught; + try { + loadShim('promises.js'); + } catch (err) { + caught = err; + } + expect(caught).to.be.an.instanceOf(Error); + expect(caught.message).to.match(/'ably\/promises' was the v1 entry point/); + expect(caught.hint).to.be.a('string'); + expect(caught.hint).to.match(/promise-only/); + expect(caught.hint).to.match(/migration-guides\/v2\/lib\.md/); + }); + + it("'ably/callbacks' shim throws naming the v1 callback API, with a hint pointing at the migration guide", function () { + let caught; + try { + loadShim('callbacks.js'); + } catch (err) { + caught = err; + } + expect(caught).to.be.an.instanceOf(Error); + expect(caught.message).to.match(/'ably\/callbacks' was the v1 callback API entry point/); + expect(caught.hint).to.be.a('string'); + expect(caught.hint).to.match(/await/); + expect(caught.hint).to.match(/migration-guides\/v2\/lib\.md/); + }); + + it('package.json exports map wires the legacy subpaths to the shim files and their types', function () { + const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8')); + + expect(pkg.exports['./promises'], "exports['./promises']").to.deep.equal({ + types: './promises.d.ts', + default: './promises.js', + }); + expect(pkg.exports['./callbacks'], "exports['./callbacks']").to.deep.equal({ + types: './callbacks.d.ts', + default: './callbacks.js', + }); + + for (const file of ['promises.js', 'promises.d.ts', 'callbacks.js', 'callbacks.d.ts']) { + expect(fs.existsSync(path.join(repoRoot, file)), file).to.equal(true); + } + }); + + it("'files' array ships the legacy shim files in the published package", function () { + const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8')); + for (const file of ['promises.js', 'promises.d.ts', 'callbacks.js', 'callbacks.d.ts']) { + expect(pkg.files, `files[] should include ${file}`).to.include(file); + } + }); + }); +});