From d09866365c3f058565b77e3320a31cc6d66be643 Mon Sep 17 00:00:00 2001 From: Taylor Baldwin Date: Tue, 15 Oct 2024 14:53:51 -0400 Subject: [PATCH] [y sweet] support optional initialClientToken for YSweetProvider (#319) This updates the `YSweetProvider` (and the React ``) to take an optional `initialClientToken`. This can be used to cut out one server roundtrip if the client token is obtained at render time. --- js-pkg/client/src/provider.ts | 7 +- js-pkg/react/src/main.tsx | 14 ++- package-lock.json | 218 +++++++++++++++++++++++++++++++++- 3 files changed, 232 insertions(+), 7 deletions(-) diff --git a/js-pkg/client/src/provider.ts b/js-pkg/client/src/provider.ts index 907fac79..1bd514d4 100644 --- a/js-pkg/client/src/provider.ts +++ b/js-pkg/client/src/provider.ts @@ -224,6 +224,7 @@ export type YSweetProviderParams = { resyncInterval?: number maxBackoffTime?: number disableBc?: boolean + initialClientToken?: ClientToken } /** @@ -526,8 +527,10 @@ export async function ySweetProviderWrapper( authEndpoint: AuthEndpoint, roomname: string, doc: Y.Doc, - providerParams: YSweetProviderParams = {}, + wrapperParams: YSweetProviderParams = {}, ): Promise { + let { initialClientToken, ...providerParams } = wrapperParams + // we use an observable that lives outside the provider to store event listeners // so that we can re-subscribe to events when the provider is re-created const observable = new Observable() @@ -538,7 +541,7 @@ export async function ySweetProviderWrapper( const awareness = providerParams.awareness ?? new awarenessProtocol.Awareness(doc) providerParams = { ...providerParams, awareness } - let _clientToken = await getClientToken(authEndpoint, roomname) + let _clientToken = initialClientToken ?? (await getClientToken(authEndpoint, roomname)) let _provider = new YSweetProvider(_clientToken.url, roomname, doc, { ...updateProviderParams(providerParams, _clientToken), }) diff --git a/js-pkg/react/src/main.tsx b/js-pkg/react/src/main.tsx index a57d2045..dffd8d81 100644 --- a/js-pkg/react/src/main.tsx +++ b/js-pkg/react/src/main.tsx @@ -7,6 +7,7 @@ import { debuggerUrl, } from '@y-sweet/client' import type { AuthEndpoint, YSweetProviderWithClientToken } from '@y-sweet/client' +import type { ClientToken } from '@y-sweet/sdk' import type { ReactNode } from 'react' import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react' import type { Awareness } from 'y-protocols/awareness' @@ -171,14 +172,18 @@ export type YDocProviderProps = { /** The children to render. */ children: ReactNode - /** Response of a `getConnectionKey` call, passed from server to client. */ + /** The doc id to use for the Y.Doc. */ docId: string - /** The endpoint to use for authentication. */ + /** The endpoint to use for authentication or an async function that returns a client token. */ authEndpoint: AuthEndpoint + /** An optional initial client token to use for the Y.Doc. This will be used initially, and if + * the client token expires, the `authEndpoint` will be called to get a new client token. */ + initialClientToken?: ClientToken + /** If set to a string, the URL query parameter with this name - * will be set to the doc id from connectionKey. */ + * will be set to the doc id provided. */ setQueryParam?: string } @@ -186,7 +191,7 @@ export type YDocProviderProps = { * A React component that provides a Y.Doc instance to its children given an auth endpoint and a doc id. */ export function YDocProvider(props: YDocProviderProps) { - const { children, docId, authEndpoint } = props + const { children, docId, authEndpoint, initialClientToken } = props const [ctx, setCtx] = useState(null) @@ -197,6 +202,7 @@ export function YDocProvider(props: YDocProviderProps) { ;(async () => { provider = await createYjsProvider(doc, docId, authEndpoint, { + initialClientToken, // TODO: this disables local cross-tab communication, which makes // debugging easier, but should be re-enabled eventually disableBc: true, diff --git a/package-lock.json b/package-lock.json index 306d1078..db9f2bd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,7 +38,7 @@ "autoprefixer": "10.4.14", "eslint": "8.46.0", "eslint-config-next": "13.4.12", - "next": "14.2.3", + "next": "14.2.10", "postcss": "8.4.27", "prettier": "^3.0.0", "react": "18.2.0", @@ -47,6 +47,146 @@ "typescript": "5.1.6" } }, + "debugger/node_modules/@next/env": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.10.tgz", + "integrity": "sha512-dZIu93Bf5LUtluBXIv4woQw2cZVZ2DJTjax5/5DOs3lzEOeKLy7GxRSr4caK9/SCPdaW6bCgpye6+n4Dh9oJPw==" + }, + "debugger/node_modules/@next/swc-darwin-arm64": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.10.tgz", + "integrity": "sha512-V3z10NV+cvMAfxQUMhKgfQnPbjw+Ew3cnr64b0lr8MDiBJs3eLnM6RpGC46nhfMZsiXgQngCJKWGTC/yDcgrDQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "debugger/node_modules/@next/swc-darwin-x64": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.10.tgz", + "integrity": "sha512-Y0TC+FXbFUQ2MQgimJ/7Ina2mXIKhE7F+GUe1SgnzRmwFY3hX2z8nyVCxE82I2RicspdkZnSWMn4oTjIKz4uzA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "debugger/node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.10.tgz", + "integrity": "sha512-ZfQ7yOy5zyskSj9rFpa0Yd7gkrBnJTkYVSya95hX3zeBG9E55Z6OTNPn1j2BTFWvOVVj65C3T+qsjOyVI9DQpA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "debugger/node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.10.tgz", + "integrity": "sha512-n2i5o3y2jpBfXFRxDREr342BGIQCJbdAUi/K4q6Env3aSx8erM9VuKXHw5KNROK9ejFSPf0LhoSkU/ZiNdacpQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "debugger/node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.10.tgz", + "integrity": "sha512-GXvajAWh2woTT0GKEDlkVhFNxhJS/XdDmrVHrPOA83pLzlGPQnixqxD8u3bBB9oATBKB//5e4vpACnx5Vaxdqg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "debugger/node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.10.tgz", + "integrity": "sha512-opFFN5B0SnO+HTz4Wq4HaylXGFV+iHrVxd3YvREUX9K+xfc4ePbRrxqOuPOFjtSuiVouwe6uLeDtabjEIbkmDA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "debugger/node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.10.tgz", + "integrity": "sha512-9NUzZuR8WiXTvv+EiU/MXdcQ1XUvFixbLIMNQiVHuzs7ZIFrJDLJDaOF1KaqttoTujpcxljM/RNAOmw1GhPPQQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "debugger/node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.10.tgz", + "integrity": "sha512-fr3aEbSd1GeW3YUMBkWAu4hcdjZ6g4NBl1uku4gAn661tcxd1bHs1THWYzdsbTRLcCKLjrDZlNp6j2HTfrw+Bg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "debugger/node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.10.tgz", + "integrity": "sha512-UjeVoRGKNL2zfbcQ6fscmgjBAS/inHBh63mjIlfPg/NG8Yn2ztqylXt5qilYb6hoHIwaU2ogHknHWWmahJjgZQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "debugger/node_modules/@y-sweet/sdk/node_modules/@types/node": { "version": "20.16.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", @@ -56,6 +196,82 @@ "undici-types": "~6.19.2" } }, + "debugger/node_modules/next": { + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.10.tgz", + "integrity": "sha512-sDDExXnh33cY3RkS9JuFEKaS4HmlWmDKP1VJioucCG6z5KuA008DPsDZOzi8UfqEk3Ii+2NCQSJrfbEWtZZfww==", + "dependencies": { + "@next/env": "14.2.10", + "@swc/helpers": "0.5.5", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.2.10", + "@next/swc-darwin-x64": "14.2.10", + "@next/swc-linux-arm64-gnu": "14.2.10", + "@next/swc-linux-arm64-musl": "14.2.10", + "@next/swc-linux-x64-gnu": "14.2.10", + "@next/swc-linux-x64-musl": "14.2.10", + "@next/swc-win32-arm64-msvc": "14.2.10", + "@next/swc-win32-ia32-msvc": "14.2.10", + "@next/swc-win32-x64-msvc": "14.2.10" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "debugger/node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "debugger/node_modules/typescript": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",