diff --git a/examples/spaces-avatar-stack/javascript/.env.example b/examples/spaces-avatar-stack/javascript/.env.example
new file mode 100644
index 0000000000..acd79e16f2
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/.env.example
@@ -0,0 +1 @@
+VITE_PUBLIC_ABLY_KEY=
\ No newline at end of file
diff --git a/examples/spaces-avatar-stack/javascript/.gitignore b/examples/spaces-avatar-stack/javascript/.gitignore
new file mode 100644
index 0000000000..fd3dbb571a
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/.gitignore
@@ -0,0 +1,36 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+.yarn/install-state.gz
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env*.local
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/examples/spaces-avatar-stack/javascript/README.md b/examples/spaces-avatar-stack/javascript/README.md
new file mode 100644
index 0000000000..d7bdc4b91b
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/README.md
@@ -0,0 +1,39 @@
+# Display active users avatars in an application
+
+This folder contains the code for the avatar stack (Typescript) - a demo of how you can leverage [Ably Spaces](https://github.com/ably/spaces) to show a list of currently online users.
+
+## Getting started
+
+1. Clone the [Ably docs](https://github.com/ably/docs) repository where this example can be found:
+
+```sh
+git clone git@github.com:ably/docs.git
+```
+
+2. Change directory:
+
+```sh
+cd /examples/spaces-avatar-stack/javascript/
+```
+
+3. Rename the environment file:
+
+```sh
+mv .env.example .env.local
+```
+
+4. In `.env.local` update the value of `VITE_PUBLIC_ABLY_KEY` to be your Ably API key.
+
+5. Install dependencies:
+
+```sh
+yarn install
+```
+
+6. Run the server:
+
+```sh
+yarn run dev
+```
+
+7. Try it out by opening two tabs to [http://localhost:5173/](http://localhost:5173/) with your browser to see the result.
diff --git a/examples/spaces-avatar-stack/javascript/index.html b/examples/spaces-avatar-stack/javascript/index.html
new file mode 100644
index 0000000000..b2d1136eee
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+ Avatar stack
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/spaces-avatar-stack/javascript/package.json b/examples/spaces-avatar-stack/javascript/package.json
new file mode 100644
index 0000000000..218fca5151
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "js-avatar-stack",
+ "version": "1.0.0",
+ "main": "index.js",
+ "license": "MIT",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "dotenv": "^16.4.5",
+ "typescript": "^5.5.4",
+ "@faker-js/faker": "^9.2.0"
+ },
+ "dependencies": {
+ "@ably/spaces": "^0.4.0",
+ "ably": "^2.3.1",
+ "nanoid": "^5.0.7",
+ "vite": "^5.4.2"
+ }
+}
diff --git a/examples/spaces-avatar-stack/javascript/src/script.ts b/examples/spaces-avatar-stack/javascript/src/script.ts
new file mode 100644
index 0000000000..61684c506b
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/src/script.ts
@@ -0,0 +1,162 @@
+import Spaces, { type SpaceMember } from '@ably/spaces';
+import { Realtime } from 'ably';
+import { nanoid } from 'nanoid';
+import { faker } from '@faker-js/faker';
+
+export type Member = Omit & {
+ profileData: { memberColor: string; name: string };
+};
+
+connect();
+
+async function connect() {
+ const client = new Realtime({
+ clientId: nanoid(),
+ key: import.meta.env.VITE_PUBLIC_ABLY_KEY as string,
+ });
+
+ const spaces = new Spaces(client);
+ const space = await spaces.get('avatar-stack');
+
+ /** 💡 Add every avatar that enters 💡 */
+ space.members.subscribe(['leave', 'remove'], (memberUpdate: SpaceMember) => {
+ const avatar = document.querySelector(`[data-member-id="${memberUpdate.clientId}"]`);
+ if (avatar) {
+ avatar.remove();
+ }
+ });
+ space.members.subscribe('enter', (memberUpdate: SpaceMember) => {
+ const member: Member = {
+ ...memberUpdate,
+ profileData: {
+ memberColor: (memberUpdate.profileData as any).memberColor,
+ name: (memberUpdate.profileData as any).name,
+ },
+ };
+ renderAvatar(member, true);
+ });
+
+ /** 💡 Enter the space as soon as it's available 💡 */
+ space
+ .enter({
+ name: faker.person.firstName() + ' ' + faker.person.lastName(),
+ memberColor: faker.color.rgb({ format: 'hex', casing: 'lower' }),
+ })
+ .then(async () => {
+ const otherMembers = await space.members.getOthers();
+
+ /** 💡 Get first four except the local member in the space 💡 */
+ otherMembers.slice(0, 4).forEach((member) => {
+ renderAvatar(member as Member);
+ });
+
+ /** 💡 Get a count of the number exceeding four and display as a single tally 💡 */
+ renderExceedingCounter(otherMembers);
+ })
+ .catch((err) => {
+ console.error('Error joining space:', err);
+ });
+}
+
+function buildUserInfo(member: Member, isSelf: boolean = false): HTMLDivElement {
+ const wrapper = document.createElement('div');
+ wrapper.className = 'wrapper';
+
+ const userInfoContainer = document.createElement('div');
+ userInfoContainer.className = 'userInfoContainer';
+ userInfoContainer.style.backgroundColor = member.profileData.memberColor;
+ userInfoContainer.id = 'avatar';
+
+ const userInitials = member.profileData.name
+ .split(' ')
+ .map((word: string) => word.charAt(0))
+ .join('');
+
+ const initials = document.createElement('p');
+ initials.className = 'smallText';
+ initials.textContent = userInitials;
+
+ userInfoContainer.appendChild(initials);
+ wrapper.appendChild(userInfoContainer);
+
+ const userList = document.createElement('div');
+ userList.className = 'userList';
+ userList.id = 'user-list';
+
+ const nameElement = document.createElement('p');
+ nameElement.className = 'name';
+ nameElement.textContent = isSelf ? member.profileData.name + ' (You)' : member.profileData.name;
+
+ userList.appendChild(nameElement);
+ wrapper.appendChild(userList);
+
+ return wrapper;
+}
+
+async function renderAvatar(member: Member, isSelf: boolean = false): Promise {
+ console.log(member);
+ const userInitials = member.profileData.name
+ .split(' ')
+ .map((word: string) => word.charAt(0))
+ .join('');
+
+ const avatarsElement = document.getElementById('avatars');
+ if (avatarsElement) {
+ const avatarElement = document.createElement('div');
+ avatarElement.className = isSelf ? 'selfAvatar' : 'otherAvatar';
+
+ const avatarContainer = document.createElement('div');
+ avatarContainer.className = 'avatarContainer';
+
+ const avatar = document.createElement('div');
+ avatar.className = 'avatar';
+ avatar.style.backgroundColor = member.profileData.memberColor;
+ avatar.setAttribute('data-member-id', member['clientId']);
+ avatar.setAttribute('key', member['clientId']);
+
+ const initials = document.createElement('p');
+ initials.className = 'textWhite';
+ initials.textContent = userInitials;
+
+ avatar.appendChild(initials);
+
+ const popup = document.createElement('div');
+ popup.className = 'popup';
+ popup.style.display = 'none';
+
+ const userInfo = buildUserInfo(member, isSelf);
+ avatarElement.appendChild(avatarContainer);
+ avatarContainer.appendChild(avatar);
+ popup.appendChild(userInfo);
+ avatar.appendChild(popup);
+
+ avatarsElement.appendChild(avatarElement);
+
+ avatar.addEventListener('mouseover', () => {
+ popup.style.display = 'block';
+ });
+
+ avatar.addEventListener('mouseleave', () => {
+ popup.style.display = 'none';
+ });
+ }
+}
+
+function renderExceedingCounter(otherMembers: SpaceMember[]) {
+ if (otherMembers.length > 4) {
+ const avatarsElement = document.getElementById('avatars');
+
+ if (avatarsElement) {
+ const avatarElement = document.createElement('div');
+ avatarElement.className = 'avatar';
+ avatarElement.style.backgroundColor = '#595959';
+
+ const nameElement = document.createElement('p');
+ nameElement.className = 'textWhite nameOthers';
+ nameElement.textContent = `+${otherMembers.length - 4}`;
+
+ avatarElement.appendChild(nameElement);
+ avatarsElement.appendChild(avatarElement);
+ }
+ }
+}
diff --git a/examples/spaces-avatar-stack/javascript/src/styles.css b/examples/spaces-avatar-stack/javascript/src/styles.css
new file mode 100644
index 0000000000..2fc5cbe060
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/src/styles.css
@@ -0,0 +1,84 @@
+.avatarStackContainer {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ background-color: #f4f8fb;
+ height: 100vh;
+}
+
+.avatars {
+ display: inline-flex;
+}
+
+.avatarContainer {
+ position: relative;
+}
+
+.avatar {
+ background-color: rgb(234, 88, 12);
+ height: 3rem;
+ width: 3rem;
+ border-radius: 9999px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 2px solid #e2e7ef;
+ flex-shrink: 0;
+ position: relative;
+ margin-left: -7px;
+}
+
+.name {
+ font-size: 0.75rem;
+ line-height: 1rem;
+ color: rgb(255, 255, 255);
+}
+
+.textWhite {
+ color: #fff;
+}
+
+.nameOthers {
+ z-index: 20;
+ font-size: 0.75rem;
+}
+
+.popup {
+ position: absolute;
+ left: -5rem;
+ top: -4.8rem;
+ padding: 1rem;
+ background-color: #000;
+ border-radius: 8px;
+ color: #fff;
+ min-width: 240px;
+}
+
+.wrapper {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+}
+
+.userList {
+ padding-left: 0.75rem;
+ width: 100%;
+}
+
+.userInfoContainer {
+ height: 2rem;
+ width: 2rem;
+ border-radius: 9999px;
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ border: 2px solid #cbd5e0;
+}
+
+.smallText {
+ font-size: 0.75rem;
+}
diff --git a/examples/spaces-avatar-stack/javascript/tsconfig.json b/examples/spaces-avatar-stack/javascript/tsconfig.json
new file mode 100644
index 0000000000..cfcaf10637
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/tsconfig.json
@@ -0,0 +1,35 @@
+{
+ "compilerOptions": {
+ "lib": [
+ "es2021",
+ "DOM",
+ "DOM.Iterable",
+ ],
+ "module": "ESNext",
+ "target": "ESNext",
+ "strict": true,
+ "esModuleInterop": true,
+ "moduleResolution": "Node",
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowUnusedLabels": false,
+ "allowUnreachableCode": false,
+ "exactOptionalPropertyTypes": true,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitOverride": true,
+ "noImplicitReturns": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noUncheckedIndexedAccess": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "checkJs": true,
+ // Everything below are custom changes for this app
+ "allowJs": true,
+ "outDir": "dist"
+ },
+ "include": [
+ "./src/**/*",
+ "./__tests__/**/*",
+ "vite-env.d.ts"
+ ]
+}
\ No newline at end of file
diff --git a/examples/spaces-avatar-stack/javascript/vite-env.d.ts b/examples/spaces-avatar-stack/javascript/vite-env.d.ts
new file mode 100644
index 0000000000..9454b92dea
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/vite-env.d.ts
@@ -0,0 +1,8 @@
+interface ImportMetaEnv {
+ readonly VITE_PUBLIC_ABLY_KEY: string;
+ // Add other environment variables here if needed
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
diff --git a/examples/spaces-avatar-stack/javascript/yarn.lock b/examples/spaces-avatar-stack/javascript/yarn.lock
new file mode 100644
index 0000000000..24c36ebd89
--- /dev/null
+++ b/examples/spaces-avatar-stack/javascript/yarn.lock
@@ -0,0 +1,583 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@ably/msgpack-js@^0.4.0":
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/@ably/msgpack-js/-/msgpack-js-0.4.0.tgz#aaaf5d8dffacf7aa253effd8c3488aa09130e6a2"
+ integrity sha512-IPt/BoiQwCWubqoNik1aw/6M/DleMdrxJOUpSja6xmMRbT2p1TA8oqKWgfZabqzrq8emRNeSl/+4XABPNnW5pQ==
+ dependencies:
+ bops "^1.0.1"
+
+"@ably/spaces@^0.4.0":
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/@ably/spaces/-/spaces-0.4.0.tgz#766d748d79f3de3cd82939431daea99479150bbf"
+ integrity sha512-yehNgkv9DOHUBR1c46/5Q4BhkF3TJkKb00kLDhZFWTVJpFSW0Mkw0PUgHLkzAg9Bt9LJPcA0mgZq3mFeLQCrIg==
+ dependencies:
+ nanoid "^3.3.7"
+
+"@esbuild/aix-ppc64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f"
+ integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==
+
+"@esbuild/android-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052"
+ integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==
+
+"@esbuild/android-arm@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28"
+ integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==
+
+"@esbuild/android-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e"
+ integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==
+
+"@esbuild/darwin-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a"
+ integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==
+
+"@esbuild/darwin-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22"
+ integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==
+
+"@esbuild/freebsd-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e"
+ integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==
+
+"@esbuild/freebsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261"
+ integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==
+
+"@esbuild/linux-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b"
+ integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==
+
+"@esbuild/linux-arm@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9"
+ integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==
+
+"@esbuild/linux-ia32@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2"
+ integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==
+
+"@esbuild/linux-loong64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df"
+ integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==
+
+"@esbuild/linux-mips64el@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe"
+ integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==
+
+"@esbuild/linux-ppc64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4"
+ integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==
+
+"@esbuild/linux-riscv64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc"
+ integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==
+
+"@esbuild/linux-s390x@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de"
+ integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==
+
+"@esbuild/linux-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0"
+ integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==
+
+"@esbuild/netbsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047"
+ integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==
+
+"@esbuild/openbsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70"
+ integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==
+
+"@esbuild/sunos-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b"
+ integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==
+
+"@esbuild/win32-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d"
+ integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==
+
+"@esbuild/win32-ia32@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b"
+ integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==
+
+"@esbuild/win32-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c"
+ integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==
+
+"@faker-js/faker@^9.2.0":
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-9.2.0.tgz#269ee3a5d2442e88e10d984e106028422bcb9551"
+ integrity sha512-ulqQu4KMr1/sTFIYvqSdegHT8NIkt66tFAkugGnHA+1WAfEn6hMzNR+svjXGFRVLnapxvej67Z/LwchFrnLBUg==
+
+"@rollup/rollup-android-arm-eabi@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.1.tgz#c3a7938551273a2b72820cf5d22e54cf41dc206e"
+ integrity sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==
+
+"@rollup/rollup-android-arm64@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.1.tgz#fa3693e4674027702c42fcbbb86bbd0c635fd3b9"
+ integrity sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==
+
+"@rollup/rollup-darwin-arm64@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.1.tgz#e19922f4ac1e4552a230ff8f49d5688c5c07d284"
+ integrity sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==
+
+"@rollup/rollup-darwin-x64@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.1.tgz#897f8d47b115ea84692a29cf2366899499d4d915"
+ integrity sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.1.tgz#7d1e2a542f3a5744f5c24320067bd5af99ec9d62"
+ integrity sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==
+
+"@rollup/rollup-linux-arm-musleabihf@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.1.tgz#88bec1c9df85fc5e24d49f783e19934717dd69b5"
+ integrity sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==
+
+"@rollup/rollup-linux-arm64-gnu@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.1.tgz#6dc60f0fe7bd49ed07a2d4d9eab15e671b3bd59d"
+ integrity sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==
+
+"@rollup/rollup-linux-arm64-musl@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.1.tgz#a03b78775c129e8333aca9e1e420e8e217ee99b9"
+ integrity sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==
+
+"@rollup/rollup-linux-powerpc64le-gnu@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.1.tgz#ee3810647faf2c105a5a4e71260bb90b96bf87bc"
+ integrity sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==
+
+"@rollup/rollup-linux-riscv64-gnu@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.1.tgz#385d76a088c27db8054d9f3f28d64d89294f838e"
+ integrity sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==
+
+"@rollup/rollup-linux-s390x-gnu@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.1.tgz#daa2b62a6e6f737ebef6700a12a93c9764e18583"
+ integrity sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==
+
+"@rollup/rollup-linux-x64-gnu@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.1.tgz#790ae96118cc892464e9f10da358c0c8a6b9acdd"
+ integrity sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==
+
+"@rollup/rollup-linux-x64-musl@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.1.tgz#d613147f7ac15fafe2a0b6249e8484e161ca2847"
+ integrity sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==
+
+"@rollup/rollup-win32-arm64-msvc@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.1.tgz#18349db8250559a5460d59eb3575f9781be4ab98"
+ integrity sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==
+
+"@rollup/rollup-win32-ia32-msvc@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.1.tgz#199648b68271f7ab9d023f5c077725d51d12d466"
+ integrity sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==
+
+"@rollup/rollup-win32-x64-msvc@4.21.1":
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.1.tgz#4d3ec02dbf280c20bfeac7e50cd5669b66f9108f"
+ integrity sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==
+
+"@sindresorhus/is@^4.0.0":
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
+ integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==
+
+"@szmarczak/http-timer@^4.0.5":
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
+ integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==
+ dependencies:
+ defer-to-connect "^2.0.0"
+
+"@types/cacheable-request@^6.0.1":
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
+ integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==
+ dependencies:
+ "@types/http-cache-semantics" "*"
+ "@types/keyv" "^3.1.4"
+ "@types/node" "*"
+ "@types/responselike" "^1.0.0"
+
+"@types/estree@1.0.5":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
+ integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
+
+"@types/http-cache-semantics@*":
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
+ integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==
+
+"@types/keyv@^3.1.4":
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
+ integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==
+ dependencies:
+ "@types/node" "*"
+
+"@types/node@*":
+ version "22.5.0"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.0.tgz#10f01fe9465166b4cab72e75f60d8b99d019f958"
+ integrity sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==
+ dependencies:
+ undici-types "~6.19.2"
+
+"@types/responselike@^1.0.0":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50"
+ integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==
+ dependencies:
+ "@types/node" "*"
+
+ably@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/ably/-/ably-2.3.1.tgz#c3b02df6aa4262284b0b1ba130e5f85e0f423ef4"
+ integrity sha512-OQ9PUwQe0qehOUPqvLargmUTlPQsxCAdStIpLZE7pT68yDd3JF28R1Ap7C50DluCIa6NqXrieRSa2tcLNN95PA==
+ dependencies:
+ "@ably/msgpack-js" "^0.4.0"
+ fastestsmallesttextencoderdecoder "^1.0.22"
+ got "^11.8.5"
+ ulid "^2.3.0"
+ ws "^8.17.1"
+
+base64-js@1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.2.tgz#474211c95e6cf2a547db461e4f6778b51d08fa65"
+ integrity sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg==
+
+bops@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/bops/-/bops-1.0.1.tgz#502aaf00ee119db1dbae088e3df4bea2e241dbcc"
+ integrity sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag==
+ dependencies:
+ base64-js "1.0.2"
+ to-utf8 "0.0.1"
+
+cacheable-lookup@^5.0.3:
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
+ integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
+
+cacheable-request@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817"
+ integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==
+ dependencies:
+ clone-response "^1.0.2"
+ get-stream "^5.1.0"
+ http-cache-semantics "^4.0.0"
+ keyv "^4.0.0"
+ lowercase-keys "^2.0.0"
+ normalize-url "^6.0.1"
+ responselike "^2.0.0"
+
+clone-response@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3"
+ integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==
+ dependencies:
+ mimic-response "^1.0.0"
+
+decompress-response@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
+ integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
+ dependencies:
+ mimic-response "^3.1.0"
+
+defer-to-connect@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
+ integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
+
+dotenv@^16.4.5:
+ version "16.4.5"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
+ integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
+
+end-of-stream@^1.1.0:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+ integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+ dependencies:
+ once "^1.4.0"
+
+esbuild@^0.21.3:
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d"
+ integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==
+ optionalDependencies:
+ "@esbuild/aix-ppc64" "0.21.5"
+ "@esbuild/android-arm" "0.21.5"
+ "@esbuild/android-arm64" "0.21.5"
+ "@esbuild/android-x64" "0.21.5"
+ "@esbuild/darwin-arm64" "0.21.5"
+ "@esbuild/darwin-x64" "0.21.5"
+ "@esbuild/freebsd-arm64" "0.21.5"
+ "@esbuild/freebsd-x64" "0.21.5"
+ "@esbuild/linux-arm" "0.21.5"
+ "@esbuild/linux-arm64" "0.21.5"
+ "@esbuild/linux-ia32" "0.21.5"
+ "@esbuild/linux-loong64" "0.21.5"
+ "@esbuild/linux-mips64el" "0.21.5"
+ "@esbuild/linux-ppc64" "0.21.5"
+ "@esbuild/linux-riscv64" "0.21.5"
+ "@esbuild/linux-s390x" "0.21.5"
+ "@esbuild/linux-x64" "0.21.5"
+ "@esbuild/netbsd-x64" "0.21.5"
+ "@esbuild/openbsd-x64" "0.21.5"
+ "@esbuild/sunos-x64" "0.21.5"
+ "@esbuild/win32-arm64" "0.21.5"
+ "@esbuild/win32-ia32" "0.21.5"
+ "@esbuild/win32-x64" "0.21.5"
+
+fastestsmallesttextencoderdecoder@^1.0.22:
+ version "1.0.22"
+ resolved "https://registry.yarnpkg.com/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz#59b47e7b965f45258629cc6c127bf783281c5e93"
+ integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==
+
+fsevents@~2.3.2, fsevents@~2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+get-stream@^5.1.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+ integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
+ dependencies:
+ pump "^3.0.0"
+
+got@^11.8.5:
+ version "11.8.6"
+ resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
+ integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==
+ dependencies:
+ "@sindresorhus/is" "^4.0.0"
+ "@szmarczak/http-timer" "^4.0.5"
+ "@types/cacheable-request" "^6.0.1"
+ "@types/responselike" "^1.0.0"
+ cacheable-lookup "^5.0.3"
+ cacheable-request "^7.0.2"
+ decompress-response "^6.0.0"
+ http2-wrapper "^1.0.0-beta.5.2"
+ lowercase-keys "^2.0.0"
+ p-cancelable "^2.0.0"
+ responselike "^2.0.0"
+
+http-cache-semantics@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
+ integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
+
+http2-wrapper@^1.0.0-beta.5.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
+ integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
+ dependencies:
+ quick-lru "^5.1.1"
+ resolve-alpn "^1.0.0"
+
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
+keyv@^4.0.0:
+ version "4.5.4"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
+ integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
+ dependencies:
+ json-buffer "3.0.1"
+
+lowercase-keys@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
+ integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
+
+mimic-response@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
+ integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+
+mimic-response@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
+ integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
+
+nanoid@^3.3.7:
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+ integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
+
+nanoid@^5.0.7:
+ version "5.0.7"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.7.tgz#6452e8c5a816861fd9d2b898399f7e5fd6944cc6"
+ integrity sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==
+
+normalize-url@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
+ integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
+
+once@^1.3.1, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+p-cancelable@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
+ integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
+
+picocolors@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
+ integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
+
+postcss@^8.4.41:
+ version "8.4.41"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681"
+ integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==
+ dependencies:
+ nanoid "^3.3.7"
+ picocolors "^1.0.1"
+ source-map-js "^1.2.0"
+
+pump@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+quick-lru@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
+ integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
+
+resolve-alpn@^1.0.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
+ integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==
+
+responselike@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
+ integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==
+ dependencies:
+ lowercase-keys "^2.0.0"
+
+rollup@^4.20.0:
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.1.tgz#65b9b9e9de9a64604fab083fb127f3e9eac2935d"
+ integrity sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==
+ dependencies:
+ "@types/estree" "1.0.5"
+ optionalDependencies:
+ "@rollup/rollup-android-arm-eabi" "4.21.1"
+ "@rollup/rollup-android-arm64" "4.21.1"
+ "@rollup/rollup-darwin-arm64" "4.21.1"
+ "@rollup/rollup-darwin-x64" "4.21.1"
+ "@rollup/rollup-linux-arm-gnueabihf" "4.21.1"
+ "@rollup/rollup-linux-arm-musleabihf" "4.21.1"
+ "@rollup/rollup-linux-arm64-gnu" "4.21.1"
+ "@rollup/rollup-linux-arm64-musl" "4.21.1"
+ "@rollup/rollup-linux-powerpc64le-gnu" "4.21.1"
+ "@rollup/rollup-linux-riscv64-gnu" "4.21.1"
+ "@rollup/rollup-linux-s390x-gnu" "4.21.1"
+ "@rollup/rollup-linux-x64-gnu" "4.21.1"
+ "@rollup/rollup-linux-x64-musl" "4.21.1"
+ "@rollup/rollup-win32-arm64-msvc" "4.21.1"
+ "@rollup/rollup-win32-ia32-msvc" "4.21.1"
+ "@rollup/rollup-win32-x64-msvc" "4.21.1"
+ fsevents "~2.3.2"
+
+source-map-js@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
+ integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
+
+to-utf8@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852"
+ integrity sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ==
+
+typescript@^5.5.4:
+ version "5.5.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba"
+ integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==
+
+ulid@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f"
+ integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==
+
+undici-types@~6.19.2:
+ version "6.19.8"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02"
+ integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
+
+vite@^5.4.2:
+ version "5.4.2"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.2.tgz#8acb6ec4bfab823cdfc1cb2d6c53ed311bc4e47e"
+ integrity sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==
+ dependencies:
+ esbuild "^0.21.3"
+ postcss "^8.4.41"
+ rollup "^4.20.0"
+ optionalDependencies:
+ fsevents "~2.3.3"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+ws@^8.17.1:
+ version "8.18.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc"
+ integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
diff --git a/examples/spaces-avatar-stack/page.md b/examples/spaces-avatar-stack/page.md
new file mode 100644
index 0000000000..cba91d0cdb
--- /dev/null
+++ b/examples/spaces-avatar-stack/page.md
@@ -0,0 +1,121 @@
+# Display active users avatars in an application.
+
+Display the online status of users by displaying an avatar for each of them.
+
+Display the status of users within an application with an avatar stack to provide a visual rendering of which users are in the shared workspace.
+
+Avatar stacks are utilized in applications such as online whiteboards, slide shows, spreadsheets and documents to let others know who is currently active in the application.
+
+Avatar stack are implemented using [Ably Spaces](https://ably.com/docs/products/spaces). The Spaces SDK contains a set of purpose-built APIs that abstract away the complexities involved in managing the state of participants in a collaborative application. It is built on top of Ably's core platform, and so it provides the same performance and scaling guarantees.
+
+## Resources
+
+// React brief (Only visible if viewing the React example)
+
+Use the following components to add avatar stack into an application:
+
+* [`SpacesProvider`](https://ably.com/docs/spaces/react#spaces-provider): initializes and manages a shared space client instance, passing it down through React context to enable realtime spaces functionality across the application.
+* [`SpaceProvider`](https://ably.com/docs/spaces/react#spaces-provider): manages the state and functionality of a specific space, providing access to realtime interactions within that space via React context.
+* [`useSpace()`](https://ably.com/docs/spaces/react#useSpace) hook: a hook to subscribe to the current Space, receive Space state events, and get the current Space instance.
+* [`useMembers()`](https://ably.com/docs/spaces/react#useMembers) hook: a hook to build avatar stacks. It retrieves members of the space, including members that have left the space, but have not yet been removed.
+
+Find out more about [avatar stack](https://ably.com/docs/spaces/avatar).
+
+// End React brief
+
+// Javascript brief (Only visible if viewing the Javascript example)
+
+Use the following methods to add avatar stack into an application:
+
+* [`spaces.get()`](https://ably.com/docs/spaces/space#create) - creates a new or retrieves an existing `space`.
+* [`space.member.subscribe()`](https://ably.com/docs/spaces/avatar#subscribe) - subscribes to members' online status and profile updates by registering a listener.
+* [`space.enter()`](https://ably.com/docs/spaces/space#enter) - Entering a space will register a client as a member and emit an `enter` event to all subscribers.
+* [`space.members.getSelf()` and `space.members.getOthers()`](https://ably.com/docs/spaces/avatar#retrieve) - Retrieve list of users currently active in the Space or have recently left but not yet been removed.
+
+Find out more about [avatar stack](https://ably.com/docs/spaces/avatar).
+
+// End Javascript brief
+
+## View on Github
+
+// React
+
+1. Clone the [Ably docs](https://github.com/ably/docs) repository where this example can be found:
+
+```sh
+git clone git@github.com:ably/docs.git
+```
+
+2. Change directory:
+
+```sh
+cd /examples/spaces-avatar-stack/react/
+```
+
+3. Rename the environment file:
+
+```sh
+mv .env.example .env.local
+```
+
+4. In `.env.local` update the value of `NEXT_PUBLIC_ABLY_KEY` to be your Ably API key.
+
+5. Install dependencies:
+
+```sh
+yarn install
+```
+
+6. Run the server:
+
+```sh
+yarn run dev
+```
+
+7. Try it out by opening two tabs to [http://localhost:3000/](http://localhost:3000/) with your browser to see the result.
+
+// Javascript
+
+1. Clone the [Ably docs](https://github.com/ably/docs) repository where this example can be found:
+
+```sh
+git clone git@github.com:ably/docs.git
+```
+
+2. Change directory:
+
+```sh
+cd /examples/spaces-avatar-stack/javascript/
+```
+
+3. Rename the environment file:
+
+```sh
+mv .env.example .env.local
+```
+
+4. In `.env.local` update the value of `VITE_PUBLIC_API_KEY` to be your Ably API key.
+
+5. Install depdencies:
+
+```sh
+yarn install
+```
+
+6. Run the server:
+
+```sh
+yarn run dev
+```
+
+7. Try it out by opening two tabs to [http://localhost:5173/](http://localhost:5173/) with your browser to see the result.
+
+## Open in CodeSandbox
+
+// React
+
+In CodeSandbox, rename the `.env.example` file to `.env.local` and update the value of your `NEXT_PUBLIC_ABLY_KEY` variable to use your Ably API key.
+
+// Javascript
+
+In CodeSandbox, rename the `.env.example` file to `.env.local` and update the value of your `VITE_PUBLIC_ABLY_KEY` variable to use your Ably API key.
diff --git a/examples/spaces-avatar-stack/react/.env.example b/examples/spaces-avatar-stack/react/.env.example
new file mode 100644
index 0000000000..711655dfe8
--- /dev/null
+++ b/examples/spaces-avatar-stack/react/.env.example
@@ -0,0 +1 @@
+NEXT_PUBLIC_ABLY_KEY=
\ No newline at end of file
diff --git a/examples/spaces-avatar-stack/react/.eslintrc.json b/examples/spaces-avatar-stack/react/.eslintrc.json
new file mode 100644
index 0000000000..bffb357a71
--- /dev/null
+++ b/examples/spaces-avatar-stack/react/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "next/core-web-vitals"
+}
diff --git a/examples/spaces-avatar-stack/react/.gitignore b/examples/spaces-avatar-stack/react/.gitignore
new file mode 100644
index 0000000000..0cb8fedfd5
--- /dev/null
+++ b/examples/spaces-avatar-stack/react/.gitignore
@@ -0,0 +1,38 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+.yarn/install-state.gz
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env*.local
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
+
+.env.local
diff --git a/examples/spaces-avatar-stack/react/README.md b/examples/spaces-avatar-stack/react/README.md
new file mode 100644
index 0000000000..17bf3c4819
--- /dev/null
+++ b/examples/spaces-avatar-stack/react/README.md
@@ -0,0 +1,39 @@
+# Display active users avatars in an application
+
+This folder contains the code for the avatar stack (React) - a demo of how you can leverage [Ably Spaces](https://github.com/ably/spaces) to show a list of currently online users.
+
+## Getting started
+
+1. Clone the [Ably docs](https://github.com/ably/docs) repository where this example can be found:
+
+```sh
+git clone git@github.com:ably/docs.git
+```
+
+2. Change directory:
+
+```sh
+cd /examples/spaces-avatar-stack/react/
+```
+
+3. Rename the environment file:
+
+```sh
+mv .env.example .env.local
+```
+
+4. In `.env.local` update the value of `NEXT_PUBLIC_ABLY_KEY` to be your Ably API key.
+
+5. Install dependencies:
+
+```sh
+yarn install
+```
+
+6. Run the server:
+
+```sh
+yarn run dev
+```
+
+7. Try it out by opening two tabs to [http://localhost:3000/](http://localhost:3000/) with your browser to see the result.
diff --git a/examples/spaces-avatar-stack/react/next.config.mjs b/examples/spaces-avatar-stack/react/next.config.mjs
new file mode 100644
index 0000000000..4678774e6d
--- /dev/null
+++ b/examples/spaces-avatar-stack/react/next.config.mjs
@@ -0,0 +1,4 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {};
+
+export default nextConfig;
diff --git a/examples/spaces-avatar-stack/react/package.json b/examples/spaces-avatar-stack/react/package.json
new file mode 100644
index 0000000000..87148795f8
--- /dev/null
+++ b/examples/spaces-avatar-stack/react/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "react-avatar-stack",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint"
+ },
+ "dependencies": {
+ "@ably/spaces": "^0.4.0",
+ "ably": "^2.3.1",
+ "react": "^18",
+ "react-dom": "^18",
+ "next": "14.2.5"
+ },
+ "devDependencies": {
+ "typescript": "^5",
+ "@types/node": "^20",
+ "@types/react": "^18",
+ "@types/react-dom": "^18",
+ "eslint": "^8",
+ "eslint-config-next": "14.2.5",
+ "@faker-js/faker": "^9.2.0"
+ }
+}
diff --git a/examples/spaces-avatar-stack/react/src/app/layout.tsx b/examples/spaces-avatar-stack/react/src/app/layout.tsx
new file mode 100644
index 0000000000..ca695942b1
--- /dev/null
+++ b/examples/spaces-avatar-stack/react/src/app/layout.tsx
@@ -0,0 +1,28 @@
+"use client";
+
+import { Inter } from "next/font/google";
+import Spaces from "@ably/spaces";
+import { SpaceProvider, SpacesProvider } from "@ably/spaces/react";
+import { Realtime } from 'ably';
+import "../../styles/styles.css";
+
+const inter = Inter({ subsets: ["latin"] });
+
+const client = new Realtime({key: process.env.NEXT_PUBLIC_ABLY_KEY, clientId: "clientId"});
+const spaces = new Spaces(client);
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/examples/spaces-avatar-stack/react/src/app/page.tsx b/examples/spaces-avatar-stack/react/src/app/page.tsx
new file mode 100644
index 0000000000..f20f733ac2
--- /dev/null
+++ b/examples/spaces-avatar-stack/react/src/app/page.tsx
@@ -0,0 +1,65 @@
+"use client";
+
+import { useEffect } from "react";
+import { useMembers, useSpace } from "@ably/spaces/react";
+import { type SpaceMember } from "@ably/spaces";
+import { Avatar } from "../components/Avatar";
+import { faker } from '@faker-js/faker';
+import "../../styles/styles.css";
+
+export type Member = Omit & {
+ profileData: { memberColor: string; name: string };
+};
+
+export default function Home() {
+ /** 💡 Get a handle on a space instance 💡 */
+ const { space } = useSpace();
+
+ /** 💡 Enter the space as soon as it's available 💡 */
+ useEffect(() => {
+ space?.enter({
+ name: faker.person.firstName() + ' ' + faker.person.lastName(),
+ memberColor: faker.color.rgb({ format: 'hex', casing: 'lower' }),
+ });
+
+ return () => {
+ space?.leave();
+ };
+ }, [space]);
+
+ /** 💡 Get everybody in the space including the local member 💡 */
+ const { others, self } = useMembers();
+ const hasMoreUsers = others.length > 3;
+
+ return (
+
+
+ {/** 💡 Add your avatar to the stack.💡 */}
+ {self && (
+
+
+
+ )}
+
+ {/** 💡 Stack of first 4 user avatars excluding yourself.💡 */}
+ {others.slice(0, 4).map(( other ) => {
+ return (
+