diff --git a/crates/bindings-typescript/src/vue/index.ts b/crates/bindings-typescript/src/vue/index.ts index b32fbdf4b80..3b3e64aba48 100644 --- a/crates/bindings-typescript/src/vue/index.ts +++ b/crates/bindings-typescript/src/vue/index.ts @@ -2,3 +2,4 @@ export * from './SpacetimeDBProvider.ts'; export { useSpacetimeDB } from './useSpacetimeDB.ts'; export { useTable } from './useTable.ts'; export { useReducer } from './useReducer.ts'; +export { useProcedure } from './useProcedure.ts'; diff --git a/crates/bindings-typescript/src/vue/useProcedure.ts b/crates/bindings-typescript/src/vue/useProcedure.ts new file mode 100644 index 00000000000..385b0c96ae8 --- /dev/null +++ b/crates/bindings-typescript/src/vue/useProcedure.ts @@ -0,0 +1,62 @@ +import { shallowRef, watch, onUnmounted } from 'vue'; +import { useSpacetimeDB } from './useSpacetimeDB'; +import type { UntypedProcedureDef } from '../sdk/procedures'; +import type { + ProcedureParamsType, + ProcedureReturnType, +} from '../sdk/type_utils'; + +export function useProcedure( + procedureDef: ProcedureDef +): ( + ...params: ProcedureParamsType +) => Promise> { + const conn = useSpacetimeDB(); + const procedureName = procedureDef.accessorName; + + const queueRef = shallowRef< + { + params: ProcedureParamsType; + resolve: (val: any) => void; + reject: (err: unknown) => void; + }[] + >([]); + + const stopWatch = watch( + () => conn.isActive, + () => { + const connection = conn.getConnection(); + if (!connection) return; + + const fn = (connection.procedures as any)[procedureName] as ( + ...p: ProcedureParamsType + ) => Promise>; + if (queueRef.value.length) { + const pending = queueRef.value.splice(0); + for (const item of pending) { + fn(...item.params).then(item.resolve, item.reject); + } + } + }, + { immediate: true } + ); + + onUnmounted(() => { + stopWatch(); + }); + + return (...params: ProcedureParamsType) => { + const connection = conn.getConnection(); + if (!connection) { + return new Promise>( + (resolve, reject) => { + queueRef.value.push({ params, resolve, reject }); + } + ); + } + const fn = (connection.procedures as any)[procedureName] as ( + ...p: ProcedureParamsType + ) => Promise>; + return fn(...params); + }; +}