From 26e373a48fe89fbd0c58dc583541002532a5e1d8 Mon Sep 17 00:00:00 2001 From: Miguel Gomes Date: Thu, 27 Jun 2024 11:51:43 -0300 Subject: [PATCH] react-sdk: first draft (#249) Missing for now: - actions / mutations (need spec) - defaultOptions (can be super useful for actions, its a good place to add toasts) - example usage in playground - tests --- packages/playground/package.json | 5 + packages/playground/src/App.tsx | 21 +++- packages/playground/src/routes/index.tsx | 11 +- packages/playground/src/routes/layout.tsx | 14 +++ packages/playground/src/routes/root.tsx | 90 ++++++++++++-- .../playground/src/utils/viem-to-ethers.ts | 24 ++++ packages/react-sdk/README.md | 50 +++++++- packages/react-sdk/package.json | 11 +- packages/react-sdk/src/RiverSyncProvider.tsx | 30 +++++ packages/react-sdk/src/connectRiver.ts | 13 ++ packages/react-sdk/src/context.ts | 3 - packages/react-sdk/src/index.ts | 11 +- .../src/internals/RiverSyncContext.tsx | 9 ++ .../react-sdk/src/internals/useRiverSync.tsx | 4 + packages/react-sdk/src/useObservable.ts | 112 ++++++++++++++++++ packages/react-sdk/src/useRiverConnection.ts | 30 +++++ packages/react-sdk/src/useSyncAgent.tsx | 15 +++ packages/react-sdk/src/useSyncValue.ts | 15 +++ packages/react-sdk/src/utils.ts | 8 ++ packages/react-sdk/tsconfig.build.json | 3 + packages/react-sdk/tsconfig.json | 3 - packages/sdk/src/index.ts | 24 +++- .../scripts => scripts}/generate_sdk_index.sh | 15 ++- yarn.lock | 9 +- 24 files changed, 498 insertions(+), 32 deletions(-) create mode 100644 packages/playground/src/routes/layout.tsx create mode 100644 packages/playground/src/utils/viem-to-ethers.ts create mode 100644 packages/react-sdk/src/RiverSyncProvider.tsx create mode 100644 packages/react-sdk/src/connectRiver.ts delete mode 100644 packages/react-sdk/src/context.ts create mode 100644 packages/react-sdk/src/internals/RiverSyncContext.tsx create mode 100644 packages/react-sdk/src/internals/useRiverSync.tsx create mode 100644 packages/react-sdk/src/useObservable.ts create mode 100644 packages/react-sdk/src/useRiverConnection.ts create mode 100644 packages/react-sdk/src/useSyncAgent.tsx create mode 100644 packages/react-sdk/src/useSyncValue.ts create mode 100644 packages/react-sdk/src/utils.ts rename {core/scripts => scripts}/generate_sdk_index.sh (72%) diff --git a/packages/playground/package.json b/packages/playground/package.json index c14cb31ac..5b55320eb 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -17,14 +17,19 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", + "@river-build/react-sdk": "workspace:^", + "@river-build/sdk": "workspace:^", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "ethers": "^5.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.38.0", "react-router-dom": "^6.4.2", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", + "viem": "^1.18.2", + "wagmi": "^1.4.12", "zod": "^3.21.4" }, "devDependencies": { diff --git a/packages/playground/src/App.tsx b/packages/playground/src/App.tsx index a924b8559..a5cb09e3c 100644 --- a/packages/playground/src/App.tsx +++ b/packages/playground/src/App.tsx @@ -1,11 +1,26 @@ import { RouterProvider } from 'react-router-dom' +import { WagmiConfig, configureChains, createConfig, mainnet } from 'wagmi' +import { publicProvider } from 'wagmi/providers/public' +import { InjectedConnector } from 'wagmi/connectors/injected' +import { RiverSyncProvider } from '@river-build/react-sdk' import { router } from './routes' +const { publicClient, webSocketPublicClient } = configureChains([mainnet], [publicProvider()]) + +const config = createConfig({ + autoConnect: true, + publicClient, + webSocketPublicClient, + connectors: [new InjectedConnector()], +}) + function App() { return ( - <> - - + + + + + ) } diff --git a/packages/playground/src/routes/index.tsx b/packages/playground/src/routes/index.tsx index d2c50fd7c..dc905a4ec 100644 --- a/packages/playground/src/routes/index.tsx +++ b/packages/playground/src/routes/index.tsx @@ -1,11 +1,20 @@ import { createBrowserRouter } from 'react-router-dom' -import { RootLayout } from './root' +import { RootLayout } from './layout' export const router = createBrowserRouter([ { path: '/', element: , children: [ + { + path: '/', + lazy: async () => { + const { ConnectRoute } = await import('./root') + return { + Component: ConnectRoute, + } + }, + }, { path: 'components', lazy: async () => { diff --git a/packages/playground/src/routes/layout.tsx b/packages/playground/src/routes/layout.tsx new file mode 100644 index 000000000..7fc3a34e9 --- /dev/null +++ b/packages/playground/src/routes/layout.tsx @@ -0,0 +1,14 @@ +import { Outlet } from 'react-router-dom' + +export const RootLayout = () => { + return ( +
+
+

River Playground

+
+
+ +
+
+ ) +} diff --git a/packages/playground/src/routes/root.tsx b/packages/playground/src/routes/root.tsx index 7fc3a34e9..2276210f4 100644 --- a/packages/playground/src/routes/root.tsx +++ b/packages/playground/src/routes/root.tsx @@ -1,14 +1,88 @@ -import { Outlet } from 'react-router-dom' +import { useAccount, useConnect } from 'wagmi' +import { makeRiverConfig } from '@river-build/sdk' +import { useRiverConnection, useSyncValue } from '@river-build/react-sdk' +import { Button } from '@/components/ui/button' +import { useEthersSigner } from '@/utils/viem-to-ethers' + +export const ConnectRoute = () => { + const { isConnected } = useAccount() + + return ( +
+ {isConnected ? : } +
+ ) +} + +const ChainConnectButton = () => { + const { connector: activeConnector } = useAccount() + const { connect, connectors, error, isLoading, pendingConnector } = useConnect() + + return ( +
+ {connectors.map((connector) => ( + + ))} + {error &&
{error.message}
} +
+ ) +} + +const riverConfig = makeRiverConfig('gamma') + +const ConnectRiver = () => { + const signer = useEthersSigner() + const { connect, disconnect, isConnecting, isConnected } = useRiverConnection() -export const RootLayout = () => { return ( -
-
-

River Playground

-
-
- + <> +
+
+ {isConnected ? ( + <> +

Connected to Sync Agent

+ + + ) : ( +

Not Connected

+ )} + + ) +} + +const ConnectedContent = () => { + const { data: nodeUrls } = useSyncValue((s) => s.riverStreamNodeUrls, { + onUpdate: (data) => console.log('onUpdate', data), + onError: (error) => console.error('onError', error), + onSaved: (data) => console.log('onSaved', data), + }) + return ( +
+
+                {JSON.stringify(nodeUrls, null, 2)}
+            
) } diff --git a/packages/playground/src/utils/viem-to-ethers.ts b/packages/playground/src/utils/viem-to-ethers.ts new file mode 100644 index 000000000..4f8117655 --- /dev/null +++ b/packages/playground/src/utils/viem-to-ethers.ts @@ -0,0 +1,24 @@ +import * as React from 'react' +import { type WalletClient, useWalletClient } from 'wagmi' +import { providers } from 'ethers' + +export function walletClientToSigner(walletClient: WalletClient) { + const { account, chain, transport } = walletClient + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + } + const provider = new providers.Web3Provider(transport, network) + const signer = provider.getSigner(account.address) + return signer +} + +/** Hook to convert a viem Wallet Client to an ethers.js Signer. */ +export function useEthersSigner({ chainId }: { chainId?: number } = {}) { + const { data: walletClient } = useWalletClient({ chainId }) + return React.useMemo( + () => (walletClient ? walletClientToSigner(walletClient) : undefined), + [walletClient], + ) +} diff --git a/packages/react-sdk/README.md b/packages/react-sdk/README.md index a3d9e1baf..25936c2f8 100644 --- a/packages/react-sdk/README.md +++ b/packages/react-sdk/README.md @@ -12,9 +12,55 @@ yarn add @river-build/react-sdk # Usage -TODO for now. But that's what we need to solve: +## Connect to River -## Connect to a River stream +`@river-build/react-sdk` suggests you to use Wagmi to connect to River. +Wrap your app with `RiverSyncProvider` and use the `useConnectRiver` hook to connect to River. + +> [!note] If you're using Viem +> You'll need to use `useEthersSigner` to get the signer from viem wallet client. +> You can get the hook from [wagmi docs](https://wagmi.sh/react/guides/ethers#usage-1). + +```tsx +import { + RiverSyncProvider, + useConnectRiver, + useConnection, +} from "@river-build/react-sdk"; +import { makeRiverConfig } from "@river-build/sdk"; +import { WagmiProvider } from "wagmi"; +import { useEthersSigner } from "./utils/viem-to-ethers"; + +const riverConfig = makeRiverConfig("gamma"); + +const App = ({ children }: { children: React.ReactNode }) => { + return ( + + {children} + + ); +}; + +const ConnectRiver = () => { + const { connect, isConnecting, isConnected } = useConnectRiver(); + const signer = useEthersSigner(); + + return ( + <> + + {isConnected && Connected!} + + ); +}; +``` ## Get information about an account diff --git a/packages/react-sdk/package.json b/packages/react-sdk/package.json index 55abc1017..49817741b 100644 --- a/packages/react-sdk/package.json +++ b/packages/react-sdk/package.json @@ -11,6 +11,7 @@ "build": "yarn run clean && yarn run build:esm+types", "build:esm+types": "tsc --project tsconfig.build.json --outDir ./dist/esm --declaration --declarationMap --declarationDir ./dist/types", "clean": "rm -rf dist tsconfig.tsbuildinfo", + "watch": "yarn build -w", "test:build": "publint --strict && attw --pack --ignore-rules cjs-resolves-to-esm", "typecheck": "tsc --noEmit" }, @@ -23,13 +24,17 @@ ], "sideEffects": false, "type": "module", - "main": "./dist/esm/exports/index.js", - "types": "./dist/types/exports/index.d.ts", - "typings": "./dist/types/exports/index.d.ts", + "main": "./dist/esm/index.js", + "types": "./dist/types/index.d.ts", + "typings": "./dist/types/index.d.ts", "peerDependencies": { "react": "^18.2.0", "typescript": "^5.1.6" }, + "dependencies": { + "@river-build/sdk": "workspace:^", + "ethers": "^5.7.2" + }, "devDependencies": { "@testing-library/react": "^14.2.1", "@types/react": "^18.2.11", diff --git a/packages/react-sdk/src/RiverSyncProvider.tsx b/packages/react-sdk/src/RiverSyncProvider.tsx new file mode 100644 index 000000000..1ed75a918 --- /dev/null +++ b/packages/react-sdk/src/RiverSyncProvider.tsx @@ -0,0 +1,30 @@ +'use client' +import type { SyncAgent } from '@river-build/sdk' +import { useEffect, useState } from 'react' +import { RiverSyncContext } from './internals/RiverSyncContext' + +type RiverSyncProviderProps = { + syncAgent?: SyncAgent + children?: React.ReactNode +} + +export const RiverSyncProvider = (props: RiverSyncProviderProps) => { + const [syncAgent, setSyncAgent] = useState(() => props.syncAgent) + + useEffect(() => { + if (syncAgent) { + syncAgent.start() + } + }, [syncAgent]) + + return ( + + {props.children} + + ) +} diff --git a/packages/react-sdk/src/connectRiver.ts b/packages/react-sdk/src/connectRiver.ts new file mode 100644 index 000000000..40d4b6b2e --- /dev/null +++ b/packages/react-sdk/src/connectRiver.ts @@ -0,0 +1,13 @@ +/// This file can be used on server side to create a River Client +/// We don't want a 'use client' directive here +import { SyncAgent, type SyncAgentConfig, makeSignerContext } from '@river-build/sdk' +import { ethers } from 'ethers' + +export const connectRiver = async ( + signer: ethers.Signer, + config: Omit, +): Promise => { + const delegateWallet = ethers.Wallet.createRandom() + const signerContext = await makeSignerContext(signer, delegateWallet) + return new SyncAgent({ context: signerContext, ...config }) +} diff --git a/packages/react-sdk/src/context.ts b/packages/react-sdk/src/context.ts deleted file mode 100644 index cd3a62059..000000000 --- a/packages/react-sdk/src/context.ts +++ /dev/null @@ -1,3 +0,0 @@ -'use client' - -export const hello = () => 'world' diff --git a/packages/react-sdk/src/index.ts b/packages/react-sdk/src/index.ts index 402e2ddac..4360e3096 100644 --- a/packages/react-sdk/src/index.ts +++ b/packages/react-sdk/src/index.ts @@ -1 +1,10 @@ -export { hello } from './context' +/************************************************************************** + * This file can be auto generated by 🏕️ scripts/generate_sdk_index.sh 🏕️ * + **************************************************************************/ +export * from './RiverSyncProvider' +export * from './connectRiver' +export * from './useObservable' +export * from './useRiverConnection' +export * from './useSyncAgent' +export * from './useSyncValue' +export * from './utils' diff --git a/packages/react-sdk/src/internals/RiverSyncContext.tsx b/packages/react-sdk/src/internals/RiverSyncContext.tsx new file mode 100644 index 000000000..517998bd2 --- /dev/null +++ b/packages/react-sdk/src/internals/RiverSyncContext.tsx @@ -0,0 +1,9 @@ +'use client' +import { SyncAgent } from '@river-build/sdk' +import { createContext } from 'react' + +type RiverSyncContextType = { + syncAgent: SyncAgent | undefined + setSyncAgent: (syncAgent: SyncAgent | undefined) => void +} +export const RiverSyncContext = createContext(undefined) diff --git a/packages/react-sdk/src/internals/useRiverSync.tsx b/packages/react-sdk/src/internals/useRiverSync.tsx new file mode 100644 index 000000000..3f8f66efb --- /dev/null +++ b/packages/react-sdk/src/internals/useRiverSync.tsx @@ -0,0 +1,4 @@ +'use client' +import { useContext } from 'react' +import { RiverSyncContext } from './RiverSyncContext' +export const useRiverSync = () => useContext(RiverSyncContext) diff --git a/packages/react-sdk/src/useObservable.ts b/packages/react-sdk/src/useObservable.ts new file mode 100644 index 000000000..4ff08f11d --- /dev/null +++ b/packages/react-sdk/src/useObservable.ts @@ -0,0 +1,112 @@ +'use client' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { type Observable, type PersistedModel } from '@river-build/sdk' + +export type ObservableConfig = { + fireImmediately?: boolean + onUpdate?: (data: T) => void + onError?: (error: Error) => void + onSaved?: (data: T) => void +} + +type ObservableReturn = { + data: T | undefined + error: Error | undefined + status: PersistedModel['status'] + isLoading: boolean + isError: boolean + isSaving: boolean + isSaved: boolean + isLoaded: boolean +} + +// Needed to treat Observable and Observable> as the same +const makeDataModel = (value: T): PersistedModel => ({ + status: 'loaded', + data: value, +}) + +const isPersisted = (value: unknown): value is PersistedModel => { + if (typeof value !== 'object') { + return false + } + if (value === null) { + return false + } + return 'status' in value && 'data' in value +} + +export function useObservable( + observable: Observable | undefined, + config?: ObservableConfig, +): ObservableReturn { + const [value, setValue] = useState | undefined>( + observable?.value + ? isPersisted(observable.value) + ? observable?.value + : makeDataModel(observable.value) + : undefined, + ) + + const opts = { fireImmediately: true, ...config } satisfies ObservableConfig + + const onSubscribe = useCallback( + (newValue: PersistedModel | T) => { + let value: PersistedModel | undefined + if (isPersisted(newValue)) { + value = newValue + } else { + value = makeDataModel(newValue) + } + setValue(value) + if (value.status === 'loaded') { + opts.onUpdate?.(value.data) + } + if (value.status === 'error') { + opts.onError?.(value.error) + } + if (value.status === 'saved') { + opts.onSaved?.(value.data) + } + }, + [opts], + ) + + useEffect(() => { + if (!observable) { + return + } + const subscription = observable.subscribe(onSubscribe, { + fireImediately: opts?.fireImmediately, + }) + return () => subscription.unsubscribe(onSubscribe) + }, [opts, observable, onSubscribe]) + + const data = useMemo(() => { + if (!value) { + return { + data: undefined, + error: undefined, + status: 'loading', + isLoading: true, + isError: false, + isSaving: false, + isLoaded: false, + isSaved: false, + } + } + const { data, status } = value + return { + data, + error: status === 'error' ? value.error : undefined, + status, + isLoading: status === 'loading', + isError: status === 'error', + isSaving: status === 'saving', + isLoaded: status === 'loaded', + isSaved: status === 'saved', + } + }, [value]) satisfies ObservableReturn + + return data +} diff --git a/packages/react-sdk/src/useRiverConnection.ts b/packages/react-sdk/src/useRiverConnection.ts new file mode 100644 index 000000000..47e672a5c --- /dev/null +++ b/packages/react-sdk/src/useRiverConnection.ts @@ -0,0 +1,30 @@ +import type { SyncAgentConfig } from '@river-build/sdk' +import { useCallback, useMemo, useState } from 'react' +import type { ethers } from 'ethers' +import { connectRiver } from './connectRiver' +import { useRiverSync } from './internals/useRiverSync' + +export const useRiverConnection = () => { + const [isConnecting, setConnecting] = useState(false) + const river = useRiverSync() + + const connect = useCallback( + async (signer: ethers.Signer, config: Omit) => { + if (river?.syncAgent) { + return + } + + setConnecting(true) + return connectRiver(signer, config) + .then((syncAgent) => river?.setSyncAgent(syncAgent)) + .finally(() => setConnecting(false)) + }, + [river], + ) + + const disconnect = useCallback(() => river?.setSyncAgent(undefined), [river]) + + const isConnected = useMemo(() => !!river?.syncAgent, [river]) + + return { connect, disconnect, isConnecting, isConnected } +} diff --git a/packages/react-sdk/src/useSyncAgent.tsx b/packages/react-sdk/src/useSyncAgent.tsx new file mode 100644 index 000000000..9df21c92e --- /dev/null +++ b/packages/react-sdk/src/useSyncAgent.tsx @@ -0,0 +1,15 @@ +'use client' +import { useRiverSync } from './internals/useRiverSync' + +export const useSyncAgent = () => { + const river = useRiverSync() + + if (!river?.syncAgent) { + console.error( + 'No SyncAgent set, use RiverSyncProvider to set one or use useConnected to check if connected', + ) + return undefined + } + + return river.syncAgent +} diff --git a/packages/react-sdk/src/useSyncValue.ts b/packages/react-sdk/src/useSyncValue.ts new file mode 100644 index 000000000..51dc7f5b5 --- /dev/null +++ b/packages/react-sdk/src/useSyncValue.ts @@ -0,0 +1,15 @@ +'use client' +import type { Observable, SyncAgent } from '@river-build/sdk' +import { type ObservableConfig, useObservable } from './useObservable' +import { useSyncAgent } from './useSyncAgent' + +type SyncLens = SyncAgent['observables'] + +// TODO: maybe we should call this useRiver? +export function useSyncValue( + fn: (sync: SyncLens) => Observable, + config?: ObservableConfig, +) { + const syncAgent = useSyncAgent() + return useObservable(syncAgent ? fn(syncAgent.observables) : undefined, config) +} diff --git a/packages/react-sdk/src/utils.ts b/packages/react-sdk/src/utils.ts new file mode 100644 index 000000000..00967d925 --- /dev/null +++ b/packages/react-sdk/src/utils.ts @@ -0,0 +1,8 @@ +import type { PersistedModel } from '@river-build/sdk' + +export const isPersistedModel = (data: T | PersistedModel): data is PersistedModel => { + if (typeof data === 'object' && data !== null) { + return 'status' in data + } + return false +} diff --git a/packages/react-sdk/tsconfig.build.json b/packages/react-sdk/tsconfig.build.json index 676931c2d..4c6dfcf9e 100644 --- a/packages/react-sdk/tsconfig.build.json +++ b/packages/react-sdk/tsconfig.build.json @@ -1,5 +1,8 @@ { "extends": "../tsconfig.base.json", + "compilerOptions": { + "jsx": "preserve" + }, "include": ["src/**/*.ts"], "exclude": ["src/**/*.test.ts", "src/**/*.test-d.ts"] } diff --git a/packages/react-sdk/tsconfig.json b/packages/react-sdk/tsconfig.json index 4cd15526b..178dc1178 100644 --- a/packages/react-sdk/tsconfig.json +++ b/packages/react-sdk/tsconfig.json @@ -1,8 +1,5 @@ { "extends": "./tsconfig.build.json", - "compilerOptions": { - "jsx": "preserve" - }, "include": ["src/**/*.ts", "src/**/*.tsx", "test/**/*.ts", "test/**/*.tsx", ".eslintrc.cjs"], "exclude": [] } diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index e9914c1f2..76c7c57b1 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -3,15 +3,22 @@ **************************************************************************/ export * from './check' export * from './client' +export * from './clientDecryptionExtensions' export * from './encryptedContentTypes' export * from './id' -export * from './makeStreamRpcClient' export * from './makeRiverRpcClient' +export * from './makeStreamRpcClient' +export * from './migrations/migrateSnapshot' +export * from './migrations/snapshotMigration0000' +export * from './migrations/snapshotMigration0001' +export * from './observable/observable' +export * from './observable/persistedObservable' export * from './persistenceStore' export * from './riverConfig' export * from './riverDbManager' export * from './sign' export * from './signerContext' +export * from './store/store' export * from './stream' export * from './streamEvents' export * from './streamStateView' @@ -32,6 +39,19 @@ export * from './streamStateView_UserInbox' export * from './streamStateView_UserMetadata' export * from './streamStateView_UserSettings' export * from './streamUtils' +export * from './sync-agent/entitlements/entitlements' +export * from './sync-agent/river-connection/models/streamNodeUrls' +export * from './sync-agent/river-connection/riverConnection' +export * from './sync-agent/syncAgent' +export * from './sync-agent/syncAgentStore' +export * from './sync-agent/user/models/userDeviceKeys' +export * from './sync-agent/user/models/userInbox' +export * from './sync-agent/user/models/userMemberships' +export * from './sync-agent/user/models/userSettings' +export * from './sync-agent/user/user' +export * from './sync-agent/utils/promiseQueue' +export * from './sync-agent/utils/providers' +export * from './sync-agent/utils/spaceUtils' export * from './syncEvents' export * from './syncedStream' export * from './syncedStreams' @@ -39,5 +59,7 @@ export * from './syncedStreamsExtension' export * from './types' export * from './unauthenticatedClient' export * from './userMetadata_DisplayNames' +export * from './userMetadata_EnsAddresses' +export * from './userMetadata_Nft' export * from './userMetadata_Usernames' export * from './utils' diff --git a/core/scripts/generate_sdk_index.sh b/scripts/generate_sdk_index.sh similarity index 72% rename from core/scripts/generate_sdk_index.sh rename to scripts/generate_sdk_index.sh index 3567fbbe2..e7608dfe4 100755 --- a/core/scripts/generate_sdk_index.sh +++ b/scripts/generate_sdk_index.sh @@ -5,7 +5,7 @@ cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" # Array of directories to process -declare -a dirs=("../sdk/src") +declare -a dirs=("../packages/sdk/src" "../packages/react-sdk/src") # Loop through each directory for dir in "${dirs[@]}"; do @@ -23,10 +23,13 @@ for dir in "${dirs[@]}"; do # Loop through each TypeScript file to append an export statement to the array # Skip files that have ".test." in their name, the existing index.ts file, and directories - for file in $(find . -type f -name "*.ts" ! -name "*.test*" ! -name "*.d.ts" ! -name "index.ts" | sort); do - # Remove the './' prefix and '.ts' suffix from the file path - file=$(echo "$file" | sed "s|^\./||;s|\.ts$||") - + for file in $(find . -type f \( -name "*.ts" -o -name "*.tsx" \) ! -name "*.test*" ! -name "*.d.ts" ! -name "index.ts" ! -path "*/internals/*" | sort); do + # Remove the './' prefix and '.tsx' or '.ts' suffix from the file path + file_without_slash=${file#./} + file_without_tsx=${file_without_slash%.tsx} + file_without_ts=${file_without_tsx%.ts} + file=${file_without_ts} + # Append export statement to the array exports+=("export * from './$file'") done @@ -38,4 +41,4 @@ for dir in "${dirs[@]}"; do # Change back to the original directory to continue the loop cd - || exit -done +done \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index de77884e5..05b928c2d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3537,6 +3537,8 @@ __metadata: "@radix-ui/react-switch": ^1.0.3 "@river-build/eslint-config": "workspace:^" "@river-build/prettier-config": "workspace:^" + "@river-build/react-sdk": "workspace:^" + "@river-build/sdk": "workspace:^" "@types/node": ^20.5.0 "@types/react": ^18.2.11 "@types/react-dom": ^18.2.4 @@ -3550,6 +3552,7 @@ __metadata: eslint-plugin-import: ^2.27.5 eslint-plugin-react: ^7.32.2 eslint-plugin-react-hooks: ^4.6.0 + ethers: ^5.7.2 postcss: ^8.4.38 prettier: ^2.8.8 prettier-plugin-tailwindcss: ^0.4.1 @@ -3561,8 +3564,10 @@ __metadata: tailwindcss: ^3.4.4 tailwindcss-animate: ^1.0.7 typescript: ^5.1.6 + viem: ^1.18.2 vite: ^5.3.1 vite-plugin-checker: ^0.6.4 + wagmi: ^1.4.12 zod: ^3.21.4 languageName: unknown linkType: soft @@ -3603,10 +3608,11 @@ __metadata: languageName: unknown linkType: soft -"@river-build/react-sdk@workspace:packages/react-sdk": +"@river-build/react-sdk@workspace:^, @river-build/react-sdk@workspace:packages/react-sdk": version: 0.0.0-use.local resolution: "@river-build/react-sdk@workspace:packages/react-sdk" dependencies: + "@river-build/sdk": "workspace:^" "@testing-library/react": ^14.2.1 "@types/react": ^18.2.11 "@types/react-dom": ^18.2.4 @@ -3616,6 +3622,7 @@ __metadata: eslint-plugin-import: ^2.27.5 eslint-plugin-react: ^7.32.2 eslint-plugin-react-hooks: ^4.6.0 + ethers: ^5.7.2 react: ^18.2.0 react-dom: ^18.2.0 typescript: ^5.1.6