// Builds lazy native approval runtime adapters. import { createLazyRuntimeModule } from "../shared/lazy-runtime.js"; import type { ChannelApprovalNativeAvailabilityAdapter, ChannelApprovalNativeRuntimeAdapter, } from "./approval-handler-runtime-types.js"; import type { ChannelApprovalKind } from "./approval-types.js"; /** Runtime-context capability key used by channels to register native approval resources. */ export const CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY = "approval.native"; /** Creates an approval runtime adapter that loads heavy channel code only when delivery hooks run. */ export function createLazyChannelApprovalNativeRuntimeAdapter< TPendingPayload = unknown, TPreparedTarget = unknown, TPendingEntry = unknown, TBinding = unknown, TFinalPayload = unknown, TCapabilityBoundary extends boolean = false, >(params: { load: () => Promise< ChannelApprovalNativeRuntimeAdapter< TPendingPayload, TPreparedTarget, TPendingEntry, TBinding, TFinalPayload > >; isConfigured: ChannelApprovalNativeAvailabilityAdapter["isConfigured"]; shouldHandle: ChannelApprovalNativeAvailabilityAdapter["shouldHandle"]; eventKinds?: readonly ChannelApprovalKind[]; /** Erases payload types only when registering with the non-generic channel capability. */ capabilityBoundary?: TCapabilityBoundary; /** @deprecated Trusted compatibility override; omit to derive ownership from the payload. */ resolveApprovalKind?: ChannelApprovalNativeRuntimeAdapter["resolveApprovalKind"]; }): TCapabilityBoundary extends true ? ChannelApprovalNativeRuntimeAdapter : ChannelApprovalNativeRuntimeAdapter< TPendingPayload, TPreparedTarget, TPendingEntry, TBinding, TFinalPayload > { const loadRuntime = createLazyRuntimeModule(params.load); let loadedRuntime: ChannelApprovalNativeRuntimeAdapter< TPendingPayload, TPreparedTarget, TPendingEntry, TBinding, TFinalPayload > | null = null; const loadResolvedRuntime = async (): Promise< ChannelApprovalNativeRuntimeAdapter< TPendingPayload, TPreparedTarget, TPendingEntry, TBinding, TFinalPayload > > => { const runtime = await loadRuntime(); loadedRuntime = runtime; return runtime; }; const loadRequired = async ( select: ( runtime: ChannelApprovalNativeRuntimeAdapter< TPendingPayload, TPreparedTarget, TPendingEntry, TBinding, TFinalPayload >, ) => TResult, ): Promise => select(await loadResolvedRuntime()); const loadOptional = async ( select: ( runtime: ChannelApprovalNativeRuntimeAdapter< TPendingPayload, TPreparedTarget, TPendingEntry, TBinding, TFinalPayload >, ) => TResult | undefined, ): Promise => select(await loadResolvedRuntime()); return { ...(params.eventKinds ? { eventKinds: params.eventKinds } : {}), ...(params.resolveApprovalKind ? { resolveApprovalKind: params.resolveApprovalKind } : {}), availability: { isConfigured: params.isConfigured, shouldHandle: params.shouldHandle, }, presentation: { buildPendingPayload: async (runtimeParams) => (await loadRequired((runtime) => runtime.presentation.buildPendingPayload))(runtimeParams), buildResolvedResult: async (runtimeParams) => (await loadRequired((runtime) => runtime.presentation.buildResolvedResult))(runtimeParams), buildExpiredResult: async (runtimeParams) => (await loadRequired((runtime) => runtime.presentation.buildExpiredResult))(runtimeParams), }, transport: { prepareTarget: async (runtimeParams) => (await loadRequired((runtime) => runtime.transport.prepareTarget))(runtimeParams), deliverPending: async (runtimeParams) => (await loadRequired((runtime) => runtime.transport.deliverPending))(runtimeParams), updateEntry: async (runtimeParams) => await ( await loadOptional((runtime) => runtime.transport.updateEntry) )?.(runtimeParams), deleteEntry: async (runtimeParams) => await ( await loadOptional((runtime) => runtime.transport.deleteEntry) )?.(runtimeParams), }, interactions: { bindPending: async (runtimeParams) => (await loadOptional((runtime) => runtime.interactions?.bindPending))?.(runtimeParams) ?? null, unbindPending: async (runtimeParams) => await ( await loadOptional((runtime) => runtime.interactions?.unbindPending) )?.(runtimeParams), clearPendingActions: async (runtimeParams) => await ( await loadOptional((runtime) => runtime.interactions?.clearPendingActions) )?.(runtimeParams), cancelDelivered: async (runtimeParams) => await ( await loadOptional((runtime) => runtime.interactions?.cancelDelivered) )?.(runtimeParams), }, observe: { // Observe hooks are fire-and-forget at call sites. Reuse the already // loaded runtime instead of introducing unawaited lazy-load promises. onDeliveryError: (runtimeParams) => loadedRuntime?.observe?.onDeliveryError?.(runtimeParams), onDuplicateSkipped: (runtimeParams) => loadedRuntime?.observe?.onDuplicateSkipped?.(runtimeParams), onDelivered: (runtimeParams) => loadedRuntime?.observe?.onDelivered?.(runtimeParams), }, // `capabilityBoundary` opts into the non-generic registration contract; // otherwise this object preserves every type inferred from `load`. // SAFETY: the conditional return type selects exactly those two representations. } satisfies ChannelApprovalNativeRuntimeAdapter< TPendingPayload, TPreparedTarget, TPendingEntry, TBinding, TFinalPayload > as never; // SAFETY: the conditional return selects typed or capability-boundary form. }