File size: 6,004 Bytes
25d91a4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// 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 <TResult>(
    select: (
      runtime: ChannelApprovalNativeRuntimeAdapter<
        TPendingPayload,
        TPreparedTarget,
        TPendingEntry,
        TBinding,
        TFinalPayload
      >,
    ) => TResult,
  ): Promise<TResult> => select(await loadResolvedRuntime());
  const loadOptional = async <TResult>(
    select: (
      runtime: ChannelApprovalNativeRuntimeAdapter<
        TPendingPayload,
        TPreparedTarget,
        TPendingEntry,
        TBinding,
        TFinalPayload
      >,
    ) => TResult | undefined,
  ): Promise<TResult | undefined> => 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.
}