@voltro/client 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import { ClipboardEvent as ClipboardEvent_2 } from 'react';
3
3
  import { Context } from 'react';
4
4
  import { DragEvent as DragEvent_2 } from 'react';
5
5
  import { Effect } from 'effect';
6
+ import { EventDescriptor as EventDescriptor_2 } from '@voltro/protocol';
6
7
  import { Fiber } from 'effect';
7
8
  import { ManagedRuntime } from 'effect';
8
9
  import { ReactNode } from 'react';
@@ -650,6 +651,27 @@ declare type EventMap<E extends ReadonlyArray<EventDescriptor<string, unknown>>>
650
651
  [D in E[number] as D['name']]: D extends EventDescriptor<string, infer A> ? A : never;
651
652
  };
652
653
 
654
+ export declare interface EventMiss {
655
+ /** How many deliveries were lost. */
656
+ readonly count: number;
657
+ readonly reason: EventMissReason;
658
+ }
659
+
660
+ /** Why a subscriber lost deliveries. Both are PROVEN counts, never guesses. */
661
+ export declare type EventMissReason = 'buffer' | 'resume';
662
+
663
+ export declare interface EventState {
664
+ /** `idle` = not subscribed (null key or `skip`); `connecting` = attaching;
665
+ * `live` = the server confirmed the subscription is attached. */
666
+ readonly status: EventStatus;
667
+ /** Total deliveries PROVEN lost on this subscription since it mounted. */
668
+ readonly missed: number;
669
+ /** The most recent loss, with its cause. */
670
+ readonly lastMiss: EventMiss | undefined;
671
+ }
672
+
673
+ export declare type EventStatus = 'idle' | 'connecting' | 'live';
674
+
653
675
  export declare interface EventValidation {
654
676
  readonly valid: boolean;
655
677
  /** `path` → message, empty when valid. */
@@ -733,6 +755,13 @@ export declare interface FrameworkRuntimesProviderProps {
733
755
  readonly children: ReactNode;
734
756
  }
735
757
 
758
+ /** Browser-safe unique idempotency key: prefer `crypto.randomUUID`, fall back to
759
+ * a timestamp+counter for a NON-secure context (a LAN-IP dev server over plain
760
+ * http, where `crypto.randomUUID` is undefined). One key per mutate() call is
761
+ * stable for that call's lifetime — so a transport-level resend of the SAME
762
+ * in-flight request reuses it and the server dedupes. */
763
+ export declare const freshIdempotencyKey: () => string;
764
+
736
765
  /** The registered notifier, if any. */
737
766
  export declare const getMutationNotifier: () => MutationNotifier | undefined;
738
767
 
@@ -791,6 +820,12 @@ export declare interface MutateOptions<Input, Output> {
791
820
  readonly success?: string | ((output: Output, input: Input) => string);
792
821
  readonly error?: string | ((error: unknown, input: Input) => string);
793
822
  };
823
+ /** Idempotency key for this call. Omitted → a fresh one is minted per call
824
+ * (safe against transport-level resends). Pass a STABLE value (e.g. derived
825
+ * from the form/order id) to dedupe higher-level retries too — a double-click
826
+ * or an offline resend of the same logical action then runs exactly once.
827
+ * Only takes effect when the server has `idempotency` configured. */
828
+ readonly idempotencyKey?: string;
794
829
  }
795
830
 
796
831
  export declare interface MutationBuilder<Input, Output> extends MutationState<Input, Output> {
@@ -2192,6 +2227,39 @@ export declare const useDebounced: <T>(value: T, ms?: number) => T;
2192
2227
  */
2193
2228
  export declare const useDerived: <S extends Record<string, unknown>, T>(sources: S, reducer: (sources: S) => T) => T;
2194
2229
 
2230
+ /**
2231
+ * Subscribe to a declared event.
2232
+ *
2233
+ * ```tsx
2234
+ * useEvent(gameStarted, arenaId ? { arenaId } : null, (payload) => {
2235
+ * scene.switchTo('running', payload.gameId)
2236
+ * })
2237
+ * ```
2238
+ *
2239
+ * `payload` is typed from the descriptor — a wrong field name is a `tsc` error
2240
+ * at this call site, and the `key` must structurally match the descriptor's key
2241
+ * schema, so a typo cannot produce a subscription that silently never fires.
2242
+ */
2243
+ export declare function useEvent<Name extends string, Key extends Schema.Schema.Any, Payload extends Schema.Schema.Any>(descriptor: EventDescriptor_2<Name, Key, Payload>, key: Schema.Schema.Type<Key> | null, handler: (payload: Schema.Schema.Type<Payload>) => void, options?: UseEventOptions): EventState;
2244
+
2245
+ export declare interface UseEventOptions {
2246
+ /**
2247
+ * Called when the server can PROVE deliveries were lost — a serial gap while
2248
+ * you were slow to read, or a reconnect older than the server's buffer.
2249
+ *
2250
+ * This is the callback an app builds recovery on: refetch the authoritative
2251
+ * state, re-run the scene, resync the display. It exists because silence is
2252
+ * the one outcome nothing can be built on — a screen cannot tell "nothing
2253
+ * happened" from "I missed the signal", and every comparable product answers
2254
+ * that question by dropping quietly.
2255
+ */
2256
+ readonly onMissed?: (miss: EventMiss) => void;
2257
+ /** Suspend the subscription without unmounting. Same meaning as
2258
+ * `useSubscription`'s `skip`; a `null` key does the same thing. */
2259
+ readonly skip?: boolean;
2260
+ readonly apiName?: string;
2261
+ }
2262
+
2195
2263
  export declare const useFormBinding: <Input extends Record<string, unknown> = Record<string, unknown>, Output = unknown>(apiName: string, mutationTag: string, options: UseFormBindingOptions<Input>) => FormBinding<Input, Output>;
2196
2264
 
2197
2265
  export declare interface UseFormBindingOptions<Input> {
@@ -2495,6 +2563,11 @@ export declare interface WindowSpec {
2495
2563
  readonly bottomSpacer: number;
2496
2564
  }
2497
2565
 
2566
+ /** Attach a per-call `idempotency-key` header to an rpc call, MERGED over the
2567
+ * ambient headers (the auth headers seeded on the runtime) — never replacing
2568
+ * them. The server mutation funnel reads it to dedupe a retried mutation. */
2569
+ export declare const withIdempotencyKey: <A, E, R>(call: Effect.Effect<A, E, R>, key: string) => Effect.Effect<A, E, R>;
2570
+
2498
2571
  export declare interface WorkflowClientMessages {
2499
2572
  readonly signals?: Readonly<Record<string, unknown>>;
2500
2573
  readonly updates?: Readonly<Record<string, {