@lunora/react 1.0.0-alpha.3 → 1.0.0-alpha.31

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.
Files changed (49) hide show
  1. package/LICENSE.md +6 -0
  2. package/README.md +2 -0
  3. package/__assets__/package-og.svg +1 -1
  4. package/dist/index.d.mts +915 -276
  5. package/dist/index.d.ts +915 -276
  6. package/dist/index.mjs +27 -15
  7. package/dist/packem_shared/{AuthLoading-DtKgZT2Z.mjs → AuthLoading-DezUWNB2.mjs} +1 -1
  8. package/dist/packem_shared/{CheckoutButton-CVSry8U1.mjs → CheckoutButton-DUite8jJ.mjs} +8 -4
  9. package/dist/packem_shared/{LunoraProvider-D38Xp16l.mjs → LunoraProvider-BsuiW4Lk.mjs} +3 -2
  10. package/dist/packem_shared/{cache-CItk3fgN.mjs → cache-JeuDAXfE.mjs} +6 -1
  11. package/dist/packem_shared/hydratePreloaded-2omLtadR.mjs +54 -0
  12. package/dist/packem_shared/{lunoraQueryOptions-CsuWzjg1.mjs → lunoraQueryOptions-CefbPBId.mjs} +1 -1
  13. package/dist/packem_shared/query-key-LGnArBTB.mjs +13 -0
  14. package/dist/packem_shared/query-options.d-CdgGQ9s4.d.mts +38 -0
  15. package/dist/packem_shared/query-options.d-CdgGQ9s4.d.ts +38 -0
  16. package/dist/packem_shared/stable-key-DePnevIy.mjs +38 -0
  17. package/dist/packem_shared/{use-paginated-core-CoOfcc-p.mjs → use-paginated-core-xxvd1YA0.mjs} +37 -19
  18. package/dist/packem_shared/useAgent-BNLlIYHz.mjs +101 -0
  19. package/dist/packem_shared/useAgentChat-0cebQe7-.mjs +304 -0
  20. package/dist/packem_shared/useAgentState-Cqyd3Dfy.mjs +37 -0
  21. package/dist/packem_shared/useAgentToolEvents-gF7U4_KY.mjs +129 -0
  22. package/dist/packem_shared/{useAuth-CNUKtOOp.mjs → useAuth-BSutjJaa.mjs} +1 -1
  23. package/dist/packem_shared/{useAuthState-BiGhtSCs.mjs → useAuthState-CyF35qZR.mjs} +1 -1
  24. package/dist/packem_shared/useClientQuery-DIkNT4QA.mjs +17 -0
  25. package/dist/packem_shared/{useConnectionStatus-DRSY9ldm.mjs → useConnectionStatus-PJ7vyCHy.mjs} +1 -1
  26. package/dist/packem_shared/useFlag-Beyeiq2b.mjs +128 -0
  27. package/dist/packem_shared/useHttpStream-oc4s1pMy.mjs +127 -0
  28. package/dist/packem_shared/{useInfiniteQuery-MH0x4l8h.mjs → useInfiniteQuery-CJNw1XaZ.mjs} +1 -1
  29. package/dist/packem_shared/{useMutation-CrvMXRsk.mjs → useMutation-BeqeIjTr.mjs} +1 -1
  30. package/dist/packem_shared/useMutator-IIrLtDiM.mjs +47 -0
  31. package/dist/packem_shared/{usePaginatedQuery-D3PTDRGS.mjs → usePaginatedQuery-DWzydaVR.mjs} +1 -1
  32. package/dist/packem_shared/{usePresence-D7jLuxj0.mjs → usePresence-Rnx1Fznc.mjs} +13 -6
  33. package/dist/packem_shared/useQuery-CE8_QUgh.mjs +77 -0
  34. package/dist/packem_shared/{useStream-BRY9nemd.mjs → useStream-GYNgc9J5.mjs} +6 -3
  35. package/dist/packem_shared/{useSubscription-CHMCjyQg.mjs → useSubscription-DcDlvVuI.mjs} +3 -3
  36. package/dist/packem_shared/useVoiceAgent-w7fzAMSB.mjs +422 -0
  37. package/dist/packem_shared/wire-key-Bg8BJ8YM.mjs +101 -0
  38. package/dist/server.d.mts +29 -29
  39. package/dist/server.d.ts +29 -29
  40. package/dist/server.mjs +2 -2
  41. package/dist/upload.d.mts +2 -0
  42. package/dist/upload.d.ts +2 -0
  43. package/dist/upload.mjs +3 -0
  44. package/package.json +11 -5
  45. package/dist/packem_shared/hydratePreloaded-BlFL9FGq.mjs +0 -46
  46. package/dist/packem_shared/query-key-C5rufkEE.mjs +0 -21
  47. package/dist/packem_shared/query-options.d-D4okOpO8.d.mts +0 -38
  48. package/dist/packem_shared/query-options.d-D4okOpO8.d.ts +0 -38
  49. package/dist/packem_shared/useQuery-C5S0W-7K.mjs +0 -41
@@ -0,0 +1,304 @@
1
+ 'use client';
2
+ import { c } from 'react/compiler-runtime';
3
+ import { useState, useRef } from 'react';
4
+ import { useMutation } from './useMutation-BeqeIjTr.mjs';
5
+ import { useStream } from './useStream-GYNgc9J5.mjs';
6
+ import useSubscription from './useSubscription-DcDlvVuI.mjs';
7
+
8
+ const NO_MUTATION_REF = {
9
+ __lunoraRef: ""
10
+ };
11
+ const NO_STREAM_REF = {
12
+ __lunoraRef: ""
13
+ };
14
+ const EMPTY_MESSAGES = [];
15
+ const reconcileOptimistic = (optimistic, durable) => {
16
+ const durableUserRows = durable.filter((message) => message.role === "user");
17
+ const consumed = /* @__PURE__ */ new Set();
18
+ return optimistic.filter((pending) => {
19
+ for (let index = pending.durableUserCountAtSend; index < durableUserRows.length; index += 1) {
20
+ const row = durableUserRows[index];
21
+ if (row !== void 0 && !consumed.has(index) && row.content === pending.content) {
22
+ consumed.add(index);
23
+ return false;
24
+ }
25
+ }
26
+ return true;
27
+ });
28
+ };
29
+ const useAgentChat = (options) => {
30
+ const $ = c(49);
31
+ const {
32
+ api,
33
+ cancel: cancelReference,
34
+ limit,
35
+ send: sendReference,
36
+ sendArgs,
37
+ stream: streamReference,
38
+ threadKey
39
+ } = options;
40
+ let t0;
41
+ if ($[0] !== limit || $[1] !== threadKey) {
42
+ t0 = limit === void 0 ? {
43
+ key: threadKey
44
+ } : {
45
+ key: threadKey,
46
+ limit
47
+ };
48
+ $[0] = limit;
49
+ $[1] = threadKey;
50
+ $[2] = t0;
51
+ } else {
52
+ t0 = $[2];
53
+ }
54
+ const messagesArguments = t0;
55
+ const {
56
+ data: history
57
+ } = useSubscription(api.agents.agentMessages, messagesArguments);
58
+ let t1;
59
+ if ($[3] !== threadKey) {
60
+ t1 = {
61
+ key: threadKey
62
+ };
63
+ $[3] = threadKey;
64
+ $[4] = t1;
65
+ } else {
66
+ t1 = $[4];
67
+ }
68
+ const {
69
+ data: threadData
70
+ } = useSubscription(api.agents.agentThread, t1);
71
+ let t2;
72
+ if ($[5] !== streamReference || $[6] !== threadKey) {
73
+ t2 = streamReference === void 0 ? "skip" : {
74
+ key: threadKey
75
+ };
76
+ $[5] = streamReference;
77
+ $[6] = threadKey;
78
+ $[7] = t2;
79
+ } else {
80
+ t2 = $[7];
81
+ }
82
+ const streamArguments = t2;
83
+ const {
84
+ chunks
85
+ } = useStream(streamReference ?? NO_STREAM_REF, streamArguments);
86
+ const sendMutation = useMutation(sendReference);
87
+ const cancelMutation = useMutation(cancelReference ?? NO_MUTATION_REF);
88
+ const approvalMutation = useMutation(api.agents.agentResolveApproval);
89
+ let t3;
90
+ if ($[8] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
91
+ t3 = [];
92
+ $[8] = t3;
93
+ } else {
94
+ t3 = $[8];
95
+ }
96
+ const [optimistic, setOptimistic] = useState(t3);
97
+ const nextIdRef = useRef(0);
98
+ const thread = threadData;
99
+ const status = thread?.status;
100
+ const instanceId = thread?.instanceId;
101
+ const durable = history ?? EMPTY_MESSAGES;
102
+ let t4;
103
+ if ($[9] !== durable || $[10] !== optimistic) {
104
+ const visibleOptimistic = reconcileOptimistic(optimistic, durable);
105
+ let maxDurableSeq;
106
+ if ($[12] !== durable) {
107
+ maxDurableSeq = -1;
108
+ for (const message of durable) {
109
+ if (message.seq > maxDurableSeq) {
110
+ maxDurableSeq = message.seq;
111
+ }
112
+ }
113
+ $[12] = durable;
114
+ $[13] = maxDurableSeq;
115
+ } else {
116
+ maxDurableSeq = $[13];
117
+ }
118
+ t4 = visibleOptimistic.length === 0 ? durable : [...durable, ...visibleOptimistic.map((pending, index) => ({
119
+ content: pending.content,
120
+ optimistic: true,
121
+ role: "user",
122
+ seq: maxDurableSeq + 1 + index
123
+ }))];
124
+ $[9] = durable;
125
+ $[10] = optimistic;
126
+ $[11] = t4;
127
+ } else {
128
+ t4 = $[11];
129
+ }
130
+ const messages = t4;
131
+ let t5;
132
+ if ($[14] !== durable) {
133
+ t5 = durable.filter(_temp);
134
+ $[14] = durable;
135
+ $[15] = t5;
136
+ } else {
137
+ t5 = $[15];
138
+ }
139
+ const assistantCount = t5.length;
140
+ let t6;
141
+ if ($[16] !== assistantCount || $[17] !== chunks || $[18] !== threadKey) {
142
+ let t72;
143
+ if ($[20] !== assistantCount || $[21] !== threadKey) {
144
+ t72 = (event) => event.kind !== "progress" && event.threadKey === threadKey && event.turn >= assistantCount;
145
+ $[20] = assistantCount;
146
+ $[21] = threadKey;
147
+ $[22] = t72;
148
+ } else {
149
+ t72 = $[22];
150
+ }
151
+ t6 = chunks.filter(t72).map(_temp2).join("");
152
+ $[16] = assistantCount;
153
+ $[17] = chunks;
154
+ $[18] = threadKey;
155
+ $[19] = t6;
156
+ } else {
157
+ t6 = $[19];
158
+ }
159
+ const streamingText = t6;
160
+ const {
161
+ mutate: sendMutate
162
+ } = sendMutation;
163
+ const {
164
+ mutate: cancelMutate
165
+ } = cancelMutation;
166
+ const {
167
+ mutate: resolveMutate
168
+ } = approvalMutation;
169
+ let t7;
170
+ if ($[23] !== durable || $[24] !== sendArgs || $[25] !== sendMutate || $[26] !== threadKey) {
171
+ t7 = async (input, args) => {
172
+ const id = nextIdRef.current;
173
+ nextIdRef.current = nextIdRef.current + 1;
174
+ const durableUserCountAtSend = durable.filter(_temp3).length;
175
+ setOptimistic((previous) => [...reconcileOptimistic(previous, durable), {
176
+ content: input,
177
+ durableUserCountAtSend,
178
+ id
179
+ }]);
180
+ try {
181
+ await sendMutate({
182
+ input,
183
+ threadKey,
184
+ ...sendArgs,
185
+ ...args
186
+ });
187
+ } catch (t82) {
188
+ const error = t82;
189
+ setOptimistic((previous_0) => previous_0.filter((pending_0) => pending_0.id !== id));
190
+ throw error;
191
+ }
192
+ };
193
+ $[23] = durable;
194
+ $[24] = sendArgs;
195
+ $[25] = sendMutate;
196
+ $[26] = threadKey;
197
+ $[27] = t7;
198
+ } else {
199
+ t7 = $[27];
200
+ }
201
+ const send = t7;
202
+ let t8;
203
+ if ($[28] !== instanceId || $[29] !== resolveMutate || $[30] !== threadKey) {
204
+ t8 = async (toolCallId, note) => {
205
+ if (instanceId === void 0) {
206
+ throw new Error("useAgentChat: cannot approve — no in-flight run (thread has no instanceId)");
207
+ }
208
+ await resolveMutate({
209
+ decision: "approve",
210
+ instanceId,
211
+ threadKey,
212
+ toolCallId,
213
+ ...note === void 0 ? {} : {
214
+ note
215
+ }
216
+ });
217
+ };
218
+ $[28] = instanceId;
219
+ $[29] = resolveMutate;
220
+ $[30] = threadKey;
221
+ $[31] = t8;
222
+ } else {
223
+ t8 = $[31];
224
+ }
225
+ const approve = t8;
226
+ let t9;
227
+ if ($[32] !== instanceId || $[33] !== resolveMutate || $[34] !== threadKey) {
228
+ t9 = async (toolCallId_0, note_0) => {
229
+ if (instanceId === void 0) {
230
+ throw new Error("useAgentChat: cannot reject — no in-flight run (thread has no instanceId)");
231
+ }
232
+ await resolveMutate({
233
+ decision: "reject",
234
+ instanceId,
235
+ threadKey,
236
+ toolCallId: toolCallId_0,
237
+ ...note_0 === void 0 ? {} : {
238
+ note: note_0
239
+ }
240
+ });
241
+ };
242
+ $[32] = instanceId;
243
+ $[33] = resolveMutate;
244
+ $[34] = threadKey;
245
+ $[35] = t9;
246
+ } else {
247
+ t9 = $[35];
248
+ }
249
+ const reject = t9;
250
+ let t10;
251
+ if ($[36] !== cancelMutate || $[37] !== cancelReference || $[38] !== instanceId || $[39] !== threadKey) {
252
+ t10 = async () => {
253
+ if (cancelReference === void 0 || instanceId === void 0) {
254
+ return;
255
+ }
256
+ await cancelMutate({
257
+ instanceId,
258
+ threadKey
259
+ });
260
+ };
261
+ $[36] = cancelMutate;
262
+ $[37] = cancelReference;
263
+ $[38] = instanceId;
264
+ $[39] = threadKey;
265
+ $[40] = t10;
266
+ } else {
267
+ t10 = $[40];
268
+ }
269
+ const cancel = t10;
270
+ let t11;
271
+ if ($[41] !== approve || $[42] !== cancel || $[43] !== messages || $[44] !== reject || $[45] !== send || $[46] !== status || $[47] !== streamingText) {
272
+ t11 = {
273
+ approve,
274
+ cancel,
275
+ messages,
276
+ reject,
277
+ send,
278
+ status,
279
+ streamingText
280
+ };
281
+ $[41] = approve;
282
+ $[42] = cancel;
283
+ $[43] = messages;
284
+ $[44] = reject;
285
+ $[45] = send;
286
+ $[46] = status;
287
+ $[47] = streamingText;
288
+ $[48] = t11;
289
+ } else {
290
+ t11 = $[48];
291
+ }
292
+ return t11;
293
+ };
294
+ function _temp(message_0) {
295
+ return message_0.role === "assistant";
296
+ }
297
+ function _temp2(delta) {
298
+ return delta.text;
299
+ }
300
+ function _temp3(message_1) {
301
+ return message_1.role === "user";
302
+ }
303
+
304
+ export { useAgentChat };
@@ -0,0 +1,37 @@
1
+ 'use client';
2
+ import { c } from 'react/compiler-runtime';
3
+ import useSubscription from './useSubscription-DcDlvVuI.mjs';
4
+
5
+ const useAgentState = (options) => {
6
+ const $ = c(5);
7
+ let t0;
8
+ if ($[0] !== options.threadKey) {
9
+ t0 = {
10
+ key: options.threadKey
11
+ };
12
+ $[0] = options.threadKey;
13
+ $[1] = t0;
14
+ } else {
15
+ t0 = $[1];
16
+ }
17
+ const {
18
+ data,
19
+ error
20
+ } = useSubscription(options.api.agents.agentState, t0);
21
+ const t1 = data;
22
+ let t2;
23
+ if ($[2] !== error || $[3] !== t1) {
24
+ t2 = {
25
+ error,
26
+ state: t1
27
+ };
28
+ $[2] = error;
29
+ $[3] = t1;
30
+ $[4] = t2;
31
+ } else {
32
+ t2 = $[4];
33
+ }
34
+ return t2;
35
+ };
36
+
37
+ export { useAgentState };
@@ -0,0 +1,129 @@
1
+ 'use client';
2
+ import { c } from 'react/compiler-runtime';
3
+ import { useStream } from './useStream-GYNgc9J5.mjs';
4
+ import useSubscription from './useSubscription-DcDlvVuI.mjs';
5
+
6
+ const NO_STREAM_REF = {
7
+ __lunoraRef: ""
8
+ };
9
+ const EMPTY_MESSAGES = [];
10
+ const toDurableEvent = (message) => {
11
+ if (message.role === "assistant" && message.toolCalls) {
12
+ return message.toolCalls.map((call) => {
13
+ return {
14
+ input: call.input,
15
+ seq: message.seq,
16
+ toolCallId: call.id,
17
+ toolName: call.name,
18
+ type: "call"
19
+ };
20
+ });
21
+ }
22
+ if (message.role !== "tool") {
23
+ return void 0;
24
+ }
25
+ if (message.status === "awaiting_approval") {
26
+ return [{
27
+ seq: message.seq,
28
+ type: "awaiting-approval",
29
+ ...message.toolCallId === void 0 ? {} : {
30
+ toolCallId: message.toolCallId
31
+ },
32
+ ...message.toolName === void 0 ? {} : {
33
+ toolName: message.toolName
34
+ }
35
+ }];
36
+ }
37
+ return [{
38
+ output: message.content,
39
+ seq: message.seq,
40
+ type: "result",
41
+ ...message.status === "approved" || message.status === "rejected" ? {
42
+ status: message.status
43
+ } : {},
44
+ ...message.toolCallId === void 0 ? {} : {
45
+ toolCallId: message.toolCallId
46
+ },
47
+ ...message.toolName === void 0 ? {} : {
48
+ toolName: message.toolName
49
+ }
50
+ }];
51
+ };
52
+ const useAgentToolEvents = (options) => {
53
+ const $ = c(12);
54
+ const {
55
+ api,
56
+ limit,
57
+ stream: streamReference,
58
+ threadKey
59
+ } = options;
60
+ let t0;
61
+ if ($[0] !== limit || $[1] !== threadKey) {
62
+ t0 = limit === void 0 ? {
63
+ key: threadKey
64
+ } : {
65
+ key: threadKey,
66
+ limit
67
+ };
68
+ $[0] = limit;
69
+ $[1] = threadKey;
70
+ $[2] = t0;
71
+ } else {
72
+ t0 = $[2];
73
+ }
74
+ const messagesArguments = t0;
75
+ const {
76
+ data: history
77
+ } = useSubscription(api.agents.agentMessages, messagesArguments);
78
+ let t1;
79
+ if ($[3] !== streamReference || $[4] !== threadKey) {
80
+ t1 = streamReference === void 0 ? "skip" : {
81
+ key: threadKey
82
+ };
83
+ $[3] = streamReference;
84
+ $[4] = threadKey;
85
+ $[5] = t1;
86
+ } else {
87
+ t1 = $[5];
88
+ }
89
+ const streamArguments = t1;
90
+ const {
91
+ chunks
92
+ } = useStream(streamReference ?? NO_STREAM_REF, streamArguments);
93
+ const durable = history ?? EMPTY_MESSAGES;
94
+ let events;
95
+ if ($[6] !== chunks || $[7] !== durable || $[8] !== threadKey) {
96
+ events = durable.flatMap(_temp);
97
+ for (const event of chunks) {
98
+ if (event.kind === "progress" && event.threadKey === threadKey) {
99
+ events.push({
100
+ data: event.data,
101
+ toolCallId: event.toolCallId,
102
+ type: "progress"
103
+ });
104
+ }
105
+ }
106
+ $[6] = chunks;
107
+ $[7] = durable;
108
+ $[8] = threadKey;
109
+ $[9] = events;
110
+ } else {
111
+ events = $[9];
112
+ }
113
+ let t2;
114
+ if ($[10] !== events) {
115
+ t2 = {
116
+ events
117
+ };
118
+ $[10] = events;
119
+ $[11] = t2;
120
+ } else {
121
+ t2 = $[11];
122
+ }
123
+ return t2;
124
+ };
125
+ function _temp(message) {
126
+ return toDurableEvent(message) ?? [];
127
+ }
128
+
129
+ export { useAgentToolEvents };
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { c } from 'react/compiler-runtime';
3
3
  import { useSyncExternalStore } from 'react';
4
- import { useLunora } from './LunoraProvider-D38Xp16l.mjs';
4
+ import { useLunora } from './LunoraProvider-BsuiW4Lk.mjs';
5
5
 
6
6
  const stores = /* @__PURE__ */ new WeakMap();
7
7
  const createStore = (client) => {
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { c } from 'react/compiler-runtime';
3
3
  import { useSyncExternalStore } from 'react';
4
- import useAuth from './useAuth-CNUKtOOp.mjs';
4
+ import useAuth from './useAuth-BSutjJaa.mjs';
5
5
 
6
6
  const subscribe = () => () => void 0;
7
7
  const useAuthState = () => {
@@ -0,0 +1,17 @@
1
+ 'use client';
2
+ import { useCallback, useSyncExternalStore } from 'react';
3
+ import { useLunora } from './LunoraProvider-BsuiW4Lk.mjs';
4
+
5
+ const useClientQuery = (ref) => {
6
+ const client = useLunora();
7
+ const subscribe = useCallback((onStoreChange) => client.subscribeClientQuery(ref, () => {
8
+ onStoreChange();
9
+ }), [client, ref.key]);
10
+ const value = useSyncExternalStore(subscribe, () => client.getClientQuery(ref), () => client.getClientQuery(ref));
11
+ const setter = useCallback((next) => {
12
+ client.setClientQuery(ref, next);
13
+ }, [client, ref]);
14
+ return [value, setter];
15
+ };
16
+
17
+ export { useClientQuery as default };
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { c } from 'react/compiler-runtime';
3
3
  import { useSyncExternalStore } from 'react';
4
- import { useLunora } from './LunoraProvider-D38Xp16l.mjs';
4
+ import { useLunora } from './LunoraProvider-BsuiW4Lk.mjs';
5
5
 
6
6
  const useConnectionStatus = () => {
7
7
  const $ = c(4);
@@ -0,0 +1,128 @@
1
+ 'use client';
2
+ import { useState, useRef, useEffect } from 'react';
3
+ import { useLunora } from './LunoraProvider-BsuiW4Lk.mjs';
4
+ import { s as stableStringify } from './stable-key-DePnevIy.mjs';
5
+
6
+ const FLAGS_EVAL_PATH = "__lunora_flags__:eval";
7
+ const flagKind = (value) => {
8
+ const kind = typeof value;
9
+ if (kind === "boolean" || kind === "number" || kind === "string") {
10
+ return kind;
11
+ }
12
+ return "object";
13
+ };
14
+ const flagsReference = {
15
+ __lunoraRef: FLAGS_EVAL_PATH
16
+ };
17
+ const useFlag = (key, defaultValue, context) => {
18
+ const client = useLunora();
19
+ const [value, setValue] = useState(defaultValue);
20
+ const type = flagKind(defaultValue);
21
+ const serializedContext = context === void 0 ? "" : stableStringify(context);
22
+ const resetKey = `${key}::${type}::${serializedContext}`;
23
+ const resetKeyRef = useRef(resetKey);
24
+ if (resetKeyRef.current !== resetKey) {
25
+ resetKeyRef.current = resetKey;
26
+ setValue(defaultValue);
27
+ }
28
+ const latest = useRef({
29
+ context,
30
+ defaultValue
31
+ });
32
+ useEffect(() => {
33
+ latest.current = {
34
+ context,
35
+ defaultValue
36
+ };
37
+ });
38
+ useEffect(() => {
39
+ let cancelled = false;
40
+ const {
41
+ context: currentContext,
42
+ defaultValue: currentDefault
43
+ } = latest.current;
44
+ setValue(currentDefault);
45
+ let unsubscribe;
46
+ try {
47
+ unsubscribe = client.subscribe(flagsReference, {
48
+ context: currentContext,
49
+ default: currentDefault,
50
+ key,
51
+ type
52
+ }, (next) => {
53
+ if (!cancelled) {
54
+ setValue(next);
55
+ }
56
+ });
57
+ } catch {
58
+ return () => {
59
+ cancelled = true;
60
+ };
61
+ }
62
+ return () => {
63
+ cancelled = true;
64
+ unsubscribe();
65
+ };
66
+ }, [client, key, type, serializedContext]);
67
+ return value;
68
+ };
69
+ const useFlags = (flags, context) => {
70
+ const client = useLunora();
71
+ const [values, setValues] = useState(flags);
72
+ const spec = stableStringify(flags);
73
+ const serializedContext = context === void 0 ? "" : stableStringify(context);
74
+ const resetKey = `${spec}::${serializedContext}`;
75
+ const resetKeyRef = useRef(resetKey);
76
+ if (resetKeyRef.current !== resetKey) {
77
+ resetKeyRef.current = resetKey;
78
+ setValues(flags);
79
+ }
80
+ const latest = useRef({
81
+ context,
82
+ flags
83
+ });
84
+ useEffect(() => {
85
+ latest.current = {
86
+ context,
87
+ flags
88
+ };
89
+ });
90
+ useEffect(() => {
91
+ let cancelled = false;
92
+ const {
93
+ context: currentContext,
94
+ flags: currentFlags
95
+ } = latest.current;
96
+ setValues(currentFlags);
97
+ const unsubscribes = [];
98
+ for (const [key, defaultValue] of Object.entries(currentFlags)) {
99
+ try {
100
+ unsubscribes.push(client.subscribe(flagsReference, {
101
+ context: currentContext,
102
+ default: defaultValue,
103
+ key,
104
+ type: flagKind(defaultValue)
105
+ }, (next) => {
106
+ if (!cancelled) {
107
+ setValues((previous) => {
108
+ return {
109
+ ...previous,
110
+ [key]: next
111
+ };
112
+ });
113
+ }
114
+ }));
115
+ } catch {
116
+ }
117
+ }
118
+ return () => {
119
+ cancelled = true;
120
+ for (const unsubscribe of unsubscribes) {
121
+ unsubscribe();
122
+ }
123
+ };
124
+ }, [client, spec, serializedContext]);
125
+ return values;
126
+ };
127
+
128
+ export { useFlag, useFlags };