From f620b1782a612479ff8a99ff06efb8cdd4504729 Mon Sep 17 00:00:00 2001 From: rahim Date: Sat, 31 Jan 2026 18:52:59 +1100 Subject: [PATCH] refactor(store): remove platform queue bindings (#360) --- packages/store/src/lit/controllers/index.ts | 1 - .../src/lit/controllers/queue-controller.ts | 49 ----------- .../tests/queue-controller.test.ts | 86 ------------------- .../src/lit/controllers/tests/types.test.ts | 15 +--- packages/store/src/lit/create-store.ts | 43 +--------- packages/store/src/lit/index.ts | 1 - .../store/src/lit/tests/create-store.test.ts | 8 -- packages/store/src/react/create-store.tsx | 26 +----- packages/store/src/react/hooks/index.ts | 1 - .../src/react/hooks/tests/use-queue.test.tsx | 30 ------- packages/store/src/react/hooks/use-queue.ts | 35 -------- packages/store/src/react/index.ts | 2 +- .../src/react/tests/create-store.test.tsx | 15 ---- 13 files changed, 4 insertions(+), 308 deletions(-) delete mode 100644 packages/store/src/lit/controllers/queue-controller.ts delete mode 100644 packages/store/src/lit/controllers/tests/queue-controller.test.ts delete mode 100644 packages/store/src/react/hooks/tests/use-queue.test.tsx delete mode 100644 packages/store/src/react/hooks/use-queue.ts diff --git a/packages/store/src/lit/controllers/index.ts b/packages/store/src/lit/controllers/index.ts index cf97390c..419f7b13 100644 --- a/packages/store/src/lit/controllers/index.ts +++ b/packages/store/src/lit/controllers/index.ts @@ -1,6 +1,5 @@ export type { AsyncStatus } from '../../shared/types'; -export { QueueController, type QueueControllerHost } from './queue-controller'; export { SnapshotController, type SnapshotControllerHost, diff --git a/packages/store/src/lit/controllers/queue-controller.ts b/packages/store/src/lit/controllers/queue-controller.ts deleted file mode 100644 index 823082f2..00000000 --- a/packages/store/src/lit/controllers/queue-controller.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { AnyStore } from '../../core/store'; -import type { StoreSource } from '../store-accessor'; -import type { SubscriptionControllerHost } from './subscription-controller'; -import { SubscriptionController } from './subscription-controller'; - -export type QueueControllerHost = SubscriptionControllerHost; - -/** - * Subscribes to queue task changes. - * Triggers host updates when tasks change. - * - * Accepts either a direct store instance or a context that provides one. - * - * @example Direct store - * ```ts - * class MyElement extends LitElement { - * #queue = new QueueController(this, store); - * - * render() { - * const playTask = this.#queue.value.play; - * const isPending = playTask?.status === 'pending'; - * return html``; - * } - * } - * ``` - * - * @example Context source - * ```ts - * const { context } = createStore({ features: [playbackFeature] }); - * - * class MyElement extends LitElement { - * #queue = new QueueController(this, context); - * } - * ``` - */ -export class QueueController { - readonly #sub: SubscriptionController; - - constructor(host: QueueControllerHost, source: StoreSource) { - this.#sub = new SubscriptionController(host, source, { - subscribe: (store, onChange) => store.queue.subscribe(onChange), - getValue: (store) => store.queue.tasks, - }); - } - - get value(): Store['queue']['tasks'] { - return this.#sub.value; - } -} diff --git a/packages/store/src/lit/controllers/tests/queue-controller.test.ts b/packages/store/src/lit/controllers/tests/queue-controller.test.ts deleted file mode 100644 index 4017a1d2..00000000 --- a/packages/store/src/lit/controllers/tests/queue-controller.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { afterEach, describe, expect, it } from 'vitest'; - -import { createCoreTestStore, createTestHost } from '../../tests/test-utils'; -import { QueueController } from '../queue-controller'; - -describe('QueueController', () => { - afterEach(() => { - document.body.innerHTML = ''; - }); - - it('returns tasks record', () => { - const { store } = createCoreTestStore(); - const host = createTestHost(); - - const controller = new QueueController(host, store); - - expect(controller.value).toEqual({}); - }); - - it('updates when task completes', async () => { - const { store } = createCoreTestStore(); - const host = createTestHost(); - - const controller = new QueueController(host, store); - document.body.appendChild(host); - - expect(controller.value.setVolume).toBeUndefined(); - - await store.request.setVolume!(0.5); - - expect(controller.value.setVolume).toBeDefined(); - expect(controller.value.setVolume?.status).toBe('success'); - expect(host.updateCount).toBeGreaterThan(0); - }); - - it('unsubscribes on disconnect', async () => { - const { store } = createCoreTestStore(); - const host = createTestHost(); - - const controller = new QueueController(host, store); - document.body.appendChild(host); - host.remove(); - - const updateCountBefore = host.updateCount; - await store.request.setVolume!(0.5); - - expect(host.updateCount).toBe(updateCountBefore); - }); - - it('handles multiple task updates', async () => { - const { store } = createCoreTestStore(); - const host = createTestHost(); - - const controller = new QueueController(host, store); - document.body.appendChild(host); - - await store.request.setVolume!(0.5); - await store.request.setMuted!(true); - - expect(controller.value.setVolume).toBeDefined(); - expect(controller.value.setMuted).toBeDefined(); - expect(controller.value.setVolume?.status).toBe('success'); - expect(controller.value.setMuted?.status).toBe('success'); - }); - - it('syncs to current tasks on reconnect', async () => { - const { store } = createCoreTestStore(); - const host = createTestHost(); - - const controller = new QueueController(host, store); - document.body.appendChild(host); - - await store.request.setVolume!(0.5); - expect(controller.value.setVolume?.status).toBe('success'); - - host.remove(); - - await store.request.setMuted!(true); - - // Reconnect - document.body.appendChild(host); - - expect(controller.value.setVolume?.status).toBe('success'); - expect(controller.value.setMuted?.status).toBe('success'); - }); -}); diff --git a/packages/store/src/lit/controllers/tests/types.test.ts b/packages/store/src/lit/controllers/tests/types.test.ts index d4748930..cd1e6079 100644 --- a/packages/store/src/lit/controllers/tests/types.test.ts +++ b/packages/store/src/lit/controllers/tests/types.test.ts @@ -1,8 +1,7 @@ import { describe, expectTypeOf, it } from 'vitest'; import { createState } from '../../../core/state'; -import { createCoreTestStore, createTestHost } from '../../tests/test-utils'; -import { QueueController } from '../queue-controller'; +import { createTestHost } from '../../tests/test-utils'; import { SnapshotController } from '../snapshot-controller'; describe('controller types', () => { @@ -30,16 +29,4 @@ describe('controller types', () => { expectTypeOf(controller.value.muted).toEqualTypeOf(); }); }); - - describe('QueueController', () => { - it('value is tasks record', () => { - const { store } = createCoreTestStore(); - const host = createTestHost(); - - const controller = new QueueController(host, store); - - // Value type matches store.queue.tasks - expectTypeOf(controller.value).toMatchTypeOf(store.queue.tasks); - }); - }); }); diff --git a/packages/store/src/lit/create-store.ts b/packages/store/src/lit/create-store.ts index 32e8cf87..c3c348ec 100644 --- a/packages/store/src/lit/create-store.ts +++ b/packages/store/src/lit/create-store.ts @@ -3,18 +3,10 @@ import { ContextConsumer, createContext } from '@lit/context'; import type { ReactiveControllerHost, ReactiveElement } from '@lit/reactive-element'; import { noop } from '@videojs/utils/function'; import type { Constructor } from '@videojs/utils/types'; -import type { - AnyFeature, - UnionFeatureRequests, - UnionFeatureState, - UnionFeatureTarget, - UnionFeatureTasks, -} from '../core/feature'; -import type { TasksRecord } from '../core/queue'; +import type { AnyFeature, UnionFeatureRequests, UnionFeatureState, UnionFeatureTarget } from '../core/feature'; import type { StoreConfig, StoreConsumer, StoreProvider } from '../core/store'; import { Store } from '../core/store'; -import { QueueController as QueueControllerBase } from './controllers'; import { createStoreAttachMixin, createStoreMixin, createStoreProviderMixin } from './mixins'; export const contextKey = Symbol('@videojs/store'); @@ -118,32 +110,6 @@ export interface CreateStoreResult { hostConnected: () => void; hostDisconnected: () => void; }; - - /** - * Queue controller bound to this store's context. - * Subscribes to queue task changes. - * - * @example - * ```ts - * const { QueueController } = createStore({ features: [playbackFeature] }); - * - * class MyElement extends LitElement { - * #queue = new QueueController(this); - * - * render() { - * const playTask = this.#queue.value.play; - * return html``; - * } - * } - * ``` - */ - QueueController: new ( - host: CreateStoreHost - ) => { - value: Readonly>>; - hostConnected: () => void; - hostDisconnected: () => void; - }; } /** @@ -240,12 +206,6 @@ export function createStore( } } - class QueueController extends QueueControllerBase { - constructor(host: CreateStoreHost) { - super(host, context); - } - } - return { StoreMixin, StoreProviderMixin, @@ -253,6 +213,5 @@ export function createStore( context, create, StoreController, - QueueController, }; } diff --git a/packages/store/src/lit/index.ts b/packages/store/src/lit/index.ts index a5a98b99..296e5f7f 100644 --- a/packages/store/src/lit/index.ts +++ b/packages/store/src/lit/index.ts @@ -1,6 +1,5 @@ export type { AsyncStatus } from './controllers'; export { - QueueController, SnapshotController, StoreController, SubscriptionController, diff --git a/packages/store/src/lit/tests/create-store.test.ts b/packages/store/src/lit/tests/create-store.test.ts index 7ba944f0..f7aaf13e 100644 --- a/packages/store/src/lit/tests/create-store.test.ts +++ b/packages/store/src/lit/tests/create-store.test.ts @@ -113,7 +113,6 @@ describe('createStore', () => { expect(result).toHaveProperty('context'); expect(result).toHaveProperty('create'); expect(result).toHaveProperty('StoreController'); - expect(result).toHaveProperty('QueueController'); }); }); @@ -125,13 +124,6 @@ describe('createStore', () => { expect(StoreController.prototype).toBeDefined(); }); - it('QueueController is a class', () => { - const { QueueController } = createStore({ features: [audioFeature] }); - - expect(typeof QueueController).toBe('function'); - expect(QueueController.prototype).toBeDefined(); - }); - // Note: Full integration tests with DOM and context would require // setting up a provider element hierarchy. The bound controllers // work via context, which is tested in integration tests. diff --git a/packages/store/src/react/create-store.tsx b/packages/store/src/react/create-store.tsx index 5b9a74a6..5109cf33 100644 --- a/packages/store/src/react/create-store.tsx +++ b/packages/store/src/react/create-store.tsx @@ -1,14 +1,7 @@ import { isNull, isUndefined } from '@videojs/utils/predicate'; import type { FC, ReactNode } from 'react'; import { useEffect, useMemo, useState, useSyncExternalStore } from 'react'; -import type { - AnyFeature, - UnionFeatureRequests, - UnionFeatureState, - UnionFeatureTarget, - UnionFeatureTasks, -} from '../core/feature'; -import type { TasksRecord } from '../core/queue'; +import type { AnyFeature, UnionFeatureRequests, UnionFeatureState, UnionFeatureTarget } from '../core/feature'; import type { StoreConfig } from '../core/store'; import { Store } from '../core/store'; @@ -53,12 +46,6 @@ export interface CreateStoreResult { */ useStore: () => UseStoreResult; - /** - * Subscribes to queue task changes. - * Returns the current tasks map from the queue. - */ - useQueue: () => TasksRecord>; - /** * Creates a new store instance. * Useful for imperative access or creating a store before render. @@ -87,7 +74,6 @@ export function createStore( config: CreateStoreConfig ): CreateStoreResult { type Target = UnionFeatureTarget; - type Tasks = UnionFeatureTasks; type StoreType = Store; function create(): StoreType { @@ -152,19 +138,9 @@ export function createStore( ); } - function useQueue(): TasksRecord { - const store = useStoreContext() as StoreType; - return useSyncExternalStore( - (cb) => store.queue.subscribe(cb), - () => store.queue.tasks, - () => store.queue.tasks - ); - } - return { Provider, useStore, - useQueue, create, }; } diff --git a/packages/store/src/react/hooks/index.ts b/packages/store/src/react/hooks/index.ts index 94a4b1f9..8af57778 100644 --- a/packages/store/src/react/hooks/index.ts +++ b/packages/store/src/react/hooks/index.ts @@ -1,5 +1,4 @@ export type { AsyncStatus } from '../../shared/types'; -export { useQueue } from './use-queue'; export { useSnapshot } from './use-snapshot'; export { useStore } from './use-store'; diff --git a/packages/store/src/react/hooks/tests/use-queue.test.tsx b/packages/store/src/react/hooks/tests/use-queue.test.tsx deleted file mode 100644 index 1aa992e2..00000000 --- a/packages/store/src/react/hooks/tests/use-queue.test.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { act, renderHook } from '@testing-library/react'; -import { describe, expect, it } from 'vitest'; - -import { useQueue } from '../use-queue'; -import { createTestStore } from './test-utils'; - -describe('useQueue', () => { - it('returns tasks record', () => { - const { store } = createTestStore(); - - const { result } = renderHook(() => useQueue(store)); - - expect(result.current).toEqual({}); - }); - - it('updates when task completes', async () => { - const { store } = createTestStore(); - - const { result } = renderHook(() => useQueue(store)); - - expect(result.current.setVolume).toBeUndefined(); - - await act(async () => { - await store.request.setVolume(0.5); - }); - - expect(result.current.setVolume).toBeDefined(); - expect(result.current.setVolume?.status).toBe('success'); - }); -}); diff --git a/packages/store/src/react/hooks/use-queue.ts b/packages/store/src/react/hooks/use-queue.ts deleted file mode 100644 index 59ecd972..00000000 --- a/packages/store/src/react/hooks/use-queue.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { useSyncExternalStore } from 'react'; -import type { TasksRecord } from '../../core/queue'; -import type { AnyStore, InferStoreTasks } from '../../core/store'; - -/** - * Subscribe to queue task changes. - * - * Returns a record of all tasks keyed by request name. - * Re-renders when any task is added, updated, or removed. - * - * @example - * ```tsx - * function TaskStatus() { - * const tasks = useQueue(store); - * const playTask = tasks.play; - * - * if (playTask?.status === 'pending') { - * return Loading...; - * } - * - * return Ready; - * } - * ``` - */ -export function useQueue(store: Store): TasksRecord> { - return useSyncExternalStore( - (cb) => store.queue.subscribe(cb), - () => store.queue.tasks as TasksRecord>, - () => store.queue.tasks as TasksRecord> - ); -} - -export namespace useQueue { - export type Result = TasksRecord>; -} diff --git a/packages/store/src/react/index.ts b/packages/store/src/react/index.ts index 505e6cec..6a29d3ff 100644 --- a/packages/store/src/react/index.ts +++ b/packages/store/src/react/index.ts @@ -6,4 +6,4 @@ export type { } from './create-store'; export { createStore } from './create-store'; -export { useQueue, useSnapshot, useStore } from './hooks'; +export { useSnapshot, useStore } from './hooks'; diff --git a/packages/store/src/react/tests/create-store.test.tsx b/packages/store/src/react/tests/create-store.test.tsx index f27b1983..37e6d0f6 100644 --- a/packages/store/src/react/tests/create-store.test.tsx +++ b/packages/store/src/react/tests/create-store.test.tsx @@ -124,19 +124,4 @@ describe('createStore', () => { expect(result.current.volume).toBe(0.5); }); }); - - describe('useQueue', () => { - it('returns tasks from context store', () => { - const { Provider, useQueue, create } = createStore({ - features: [audioFeature], - }); - const store = create(); - - const { result } = renderHook(() => useQueue(), { - wrapper: ({ children }: { children: ReactNode }) => {children}, - }); - - expect(result.current).toEqual({}); - }); - }); });