+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/browser/package-lock.json b/examples/browser/package-lock.json
new file mode 100644
index 00000000..5d4064c6
--- /dev/null
+++ b/examples/browser/package-lock.json
@@ -0,0 +1,78 @@
+{
+ "name": "realtime-browser-example",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "realtime-browser-example",
+ "version": "1.0.0",
+ "devDependencies": {
+ "@playwright/test": "^1.42.1"
+ }
+ },
+ "node_modules/@playwright/test": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz",
+ "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright": "1.52.0"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/playwright": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz",
+ "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright-core": "1.52.0"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz",
+ "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ }
+ }
+}
diff --git a/examples/browser/package.json b/examples/browser/package.json
new file mode 100644
index 00000000..dcd43bbd
--- /dev/null
+++ b/examples/browser/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "realtime-browser-example",
+ "version": "1.0.0",
+ "description": "Browser example for Supabase Realtime",
+ "scripts": {
+ "test": "playwright test",
+ "test:ui": "playwright test --ui"
+ },
+ "devDependencies": {
+ "@playwright/test": "^1.42.1"
+ }
+}
\ No newline at end of file
diff --git a/examples/browser/playwright.config.js b/examples/browser/playwright.config.js
new file mode 100644
index 00000000..84cf7adf
--- /dev/null
+++ b/examples/browser/playwright.config.js
@@ -0,0 +1,18 @@
+import { defineConfig } from '@playwright/test'
+
+export default defineConfig({
+ testDir: './tests',
+ timeout: 30000,
+ expect: {
+ timeout: 10000
+ },
+ use: {
+ baseURL: 'http://localhost:8000',
+ trace: 'on-first-retry',
+ },
+ webServer: {
+ command: 'python -m http.server 8000',
+ url: 'http://localhost:8000',
+ reuseExistingServer: !process.env.CI,
+ },
+})
\ No newline at end of file
diff --git a/examples/browser/pnpm-lock.yaml b/examples/browser/pnpm-lock.yaml
new file mode 100644
index 00000000..89fb08b0
--- /dev/null
+++ b/examples/browser/pnpm-lock.yaml
@@ -0,0 +1,52 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ devDependencies:
+ '@playwright/test':
+ specifier: ^1.42.1
+ version: 1.52.0
+
+packages:
+
+ '@playwright/test@1.52.0':
+ resolution: {integrity: sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ playwright-core@1.52.0:
+ resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ playwright@1.52.0:
+ resolution: {integrity: sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+snapshots:
+
+ '@playwright/test@1.52.0':
+ dependencies:
+ playwright: 1.52.0
+
+ fsevents@2.3.2:
+ optional: true
+
+ playwright-core@1.52.0: {}
+
+ playwright@1.52.0:
+ dependencies:
+ playwright-core: 1.52.0
+ optionalDependencies:
+ fsevents: 2.3.2
diff --git a/examples/browser/supabase/.gitignore b/examples/browser/supabase/.gitignore
new file mode 100644
index 00000000..ad9264f0
--- /dev/null
+++ b/examples/browser/supabase/.gitignore
@@ -0,0 +1,8 @@
+# Supabase
+.branches
+.temp
+
+# dotenvx
+.env.keys
+.env.local
+.env.*.local
diff --git a/examples/browser/supabase/config.toml b/examples/browser/supabase/config.toml
new file mode 100644
index 00000000..3a30ba0c
--- /dev/null
+++ b/examples/browser/supabase/config.toml
@@ -0,0 +1,308 @@
+# For detailed configuration reference documentation, visit:
+# https://supabase.com/docs/guides/local-development/cli/config
+# A string used to distinguish different Supabase projects on the same host. Defaults to the
+# working directory name when running `supabase init`.
+project_id = "browser"
+
+[api]
+enabled = true
+# Port to use for the API URL.
+port = 54321
+# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
+# endpoints. `public` and `graphql_public` schemas are included by default.
+schemas = ["public", "graphql_public"]
+# Extra schemas to add to the search_path of every request.
+extra_search_path = ["public", "extensions"]
+# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
+# for accidental or malicious requests.
+max_rows = 1000
+
+[api.tls]
+# Enable HTTPS endpoints locally using a self-signed certificate.
+enabled = false
+
+[db]
+# Port to use for the local database URL.
+port = 54322
+# Port used by db diff command to initialize the shadow database.
+shadow_port = 54320
+# The database major version to use. This has to be the same as your remote database's. Run `SHOW
+# server_version;` on the remote database to check.
+major_version = 15
+
+[db.pooler]
+enabled = false
+# Port to use for the local connection pooler.
+port = 54329
+# Specifies when a server connection can be reused by other clients.
+# Configure one of the supported pooler modes: `transaction`, `session`.
+pool_mode = "transaction"
+# How many server connections to allow per user/database pair.
+default_pool_size = 20
+# Maximum number of client connections allowed.
+max_client_conn = 100
+
+# [db.vault]
+# secret_key = "env(SECRET_VALUE)"
+
+[db.migrations]
+# Specifies an ordered list of schema files that describe your database.
+# Supports glob patterns relative to supabase directory: "./schemas/*.sql"
+schema_paths = []
+
+[db.seed]
+# If enabled, seeds the database after migrations during a db reset.
+enabled = true
+# Specifies an ordered list of seed files to load during db reset.
+# Supports glob patterns relative to supabase directory: "./seeds/*.sql"
+sql_paths = ["./seed.sql"]
+
+[realtime]
+enabled = true
+# Bind realtime via either IPv4 or IPv6. (default: IPv4)
+# ip_version = "IPv6"
+# The maximum length in bytes of HTTP request headers. (default: 4096)
+# max_header_length = 4096
+
+[studio]
+enabled = true
+# Port to use for Supabase Studio.
+port = 54323
+# External URL of the API server that frontend connects to.
+api_url = "http://127.0.0.1"
+# OpenAI API Key to use for Supabase AI in the Supabase Studio.
+openai_api_key = "env(OPENAI_API_KEY)"
+
+# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
+# are monitored, and you can view the emails that would have been sent from the web interface.
+[inbucket]
+enabled = true
+# Port to use for the email testing server web interface.
+port = 54324
+# Uncomment to expose additional ports for testing user applications that send emails.
+# smtp_port = 54325
+# pop3_port = 54326
+# admin_email = "admin@email.com"
+# sender_name = "Admin"
+
+[storage]
+enabled = true
+# The maximum file size allowed (e.g. "5MB", "500KB").
+file_size_limit = "50MiB"
+
+# Image transformation API is available to Supabase Pro plan.
+# [storage.image_transformation]
+# enabled = true
+
+# Uncomment to configure local storage buckets
+# [storage.buckets.images]
+# public = false
+# file_size_limit = "50MiB"
+# allowed_mime_types = ["image/png", "image/jpeg"]
+# objects_path = "./images"
+
+[auth]
+enabled = true
+# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
+# in emails.
+site_url = "http://127.0.0.1:3000"
+# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
+additional_redirect_urls = ["https://127.0.0.1:3000"]
+# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week).
+jwt_expiry = 3600
+# If disabled, the refresh token will never expire.
+enable_refresh_token_rotation = true
+# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds.
+# Requires enable_refresh_token_rotation = true.
+refresh_token_reuse_interval = 10
+# Allow/disallow new user signups to your project.
+enable_signup = true
+# Allow/disallow anonymous sign-ins to your project.
+enable_anonymous_sign_ins = false
+# Allow/disallow testing manual linking of accounts
+enable_manual_linking = false
+# Passwords shorter than this value will be rejected as weak. Minimum 6, recommended 8 or more.
+minimum_password_length = 6
+# Passwords that do not meet the following requirements will be rejected as weak. Supported values
+# are: `letters_digits`, `lower_upper_letters_digits`, `lower_upper_letters_digits_symbols`
+password_requirements = ""
+
+[auth.rate_limit]
+# Number of emails that can be sent per hour. Requires auth.email.smtp to be enabled.
+email_sent = 2
+# Number of SMS messages that can be sent per hour. Requires auth.sms to be enabled.
+sms_sent = 30
+# Number of anonymous sign-ins that can be made per hour per IP address. Requires enable_anonymous_sign_ins = true.
+anonymous_users = 30
+# Number of sessions that can be refreshed in a 5 minute interval per IP address.
+token_refresh = 150
+# Number of sign up and sign-in requests that can be made in a 5 minute interval per IP address (excludes anonymous users).
+sign_in_sign_ups = 30
+# Number of OTP / Magic link verifications that can be made in a 5 minute interval per IP address.
+token_verifications = 30
+
+# Configure one of the supported captcha providers: `hcaptcha`, `turnstile`.
+# [auth.captcha]
+# enabled = true
+# provider = "hcaptcha"
+# secret = ""
+
+[auth.email]
+# Allow/disallow new user signups via email to your project.
+enable_signup = true
+# If enabled, a user will be required to confirm any email change on both the old, and new email
+# addresses. If disabled, only the new email is required to confirm.
+double_confirm_changes = true
+# If enabled, users need to confirm their email address before signing in.
+enable_confirmations = false
+# If enabled, users will need to reauthenticate or have logged in recently to change their password.
+secure_password_change = false
+# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email.
+max_frequency = "1s"
+# Number of characters used in the email OTP.
+otp_length = 6
+# Number of seconds before the email OTP expires (defaults to 1 hour).
+otp_expiry = 3600
+
+# Use a production-ready SMTP server
+# [auth.email.smtp]
+# enabled = true
+# host = "smtp.sendgrid.net"
+# port = 587
+# user = "apikey"
+# pass = "env(SENDGRID_API_KEY)"
+# admin_email = "admin@email.com"
+# sender_name = "Admin"
+
+# Uncomment to customize email template
+# [auth.email.template.invite]
+# subject = "You have been invited"
+# content_path = "./supabase/templates/invite.html"
+
+[auth.sms]
+# Allow/disallow new user signups via SMS to your project.
+enable_signup = false
+# If enabled, users need to confirm their phone number before signing in.
+enable_confirmations = false
+# Template for sending OTP to users
+template = "Your code is {{ .Code }}"
+# Controls the minimum amount of time that must pass before sending another sms otp.
+max_frequency = "5s"
+
+# Use pre-defined map of phone number to OTP for testing.
+# [auth.sms.test_otp]
+# 4152127777 = "123456"
+
+# Configure logged in session timeouts.
+# [auth.sessions]
+# Force log out after the specified duration.
+# timebox = "24h"
+# Force log out if the user has been inactive longer than the specified duration.
+# inactivity_timeout = "8h"
+
+# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used.
+# [auth.hook.custom_access_token]
+# enabled = true
+# uri = "pg-functions:////"
+
+# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`.
+[auth.sms.twilio]
+enabled = false
+account_sid = ""
+message_service_sid = ""
+# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead:
+auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)"
+
+# Multi-factor-authentication is available to Supabase Pro plan.
+[auth.mfa]
+# Control how many MFA factors can be enrolled at once per user.
+max_enrolled_factors = 10
+
+# Control MFA via App Authenticator (TOTP)
+[auth.mfa.totp]
+enroll_enabled = false
+verify_enabled = false
+
+# Configure MFA via Phone Messaging
+[auth.mfa.phone]
+enroll_enabled = false
+verify_enabled = false
+otp_length = 6
+template = "Your code is {{ .Code }}"
+max_frequency = "5s"
+
+# Configure MFA via WebAuthn
+# [auth.mfa.web_authn]
+# enroll_enabled = true
+# verify_enabled = true
+
+# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
+# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`,
+# `twitter`, `slack`, `spotify`, `workos`, `zoom`.
+[auth.external.apple]
+enabled = false
+client_id = ""
+# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead:
+secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)"
+# Overrides the default auth redirectUrl.
+redirect_uri = ""
+# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
+# or any other third-party OIDC providers.
+url = ""
+# If enabled, the nonce check will be skipped. Required for local sign in with Google auth.
+skip_nonce_check = false
+
+# Use Firebase Auth as a third-party provider alongside Supabase Auth.
+[auth.third_party.firebase]
+enabled = false
+# project_id = "my-firebase-project"
+
+# Use Auth0 as a third-party provider alongside Supabase Auth.
+[auth.third_party.auth0]
+enabled = false
+# tenant = "my-auth0-tenant"
+# tenant_region = "us"
+
+# Use AWS Cognito (Amplify) as a third-party provider alongside Supabase Auth.
+[auth.third_party.aws_cognito]
+enabled = false
+# user_pool_id = "my-user-pool-id"
+# user_pool_region = "us-east-1"
+
+# Use Clerk as a third-party provider alongside Supabase Auth.
+[auth.third_party.clerk]
+enabled = false
+# Obtain from https://clerk.com/setup/supabase
+# domain = "example.clerk.accounts.dev"
+
+[edge_runtime]
+enabled = true
+# Configure one of the supported request policies: `oneshot`, `per_worker`.
+# Use `oneshot` for hot reload, or `per_worker` for load testing.
+policy = "oneshot"
+# Port to attach the Chrome inspector for debugging edge functions.
+inspector_port = 8083
+# The Deno major version to use.
+deno_version = 1
+
+# [edge_runtime.secrets]
+# secret_key = "env(SECRET_VALUE)"
+
+[analytics]
+enabled = true
+port = 54327
+# Configure one of the supported backends: `postgres`, `bigquery`.
+backend = "postgres"
+
+# Experimental features may be deprecated any time
+[experimental]
+# Configures Postgres storage engine to use OrioleDB (S3)
+orioledb_version = ""
+# Configures S3 bucket URL, eg. .s3-.amazonaws.com
+s3_host = "env(S3_HOST)"
+# Configures S3 bucket region, eg. us-east-1
+s3_region = "env(S3_REGION)"
+# Configures AWS_ACCESS_KEY_ID for S3 bucket
+s3_access_key = "env(S3_ACCESS_KEY)"
+# Configures AWS_SECRET_ACCESS_KEY for S3 bucket
+s3_secret_key = "env(S3_SECRET_KEY)"
diff --git a/examples/browser/tests/connection.test.js b/examples/browser/tests/connection.test.js
new file mode 100644
index 00000000..885d75d2
--- /dev/null
+++ b/examples/browser/tests/connection.test.js
@@ -0,0 +1,73 @@
+import { test, expect } from '@playwright/test'
+
+test.describe('Realtime Connection', () => {
+ test('should connect and show connected status', async ({ page }) => {
+ // Navigate to the example page
+ await page.goto('http://localhost:8000')
+
+ // Get initial state
+ const status = await page.locator('#status')
+ await expect(status).toHaveText('Disconnected')
+
+ // Click connect button
+ const connectButton = await page.locator('#toggleConnection')
+ await connectButton.click()
+
+ // Wait for status to change to Connected
+ // We'll wait up to 10 seconds for the connection to establish
+ await expect(async () => {
+ const currentStatus = await status.textContent()
+ expect(currentStatus).toBe('Connected')
+ }).toPass({
+ timeout: 10000,
+ intervals: [1000] // Check every second
+ })
+
+ // Verify button state changed
+ await expect(connectButton).toHaveText('Disconnect')
+ await expect(connectButton).toHaveClass(/disconnect/)
+
+ // Verify message was added
+ const messages = await page.locator('#messages div').first()
+ await expect(messages).toContainText('Connected to Supabase Realtime')
+ })
+
+ test('should disconnect and show disconnected status', async ({ page }) => {
+ // Navigate to the example page
+ await page.goto('http://localhost:8000')
+
+ // Connect first
+ const connectButton = await page.locator('#toggleConnection')
+ await connectButton.click()
+
+ // Wait for connection
+ const status = await page.locator('#status')
+ await expect(async () => {
+ const currentStatus = await status.textContent()
+ expect(currentStatus).toBe('Connected')
+ }).toPass({
+ timeout: 10000,
+ intervals: [1000]
+ })
+
+ // Click disconnect
+ await connectButton.click()
+
+ // Wait for status to change to Disconnected
+ await expect(async () => {
+ const currentStatus = await status.textContent()
+ expect(currentStatus).toBe('Disconnected')
+ }).toPass({
+ timeout: 10000,
+ intervals: [1000]
+ })
+
+ // Verify button state changed
+ await expect(connectButton).toHaveText('Connect')
+ await expect(connectButton).toHaveClass(/connect/)
+
+ // Verify message was added
+ const messages = await page.locator('#messages div').first()
+ await expect(messages).toContainText('Disconnected from Supabase Realtime')
+ })
+})
\ No newline at end of file
diff --git a/example/.gitignore b/examples/nextjs/.gitignore
similarity index 100%
rename from example/.gitignore
rename to examples/nextjs/.gitignore
diff --git a/example/README.md b/examples/nextjs/README.md
similarity index 100%
rename from example/README.md
rename to examples/nextjs/README.md
diff --git a/example/lib/constants.js b/examples/nextjs/lib/constants.js
similarity index 100%
rename from example/lib/constants.js
rename to examples/nextjs/lib/constants.js
diff --git a/example/package-lock.json b/examples/nextjs/package-lock.json
similarity index 100%
rename from example/package-lock.json
rename to examples/nextjs/package-lock.json
diff --git a/example/package.json b/examples/nextjs/package.json
similarity index 100%
rename from example/package.json
rename to examples/nextjs/package.json
diff --git a/example/pages/_app.js b/examples/nextjs/pages/_app.js
similarity index 100%
rename from example/pages/_app.js
rename to examples/nextjs/pages/_app.js
diff --git a/example/pages/index.js b/examples/nextjs/pages/index.js
similarity index 100%
rename from example/pages/index.js
rename to examples/nextjs/pages/index.js
diff --git a/example/postcss.config.js b/examples/nextjs/postcss.config.js
similarity index 100%
rename from example/postcss.config.js
rename to examples/nextjs/postcss.config.js
diff --git a/example/styles/index.css b/examples/nextjs/styles/index.css
similarity index 100%
rename from example/styles/index.css
rename to examples/nextjs/styles/index.css
diff --git a/example/tailwind.config.js b/examples/nextjs/tailwind.config.js
similarity index 100%
rename from example/tailwind.config.js
rename to examples/nextjs/tailwind.config.js
diff --git a/package.json b/package.json
index d26430b8..aae74300 100644
--- a/package.json
+++ b/package.json
@@ -73,4 +73,4 @@
"default": "./src/native.js"
}
}
-}
\ No newline at end of file
+}