Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions apps/dashboard/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,18 @@ function SharedWorkerTest({iframeRef}: {iframeRef: React.RefObject<HTMLIFrameEle
const handleQueryRequest = useCallback(async (data: unknown) => {
console.log('[Dashboard] Received query request:', data)

try {
// Type assert the data to the expected structure
const queryData = data as {
queryOptions: {
projectId: string
dataset: string
query: string
params?: Record<string, unknown>
}
requestId: string
// Type assert the data to the expected structure
const queryData = data as {
queryOptions: {
projectId: string
dataset: string
query: string
params?: Record<string, unknown>
}
requestId: string
}

try {
// Create a subscription request from the incoming query data
const subscription = createSubscriptionRequest({
storeName: 'query',
Expand Down Expand Up @@ -105,6 +105,7 @@ function SharedWorkerTest({iframeRef}: {iframeRef: React.RefObject<HTMLIFrameEle
} catch (error) {
console.error('[Dashboard] Error handling query request:', error)
return {
requestId: queryData.requestId,
error: error instanceof Error ? error.message : String(error),
subscriptionId: null,
}
Expand All @@ -115,7 +116,7 @@ function SharedWorkerTest({iframeRef}: {iframeRef: React.RefObject<HTMLIFrameEle
name: 'dashboard',
connectTo: 'sdk-app',
targetOrigin: '*',
onStatus: handleStatus,
onStatus: (workerStatus) => handleStatus(workerStatus as WorkerStatus),
heartbeat: false, // Disable heartbeat to reduce cycling
onMessage: {
'dashboard/v1/query/request': handleQueryRequest,
Expand Down Expand Up @@ -161,7 +162,10 @@ function SharedWorkerTest({iframeRef}: {iframeRef: React.RefObject<HTMLIFrameEle
iframe.removeEventListener('load', handleIframeLoad)
}
}
}, [connect])

// Return empty cleanup function when no iframe
return () => {}
}, [connect, iframeRef])

const testSubscription = async () => {
console.log('testSubscription')
Expand Down
3 changes: 3 additions & 0 deletions apps/dashboard/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export default defineConfig(({mode}) => {
'@sanity/sdk-react': resolve(import.meta.dirname, '../../packages/react/src/_exports'),
},
},
worker: {
format: 'es',
},
define: {
'import.meta.env.VITE_IS_E2E': JSON.stringify(isE2E),
'import.meta.env.VITE_E2E_PROJECT_ID': JSON.stringify(
Expand Down
24 changes: 16 additions & 8 deletions apps/sdk-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {SanityApp, SanityConfig, useQuery, useWindowConnection} from '@sanity/sdk-react'
import {Spinner, ThemeProvider} from '@sanity/ui'
import {buildTheme} from '@sanity/ui/theme'
import {type JSX, useEffect, useRef, useState} from 'react'
import {type JSX} from 'react'

const theme = buildTheme({})

Expand All @@ -25,7 +25,7 @@ type QueryRequestMessage = {
type: 'dashboard/v1/query/request'
data: {
queryId: string
queryOptions: any
queryOptions: unknown
requestId: string
}
}
Expand All @@ -42,20 +42,20 @@ type QueryResponseMessage = {

// Test component to demonstrate query forwarding
function QueryTest() {

// hack -- something in the node setup in the query store has a race condition
useWindowConnection<QueryResponseMessage, QueryRequestMessage>({
name: 'sdk-app',
connectTo: 'dashboard',
})

// This query should be forwarded to Dashboard when in iframe context
const {data, isPending} = useQuery({
const {data} = useQuery({
query: '*[_type == "movie"][0...5]{_id, title, releaseYear}',
projectId: 'ppsg7ml5',
dataset: 'test',
})

// eslint-disable-next-line no-console
console.log('data', data)

return (
Expand All @@ -66,7 +66,15 @@ function QueryTest() {
</div>
<div style={{marginTop: 8}}>
<strong>Data:</strong>
<pre style={{marginTop: 4, padding: 8, backgroundColor: '#f5f5f5', borderRadius: 4, fontSize: '12px'}}>
<pre
style={{
marginTop: 4,
padding: 8,
backgroundColor: '#f5f5f5',
borderRadius: 4,
fontSize: '12px',
}}
>
{/* {JSON.stringify(data, null, 2)} */}
</pre>
</div>
Expand All @@ -81,9 +89,9 @@ export default function App(): JSX.Element {
return (
<ThemeProvider theme={theme}>
<SanityApp fallback={<Spinner />} config={devConfigs}>
<div style={{height: '100vh', width: '100vw', overflow: 'auto'}}>
<QueryTest />
</div>
<div style={{height: '100vh', width: '100vw', overflow: 'auto'}}>
<QueryTest />
</div>
</SanityApp>
</ThemeProvider>
)
Expand Down
45 changes: 26 additions & 19 deletions packages/core/src/_exports/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@
*/

import {createClient} from '@sanity/client'

import {sharedWorkerStore} from '../sharedWorkerStore/sharedWorkerStore'
import {type SubscriptionRequest} from '../sharedWorkerStore/types'

declare const self: SharedWorkerGlobalScope

// Cache to store query results
const queryCache = new Map<string, {
result: unknown
timestamp: number
subscribers: Set<MessagePort>
}>()
const queryCache = new Map<
string,
{
result: unknown
timestamp: number
subscribers: Set<MessagePort>
}
>()

// Helper to create stable cache keys
function getCacheKey(subscription: SubscriptionRequest): string {
Expand Down Expand Up @@ -85,7 +89,7 @@ function handleRegisterSubscription(subscription: SubscriptionRequest, port: Mes
try {
// Register the subscription in the store
sharedWorkerStore.getState().registerSubscription(subscription)

// Check if we need to execute a query for this subscription
if (subscription.storeName === 'query' && subscription.params?.['query']) {
handleQuerySubscription(subscription, port)
Expand Down Expand Up @@ -113,12 +117,15 @@ function handleRegisterSubscription(subscription: SubscriptionRequest, port: Mes
* @internal
* Handle query subscription - execute the query and cache results
*/
async function handleQuerySubscription(subscription: SubscriptionRequest, port: MessagePort): Promise<void> {
async function handleQuerySubscription(
subscription: SubscriptionRequest,
port: MessagePort,
): Promise<void> {
const cacheKey = getCacheKey(subscription)

// Check if we already have this query result cached
let cacheEntry = queryCache.get(cacheKey)

if (!cacheEntry) {
try {
// Create Sanity client for this project/dataset
Expand All @@ -128,50 +135,50 @@ async function handleQuerySubscription(subscription: SubscriptionRequest, port:
apiVersion: '2024-01-01',
useCdn: true,
})

// Execute the query
console.log('[SharedWorker] Executing query:', subscription.params?.['query'])
const result = await client.fetch(
subscription.params?.['query'] as string,
subscription.params?.['options'] as Record<string, unknown> || {}
(subscription.params?.['options'] as Record<string, unknown>) || {},
)

// Cache the result
cacheEntry = {
result,
timestamp: Date.now(),
subscribers: new Set()
subscribers: new Set(),
}
queryCache.set(cacheKey, cacheEntry)

console.log('[SharedWorker] Query executed and cached:', cacheKey)
} catch (error) {
console.error('[SharedWorker] Query execution failed:', error)
port.postMessage({
type: 'SUBSCRIPTION_ERROR',
data: {
error: `Query execution failed: ${(error as Error).message}`,
subscriptionId: subscription.subscriptionId
subscriptionId: subscription.subscriptionId,
},
})
return
}
}

// Add this port as a subscriber to the cache entry
cacheEntry.subscribers.add(port)

// Send the query result back to the subscriber
port.postMessage({
type: 'SUBSCRIPTION_REGISTERED',
data: {
subscriptionId: subscription.subscriptionId,
result: cacheEntry.result,
cached: cacheEntry.timestamp !== Date.now(),
cacheKey
cacheKey,
},
})

console.log('[SharedWorker] Query result sent to subscriber:', subscription.subscriptionId)
}

Expand Down
Loading