deepspace 0.4.2 → 0.4.4

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.js CHANGED
@@ -4888,6 +4888,9 @@ async function request(method, endpoint, body, options) {
4888
4888
  } catch {
4889
4889
  }
4890
4890
  const controller = new AbortController();
4891
+ const abortFromCaller = () => controller.abort();
4892
+ if (options?.signal?.aborted) controller.abort();
4893
+ else options?.signal?.addEventListener("abort", abortFromCaller, { once: true });
4891
4894
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
4892
4895
  try {
4893
4896
  const res = await fetch(url, {
@@ -4924,6 +4927,7 @@ async function request(method, endpoint, body, options) {
4924
4927
  };
4925
4928
  } finally {
4926
4929
  clearTimeout(timeout);
4930
+ options?.signal?.removeEventListener("abort", abortFromCaller);
4927
4931
  }
4928
4932
  }
4929
4933
  var integration = {
@@ -4950,6 +4954,236 @@ var integration = {
4950
4954
  }
4951
4955
  };
4952
4956
 
4957
+ // src/client/voice/useVoiceAgent.ts
4958
+ import { useCallback as useCallback26, useEffect as useEffect20, useRef as useRef17, useState as useState17 } from "react";
4959
+ var OPENAI_REALTIME_BASE = "https://api.openai.com/v1";
4960
+ var ZERO_USAGE = { inputAudioTokens: 0, outputAudioTokens: 0, inputTextTokens: 0, outputTextTokens: 0 };
4961
+ function useVoiceAgent(options = {}) {
4962
+ const [status, setStatus] = useState17("idle");
4963
+ const [isMuted, setIsMuted] = useState17(false);
4964
+ const [isAgentSpeaking, setIsAgentSpeaking] = useState17(false);
4965
+ const [transcript, setTranscript] = useState17([]);
4966
+ const [error, setError] = useState17(null);
4967
+ const pcRef = useRef17(null);
4968
+ const dcRef = useRef17(null);
4969
+ const streamRef = useRef17(null);
4970
+ const audioRef = useRef17(null);
4971
+ const timerRef = useRef17(null);
4972
+ const sessionIdRef = useRef17(null);
4973
+ const liveStartRef = useRef17(null);
4974
+ const settledRef = useRef17(false);
4975
+ const usageRef = useRef17({ ...ZERO_USAGE });
4976
+ const optsRef = useRef17(options);
4977
+ optsRef.current = options;
4978
+ const settle = useCallback26(async () => {
4979
+ const sessionId = sessionIdRef.current;
4980
+ if (!sessionId || settledRef.current) return;
4981
+ settledRef.current = true;
4982
+ const durationSeconds = liveStartRef.current ? Math.max(0, (Date.now() - liveStartRef.current) / 1e3) : 0;
4983
+ try {
4984
+ await integration.post("openai-realtime/settle-session", {
4985
+ sessionId,
4986
+ durationSeconds,
4987
+ usage: usageRef.current
4988
+ });
4989
+ } catch {
4990
+ }
4991
+ }, []);
4992
+ const cleanup = useCallback26(() => {
4993
+ if (timerRef.current) {
4994
+ clearTimeout(timerRef.current);
4995
+ timerRef.current = null;
4996
+ }
4997
+ try {
4998
+ dcRef.current?.close();
4999
+ } catch {
5000
+ }
5001
+ try {
5002
+ streamRef.current?.getTracks().forEach((t) => t.stop());
5003
+ } catch {
5004
+ }
5005
+ try {
5006
+ if (pcRef.current) pcRef.current.onconnectionstatechange = null;
5007
+ pcRef.current?.close();
5008
+ } catch {
5009
+ }
5010
+ if (audioRef.current) audioRef.current.srcObject = null;
5011
+ dcRef.current = null;
5012
+ pcRef.current = null;
5013
+ streamRef.current = null;
5014
+ audioRef.current = null;
5015
+ }, []);
5016
+ const stop = useCallback26(async () => {
5017
+ cleanup();
5018
+ await settle();
5019
+ setIsAgentSpeaking(false);
5020
+ setStatus((s) => s === "error" ? s : "ended");
5021
+ }, [cleanup, settle]);
5022
+ const appendTranscript = useCallback26((role, delta) => {
5023
+ if (!delta) return;
5024
+ setTranscript((prev) => {
5025
+ const last = prev[prev.length - 1];
5026
+ if (last && last.role === role) return [...prev.slice(0, -1), { role, content: last.content + delta }];
5027
+ return [...prev, { role, content: delta }];
5028
+ });
5029
+ }, []);
5030
+ const handleToolCall = useCallback26(async (item) => {
5031
+ const onToolCall = optsRef.current.onToolCall;
5032
+ let output = null;
5033
+ if (onToolCall && item.name) {
5034
+ let args = {};
5035
+ try {
5036
+ args = item.arguments ? JSON.parse(item.arguments) : {};
5037
+ } catch {
5038
+ args = {};
5039
+ }
5040
+ try {
5041
+ output = await onToolCall(item.name, args);
5042
+ } catch (e) {
5043
+ output = { error: e instanceof Error ? e.message : String(e) };
5044
+ }
5045
+ }
5046
+ const dc = dcRef.current;
5047
+ if (!dc || dc.readyState !== "open") return;
5048
+ dc.send(
5049
+ JSON.stringify({
5050
+ type: "conversation.item.create",
5051
+ item: { type: "function_call_output", call_id: item.call_id, output: JSON.stringify(output ?? null) }
5052
+ })
5053
+ );
5054
+ dc.send(JSON.stringify({ type: "response.create" }));
5055
+ }, []);
5056
+ const handleEvent = useCallback26(
5057
+ (raw) => {
5058
+ if (typeof raw !== "string") return;
5059
+ let ev;
5060
+ try {
5061
+ ev = JSON.parse(raw);
5062
+ } catch {
5063
+ return;
5064
+ }
5065
+ switch (ev.type) {
5066
+ case "response.output_audio_transcript.delta":
5067
+ case "response.audio_transcript.delta":
5068
+ appendTranscript("assistant", ev.delta ?? "");
5069
+ break;
5070
+ case "conversation.item.input_audio_transcription.completed":
5071
+ appendTranscript("user", ev.transcript ?? "");
5072
+ break;
5073
+ case "output_audio_buffer.started":
5074
+ setIsAgentSpeaking(true);
5075
+ break;
5076
+ case "output_audio_buffer.stopped":
5077
+ setIsAgentSpeaking(false);
5078
+ break;
5079
+ case "response.done": {
5080
+ const u = ev.response?.usage;
5081
+ if (u) {
5082
+ usageRef.current.inputAudioTokens += u.input_token_details?.audio_tokens ?? 0;
5083
+ usageRef.current.outputAudioTokens += u.output_token_details?.audio_tokens ?? 0;
5084
+ usageRef.current.inputTextTokens += u.input_token_details?.text_tokens ?? 0;
5085
+ usageRef.current.outputTextTokens += u.output_token_details?.text_tokens ?? 0;
5086
+ }
5087
+ for (const item of ev.response?.output ?? []) {
5088
+ if (item?.type === "function_call") void handleToolCall(item);
5089
+ }
5090
+ break;
5091
+ }
5092
+ }
5093
+ },
5094
+ [appendTranscript, handleToolCall]
5095
+ );
5096
+ const start = useCallback26(
5097
+ async (overrides = {}) => {
5098
+ if (sessionIdRef.current) {
5099
+ cleanup();
5100
+ await settle();
5101
+ }
5102
+ const o = { ...optsRef.current, ...overrides };
5103
+ setError(null);
5104
+ setTranscript([]);
5105
+ setIsAgentSpeaking(false);
5106
+ setStatus("connecting");
5107
+ settledRef.current = false;
5108
+ liveStartRef.current = null;
5109
+ sessionIdRef.current = null;
5110
+ usageRef.current = { ...ZERO_USAGE };
5111
+ try {
5112
+ const res = await integration.post(
5113
+ "openai-realtime/create-session",
5114
+ { instructions: o.instructions, voice: o.voice, tools: o.tools, maxMinutes: o.maxMinutes }
5115
+ );
5116
+ if (!res.success || !res.data) throw new Error(res.error ?? "Failed to start voice session");
5117
+ const { sessionId, clientSecret, model, maxMinutes } = res.data;
5118
+ sessionIdRef.current = sessionId;
5119
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
5120
+ streamRef.current = stream;
5121
+ const pc = new RTCPeerConnection();
5122
+ pcRef.current = pc;
5123
+ pc.onconnectionstatechange = () => {
5124
+ if (pc.connectionState === "failed" || pc.connectionState === "closed") void stop();
5125
+ };
5126
+ const audio = new Audio();
5127
+ audio.autoplay = true;
5128
+ audioRef.current = audio;
5129
+ pc.ontrack = (e) => {
5130
+ audio.srcObject = e.streams[0];
5131
+ };
5132
+ stream.getTracks().forEach((t) => pc.addTrack(t, stream));
5133
+ const dc = pc.createDataChannel("oai-events");
5134
+ dcRef.current = dc;
5135
+ dc.onmessage = (e) => handleEvent(e.data);
5136
+ const offer = await pc.createOffer();
5137
+ await pc.setLocalDescription(offer);
5138
+ const sdpRes = await fetch(`${OPENAI_REALTIME_BASE}/realtime/calls?model=${encodeURIComponent(model)}`, {
5139
+ method: "POST",
5140
+ headers: { Authorization: `Bearer ${clientSecret}`, "Content-Type": "application/sdp" },
5141
+ body: offer.sdp
5142
+ });
5143
+ if (!sdpRes.ok) throw new Error(`Realtime connect failed (${sdpRes.status})`);
5144
+ const answer = await sdpRes.text();
5145
+ await pc.setRemoteDescription({ type: "answer", sdp: answer });
5146
+ liveStartRef.current = Date.now();
5147
+ setStatus("live");
5148
+ timerRef.current = setTimeout(() => void stop(), (maxMinutes ?? 30) * 6e4);
5149
+ } catch (err) {
5150
+ setError(err instanceof Error ? err.message : String(err));
5151
+ setStatus("error");
5152
+ cleanup();
5153
+ await settle();
5154
+ }
5155
+ },
5156
+ [cleanup, settle, stop, handleEvent]
5157
+ );
5158
+ const toggleMute = useCallback26(() => {
5159
+ const stream = streamRef.current;
5160
+ if (!stream) return;
5161
+ setIsMuted((muted) => {
5162
+ const next = !muted;
5163
+ stream.getAudioTracks().forEach((t) => t.enabled = !next);
5164
+ return next;
5165
+ });
5166
+ }, []);
5167
+ useEffect20(() => {
5168
+ return () => {
5169
+ cleanup();
5170
+ void settle();
5171
+ };
5172
+ }, [cleanup, settle]);
5173
+ return {
5174
+ status,
5175
+ start,
5176
+ stop,
5177
+ isMuted,
5178
+ toggleMute,
5179
+ isAgentSpeaking,
5180
+ transcript,
5181
+ error,
5182
+ pc: pcRef.current,
5183
+ dataChannel: dcRef.current
5184
+ };
5185
+ }
5186
+
4953
5187
  // src/client/ai-stream.ts
4954
5188
  function parseSseLine(line) {
4955
5189
  if (!line) return null;
@@ -5017,8 +5251,364 @@ function decodeAiStreamChunk(chunk) {
5017
5251
  }
5018
5252
  }
5019
5253
 
5254
+ // src/client/status.ts
5255
+ import { useCallback as useCallback27, useEffect as useEffect21, useMemo as useMemo15, useRef as useRef18, useState as useState18 } from "react";
5256
+
5257
+ // src/client/status-core.ts
5258
+ var ASYNC_RESOURCE_DEFAULTS = {
5259
+ retry: 0,
5260
+ retryDelayMs: 2e3,
5261
+ slowAfterMs: 1e4
5262
+ };
5263
+ function isAsyncResourceSlow(input) {
5264
+ return input.slowAfterMs > 0 && input.now - input.startedAt >= input.slowAfterMs;
5265
+ }
5266
+ function getPagedResourceCooldownMs(input) {
5267
+ const failureCount = Math.max(1, input.failureCount);
5268
+ return Math.min(input.maxRetryDelayMs, input.retryDelayMs * 2 ** (failureCount - 1));
5269
+ }
5270
+ function canAutoLoadPagedResource(input) {
5271
+ return input.hasMore && !input.isLoading && input.cooldownUntil <= input.now;
5272
+ }
5273
+ function clampPagedResourceItems(input) {
5274
+ if (input.maxItemsPerPage <= 0 || input.items.length <= input.maxItemsPerPage) {
5275
+ return { items: input.items, droppedItemCount: 0 };
5276
+ }
5277
+ return {
5278
+ items: input.items.slice(0, input.maxItemsPerPage),
5279
+ droppedItemCount: input.items.length - input.maxItemsPerPage
5280
+ };
5281
+ }
5282
+ function deriveLoadState(input) {
5283
+ const auth = input.auth;
5284
+ if (auth) {
5285
+ if (!auth.isLoaded) return "loading";
5286
+ if (auth.requireSignedIn && !auth.isSignedIn) return "signedOut";
5287
+ if (auth.requireUser && auth.isSignedIn && auth.userLoading) return "loading";
5288
+ }
5289
+ const statuses = [...input.queries ?? [], ...input.resources ?? []];
5290
+ if (statuses.some((item) => item.status === "error" || item.error)) return "error";
5291
+ if (statuses.some((item) => item.status === "loading" || item.status === "idle")) return "loading";
5292
+ if (input.empty) return "empty";
5293
+ return "ready";
5294
+ }
5295
+
5296
+ // src/client/status.ts
5297
+ function useAuthStatus(options = {}) {
5298
+ const auth = useAuth();
5299
+ const status = deriveLoadState({
5300
+ auth: {
5301
+ isLoaded: auth.isLoaded,
5302
+ isSignedIn: auth.isSignedIn,
5303
+ requireSignedIn: options.requireSignedIn
5304
+ }
5305
+ });
5306
+ return {
5307
+ ...auth,
5308
+ status,
5309
+ isReady: status === "ready"
5310
+ };
5311
+ }
5312
+ function useAuthProfileReady(options = {}) {
5313
+ const auth = useAuth();
5314
+ const { user, isLoading: userLoading, refetch } = useUser();
5315
+ const status = deriveLoadState({
5316
+ auth: {
5317
+ isLoaded: auth.isLoaded,
5318
+ isSignedIn: auth.isSignedIn,
5319
+ requireSignedIn: options.requireSignedIn,
5320
+ requireUser: options.requireUser,
5321
+ userLoading
5322
+ }
5323
+ });
5324
+ return {
5325
+ ...auth,
5326
+ user,
5327
+ userLoading,
5328
+ refetchUser: refetch,
5329
+ status,
5330
+ isReady: status === "ready"
5331
+ };
5332
+ }
5333
+ var useAuthReady = useAuthProfileReady;
5334
+ function useAsyncResource(fetcher, deps, options = {}) {
5335
+ const enabled = options.enabled ?? true;
5336
+ const keepPreviousData = options.keepPreviousData ?? true;
5337
+ const retry = options.retry ?? ASYNC_RESOURCE_DEFAULTS.retry;
5338
+ const retryDelayMs = options.retryDelayMs ?? ASYNC_RESOURCE_DEFAULTS.retryDelayMs;
5339
+ const slowAfterMs = options.slowAfterMs ?? ASYNC_RESOURCE_DEFAULTS.slowAfterMs;
5340
+ const [state, setState] = useState18(() => ({
5341
+ status: enabled ? "loading" : "idle",
5342
+ data: options.initialData ?? null,
5343
+ error: null,
5344
+ isRefreshing: false,
5345
+ isSlow: false,
5346
+ retryCount: 0
5347
+ }));
5348
+ const requestIdRef = useRef18(0);
5349
+ const [reloadTick, setReloadTick] = useState18(0);
5350
+ const reload = useCallback27(() => {
5351
+ setReloadTick((tick) => tick + 1);
5352
+ }, []);
5353
+ useEffect21(() => {
5354
+ if (!enabled) {
5355
+ setState((prev) => ({ ...prev, status: "idle", isRefreshing: false, isSlow: false, retryCount: 0 }));
5356
+ return;
5357
+ }
5358
+ const requestId = ++requestIdRef.current;
5359
+ const controller = new AbortController();
5360
+ let retryTimer = null;
5361
+ let slowTimer = null;
5362
+ setState((prev) => {
5363
+ const hasData = keepPreviousData && prev.data != null;
5364
+ return {
5365
+ ...prev,
5366
+ status: hasData ? "ready" : "loading",
5367
+ error: null,
5368
+ isRefreshing: hasData,
5369
+ isSlow: false,
5370
+ data: hasData ? prev.data : options.initialData ?? null,
5371
+ retryCount: 0
5372
+ };
5373
+ });
5374
+ if (slowAfterMs > 0) {
5375
+ const startedAt = Date.now();
5376
+ slowTimer = setTimeout(() => {
5377
+ if (requestIdRef.current !== requestId || controller.signal.aborted) return;
5378
+ setState((prev) => ({
5379
+ ...prev,
5380
+ isSlow: isAsyncResourceSlow({ startedAt, now: Date.now(), slowAfterMs })
5381
+ }));
5382
+ }, slowAfterMs);
5383
+ }
5384
+ const wait = (ms) => new Promise((resolve) => {
5385
+ retryTimer = setTimeout(resolve, ms);
5386
+ });
5387
+ const load = async () => {
5388
+ let attempt = 0;
5389
+ while (!controller.signal.aborted) {
5390
+ try {
5391
+ const data = await fetcher(controller.signal);
5392
+ if (requestIdRef.current !== requestId || controller.signal.aborted) return;
5393
+ if (slowTimer) clearTimeout(slowTimer);
5394
+ setState({ status: "ready", data, error: null, isRefreshing: false, isSlow: false, retryCount: attempt });
5395
+ return;
5396
+ } catch (err) {
5397
+ if (requestIdRef.current !== requestId || controller.signal.aborted) return;
5398
+ const message = err instanceof Error ? err.message : "Request failed";
5399
+ if (attempt < retry) {
5400
+ attempt += 1;
5401
+ setState((prev) => ({
5402
+ ...prev,
5403
+ error: message,
5404
+ retryCount: attempt,
5405
+ isRefreshing: keepPreviousData && prev.data != null
5406
+ }));
5407
+ await wait(retryDelayMs);
5408
+ continue;
5409
+ }
5410
+ if (slowTimer) clearTimeout(slowTimer);
5411
+ setState((prev) => ({
5412
+ status: keepPreviousData && prev.data != null ? "ready" : "error",
5413
+ data: keepPreviousData ? prev.data : null,
5414
+ error: message,
5415
+ isRefreshing: false,
5416
+ isSlow: false,
5417
+ retryCount: attempt
5418
+ }));
5419
+ return;
5420
+ }
5421
+ }
5422
+ };
5423
+ load();
5424
+ return () => {
5425
+ if (retryTimer) clearTimeout(retryTimer);
5426
+ if (slowTimer) clearTimeout(slowTimer);
5427
+ controller.abort();
5428
+ };
5429
+ }, [enabled, keepPreviousData, retry, retryDelayMs, slowAfterMs, reloadTick, ...deps]);
5430
+ return useMemo15(() => ({ ...state, reload }), [state, reload]);
5431
+ }
5432
+ function usePagedResource(fetchPage, deps, options = {}) {
5433
+ const enabled = options.enabled ?? true;
5434
+ const initialItems = options.initialItems ?? [];
5435
+ const pageSize = options.pageSize ?? 20;
5436
+ const maxItemsPerPage = options.maxItemsPerPage ?? pageSize;
5437
+ const keepPreviousData = options.keepPreviousData ?? true;
5438
+ const autoRetryOnError = options.autoRetryOnError ?? false;
5439
+ const retryDelayMs = options.retryDelayMs ?? ASYNC_RESOURCE_DEFAULTS.retryDelayMs;
5440
+ const maxRetryDelayMs = options.maxRetryDelayMs ?? 3e4;
5441
+ const hasInitialItems = initialItems.length > 0;
5442
+ const [state, setState] = useState18(() => ({
5443
+ status: enabled ? hasInitialItems ? "ready" : "loading" : "idle",
5444
+ items: initialItems,
5445
+ error: null,
5446
+ warning: null,
5447
+ hasMore: true,
5448
+ isLoadingInitial: enabled && !hasInitialItems,
5449
+ isLoadingMore: false,
5450
+ isRefreshing: false
5451
+ }));
5452
+ const requestIdRef = useRef18(0);
5453
+ const controllerRef = useRef18(null);
5454
+ const loadingRef = useRef18(false);
5455
+ const nextPageRef = useRef18(hasInitialItems ? 2 : 1);
5456
+ const failedPageRef = useRef18(null);
5457
+ const failureCountRef = useRef18(0);
5458
+ const cooldownUntilRef = useRef18(0);
5459
+ const autoRetryTimerRef = useRef18(null);
5460
+ const clearAutoRetryTimer = useCallback27(() => {
5461
+ if (autoRetryTimerRef.current) {
5462
+ clearTimeout(autoRetryTimerRef.current);
5463
+ autoRetryTimerRef.current = null;
5464
+ }
5465
+ }, []);
5466
+ const resetCooldown = useCallback27(() => {
5467
+ failureCountRef.current = 0;
5468
+ cooldownUntilRef.current = 0;
5469
+ }, []);
5470
+ const setFailureCooldown = useCallback27(() => {
5471
+ failureCountRef.current += 1;
5472
+ const delay = getPagedResourceCooldownMs({
5473
+ failureCount: failureCountRef.current,
5474
+ retryDelayMs,
5475
+ maxRetryDelayMs
5476
+ });
5477
+ cooldownUntilRef.current = Date.now() + delay;
5478
+ return delay;
5479
+ }, [maxRetryDelayMs, retryDelayMs]);
5480
+ const startLoad = useCallback27(async (page, mode) => {
5481
+ if (!enabled || loadingRef.current) return;
5482
+ if (mode === "auto" && !canAutoLoadPagedResource({
5483
+ hasMore: true,
5484
+ isLoading: false,
5485
+ now: Date.now(),
5486
+ cooldownUntil: cooldownUntilRef.current
5487
+ })) {
5488
+ return;
5489
+ }
5490
+ clearAutoRetryTimer();
5491
+ loadingRef.current = true;
5492
+ const requestId = ++requestIdRef.current;
5493
+ controllerRef.current?.abort();
5494
+ const controller = new AbortController();
5495
+ controllerRef.current = controller;
5496
+ setState((prev) => {
5497
+ const hasItems = prev.items.length > 0;
5498
+ return {
5499
+ ...prev,
5500
+ status: hasItems && mode !== "refresh" ? "ready" : "loading",
5501
+ error: mode === "auto" && prev.error ? prev.error : null,
5502
+ warning: null,
5503
+ isLoadingInitial: !hasItems && mode !== "refresh",
5504
+ isLoadingMore: hasItems && mode !== "refresh",
5505
+ isRefreshing: mode === "refresh" && hasItems,
5506
+ items: mode === "refresh" && !keepPreviousData ? [] : prev.items
5507
+ };
5508
+ });
5509
+ try {
5510
+ const result = await fetchPage({ page, pageSize, signal: controller.signal });
5511
+ if (requestIdRef.current !== requestId || controller.signal.aborted) return;
5512
+ const { items: pageItems, droppedItemCount } = clampPagedResourceItems({
5513
+ items: result.items,
5514
+ maxItemsPerPage
5515
+ });
5516
+ resetCooldown();
5517
+ failedPageRef.current = null;
5518
+ nextPageRef.current = page + 1;
5519
+ setState((prev) => ({
5520
+ status: "ready",
5521
+ items: page === 1 || mode === "refresh" ? pageItems : [...prev.items, ...pageItems],
5522
+ error: null,
5523
+ warning: droppedItemCount > 0 ? `The last API page returned ${result.items.length} items; only ${pageItems.length} were kept. Request a smaller page from the API instead of fetching the whole feed.` : null,
5524
+ hasMore: droppedItemCount > 0 || (result.hasMore ?? result.items.length >= pageSize),
5525
+ isLoadingInitial: false,
5526
+ isLoadingMore: false,
5527
+ isRefreshing: false
5528
+ }));
5529
+ } catch (err) {
5530
+ if (requestIdRef.current !== requestId || controller.signal.aborted) return;
5531
+ const message = err instanceof Error ? err.message : "Request failed";
5532
+ failedPageRef.current = page;
5533
+ const cooldownMs = setFailureCooldown();
5534
+ setState((prev) => {
5535
+ const hasItems = prev.items.length > 0;
5536
+ return {
5537
+ ...prev,
5538
+ status: hasItems ? "ready" : "error",
5539
+ error: message,
5540
+ warning: prev.warning,
5541
+ hasMore: hasItems ? prev.hasMore : false,
5542
+ isLoadingInitial: false,
5543
+ isLoadingMore: false,
5544
+ isRefreshing: false
5545
+ };
5546
+ });
5547
+ if (autoRetryOnError) {
5548
+ autoRetryTimerRef.current = setTimeout(() => {
5549
+ autoRetryTimerRef.current = null;
5550
+ void startLoad(page, "auto");
5551
+ }, cooldownMs);
5552
+ }
5553
+ } finally {
5554
+ if (requestIdRef.current === requestId) {
5555
+ loadingRef.current = false;
5556
+ controllerRef.current = null;
5557
+ }
5558
+ }
5559
+ }, [autoRetryOnError, clearAutoRetryTimer, enabled, fetchPage, keepPreviousData, pageSize, resetCooldown, setFailureCooldown]);
5560
+ const loadMore = useCallback27(() => {
5561
+ if (!state.hasMore || state.isLoadingInitial || state.isLoadingMore || state.isRefreshing) return;
5562
+ void startLoad(nextPageRef.current, "auto");
5563
+ }, [startLoad, state.hasMore, state.isLoadingInitial, state.isLoadingMore, state.isRefreshing]);
5564
+ const retry = useCallback27(() => {
5565
+ const page = failedPageRef.current ?? nextPageRef.current;
5566
+ void startLoad(page, "manual");
5567
+ }, [startLoad]);
5568
+ const refresh = useCallback27(() => {
5569
+ failedPageRef.current = null;
5570
+ resetCooldown();
5571
+ nextPageRef.current = 1;
5572
+ void startLoad(1, "refresh");
5573
+ }, [resetCooldown, startLoad]);
5574
+ useEffect21(() => {
5575
+ requestIdRef.current += 1;
5576
+ controllerRef.current?.abort();
5577
+ clearAutoRetryTimer();
5578
+ loadingRef.current = false;
5579
+ failedPageRef.current = null;
5580
+ resetCooldown();
5581
+ nextPageRef.current = hasInitialItems ? 2 : 1;
5582
+ setState({
5583
+ status: enabled ? hasInitialItems ? "ready" : "loading" : "idle",
5584
+ items: initialItems,
5585
+ error: null,
5586
+ warning: null,
5587
+ hasMore: true,
5588
+ isLoadingInitial: enabled && !hasInitialItems,
5589
+ isLoadingMore: false,
5590
+ isRefreshing: false
5591
+ });
5592
+ if (enabled && !hasInitialItems) {
5593
+ void startLoad(1, "auto");
5594
+ }
5595
+ return () => {
5596
+ requestIdRef.current += 1;
5597
+ controllerRef.current?.abort();
5598
+ clearAutoRetryTimer();
5599
+ loadingRef.current = false;
5600
+ };
5601
+ }, [enabled, pageSize, maxItemsPerPage, keepPreviousData, autoRetryOnError, retryDelayMs, maxRetryDelayMs, ...deps]);
5602
+ return useMemo15(() => ({
5603
+ ...state,
5604
+ loadMore,
5605
+ retry,
5606
+ refresh
5607
+ }), [loadMore, refresh, retry, state]);
5608
+ }
5609
+
5020
5610
  // src/client/subscriptions/useSubscription.ts
5021
- import { useCallback as useCallback26, useEffect as useEffect20, useState as useState17 } from "react";
5611
+ import { useCallback as useCallback28, useEffect as useEffect22, useState as useState19 } from "react";
5022
5612
 
5023
5613
  // src/shared/subscription.ts
5024
5614
  var ENTITLED_STATUSES = /* @__PURE__ */ new Set([
@@ -5049,7 +5639,7 @@ async function authedJson(path, init) {
5049
5639
  return data;
5050
5640
  }
5051
5641
  function useSubscription() {
5052
- const [state, setState] = useState17({
5642
+ const [state, setState] = useState19({
5053
5643
  tier: "free",
5054
5644
  status: "none",
5055
5645
  interval: null,
@@ -5058,9 +5648,9 @@ function useSubscription() {
5058
5648
  trialEndsAt: null,
5059
5649
  plans: []
5060
5650
  });
5061
- const [isLoading, setLoading] = useState17(true);
5062
- const [error, setError] = useState17(null);
5063
- const refresh = useCallback26(async () => {
5651
+ const [isLoading, setLoading] = useState19(true);
5652
+ const [error, setError] = useState19(null);
5653
+ const refresh = useCallback28(async () => {
5064
5654
  setLoading(true);
5065
5655
  try {
5066
5656
  const r = await authedJson("/_deepspace/subscriptions/me");
@@ -5080,15 +5670,15 @@ function useSubscription() {
5080
5670
  setLoading(false);
5081
5671
  }
5082
5672
  }, []);
5083
- useEffect20(() => {
5673
+ useEffect22(() => {
5084
5674
  refresh();
5085
5675
  }, [refresh]);
5086
5676
  const entitled = isEntitled(state.tier, state.status);
5087
- const hasTier = useCallback26(
5677
+ const hasTier = useCallback28(
5088
5678
  (slug) => state.tier === slug && isEntitled(state.tier, state.status),
5089
5679
  [state.tier, state.status]
5090
5680
  );
5091
- const isAtLeast = useCallback26(
5681
+ const isAtLeast = useCallback28(
5092
5682
  (slug) => {
5093
5683
  if (!isEntitled(state.tier, state.status)) return false;
5094
5684
  const targetRank = state.plans.find((p) => p.slug === slug)?.rank;
@@ -5098,7 +5688,7 @@ function useSubscription() {
5098
5688
  },
5099
5689
  [state.plans, state.tier, state.status]
5100
5690
  );
5101
- const subscribe = useCallback26(
5691
+ const subscribe = useCallback28(
5102
5692
  async (planSlug, opts) => {
5103
5693
  const result = await authedJson("/_deepspace/subscriptions/checkout", {
5104
5694
  method: "POST",
@@ -5118,7 +5708,7 @@ function useSubscription() {
5118
5708
  },
5119
5709
  [refresh]
5120
5710
  );
5121
- const openPortal = useCallback26(
5711
+ const openPortal = useCallback28(
5122
5712
  async (returnUrl) => {
5123
5713
  return authedJson("/_deepspace/subscriptions/portal", {
5124
5714
  method: "POST",
@@ -5187,7 +5777,7 @@ function PricingTable(props) {
5187
5777
  }
5188
5778
 
5189
5779
  // src/client/charges/useCheckout.ts
5190
- import { useCallback as useCallback27, useEffect as useEffect21, useMemo as useMemo15, useState as useState18 } from "react";
5780
+ import { useCallback as useCallback29, useEffect as useEffect23, useMemo as useMemo16, useState as useState20 } from "react";
5191
5781
  async function authedJson2(path, init) {
5192
5782
  const token = await getAuthToken();
5193
5783
  const res = await fetch(path, {
@@ -5206,10 +5796,10 @@ async function authedJson2(path, init) {
5206
5796
  return data;
5207
5797
  }
5208
5798
  function useCheckout(opts) {
5209
- const [purchases, setPurchases] = useState18([]);
5210
- const [isLoading, setLoading] = useState18(true);
5211
- const [error, setError] = useState18(null);
5212
- const refresh = useCallback27(async () => {
5799
+ const [purchases, setPurchases] = useState20([]);
5800
+ const [isLoading, setLoading] = useState20(true);
5801
+ const [error, setError] = useState20(null);
5802
+ const refresh = useCallback29(async () => {
5213
5803
  setLoading(true);
5214
5804
  try {
5215
5805
  const r = await authedJson2(
@@ -5223,10 +5813,10 @@ function useCheckout(opts) {
5223
5813
  setLoading(false);
5224
5814
  }
5225
5815
  }, []);
5226
- useEffect21(() => {
5816
+ useEffect23(() => {
5227
5817
  refresh();
5228
5818
  }, [refresh]);
5229
- const chargeOnce = useCallback27(
5819
+ const chargeOnce = useCallback29(
5230
5820
  async (chargeOpts) => {
5231
5821
  setError(null);
5232
5822
  const common = {
@@ -5260,11 +5850,11 @@ function useCheckout(opts) {
5260
5850
  },
5261
5851
  []
5262
5852
  );
5263
- const ownsProduct = useCallback27(
5853
+ const ownsProduct = useCallback29(
5264
5854
  (productId) => purchases.some((p) => p.productId === productId),
5265
5855
  [purchases]
5266
5856
  );
5267
- const owned = useMemo15(
5857
+ const owned = useMemo16(
5268
5858
  () => !!opts?.productId && purchases.some((p) => p.productId === opts.productId),
5269
5859
  [opts?.productId, purchases]
5270
5860
  );
@@ -5278,1620 +5868,17 @@ function useCheckout(opts) {
5278
5868
  refresh
5279
5869
  };
5280
5870
  }
5281
-
5282
- // src/ui/utils.ts
5283
- import { clsx } from "clsx";
5284
- import { twMerge } from "tailwind-merge";
5285
- function cn(...inputs) {
5286
- return twMerge(clsx(inputs));
5287
- }
5288
-
5289
- // src/ui/Card.tsx
5290
- import * as React7 from "react";
5291
- import { jsx as jsx11 } from "react/jsx-runtime";
5292
- var Card = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
5293
- "div",
5294
- {
5295
- ref,
5296
- className: cn(
5297
- "relative rounded-2xl border border-border bg-card text-card-foreground shadow-card",
5298
- className
5299
- ),
5300
- ...props
5301
- }
5302
- ));
5303
- Card.displayName = "Card";
5304
- var CardHeader = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
5305
- "div",
5306
- {
5307
- ref,
5308
- className: cn("flex flex-col space-y-1.5 p-4 sm:p-6", className),
5309
- ...props
5310
- }
5311
- ));
5312
- CardHeader.displayName = "CardHeader";
5313
- var CardTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
5314
- "div",
5315
- {
5316
- ref,
5317
- className: cn("font-semibold leading-none tracking-tight", className),
5318
- ...props
5319
- }
5320
- ));
5321
- CardTitle.displayName = "CardTitle";
5322
- var CardDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
5323
- "div",
5324
- {
5325
- ref,
5326
- className: cn("text-sm text-muted-foreground", className),
5327
- ...props
5328
- }
5329
- ));
5330
- CardDescription.displayName = "CardDescription";
5331
- var CardContent = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11("div", { ref, className: cn("p-4 pt-0 sm:p-6 sm:pt-0", className), ...props }));
5332
- CardContent.displayName = "CardContent";
5333
- var CardFooter = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
5334
- "div",
5335
- {
5336
- ref,
5337
- className: cn("flex items-center p-4 pt-0 sm:p-6 sm:pt-0", className),
5338
- ...props
5339
- }
5340
- ));
5341
- CardFooter.displayName = "CardFooter";
5342
-
5343
- // src/ui/Separator.tsx
5344
- import * as React8 from "react";
5345
- import * as SeparatorPrimitive from "@radix-ui/react-separator";
5346
- import { jsx as jsx12 } from "react/jsx-runtime";
5347
- var Separator = React8.forwardRef(
5348
- ({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx12(
5349
- SeparatorPrimitive.Root,
5350
- {
5351
- ref,
5352
- decorative,
5353
- orientation,
5354
- className: cn(
5355
- "shrink-0 bg-border",
5356
- orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
5357
- className
5358
- ),
5359
- ...props
5360
- }
5361
- )
5362
- );
5363
- Separator.displayName = SeparatorPrimitive.Root.displayName;
5364
-
5365
- // src/ui/Table.tsx
5366
- import * as React9 from "react";
5367
- import { jsx as jsx13 } from "react/jsx-runtime";
5368
- var Table = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx13(
5369
- "table",
5370
- {
5371
- ref,
5372
- className: cn("w-full caption-bottom text-sm", className),
5373
- ...props
5374
- }
5375
- ) }));
5376
- Table.displayName = "Table";
5377
- var TableHeader = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
5378
- TableHeader.displayName = "TableHeader";
5379
- var TableBody = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5380
- "tbody",
5381
- {
5382
- ref,
5383
- className: cn("[&_tr:last-child]:border-0", className),
5384
- ...props
5385
- }
5386
- ));
5387
- TableBody.displayName = "TableBody";
5388
- var TableFooter = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5389
- "tfoot",
5390
- {
5391
- ref,
5392
- className: cn(
5393
- "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
5394
- className
5395
- ),
5396
- ...props
5397
- }
5398
- ));
5399
- TableFooter.displayName = "TableFooter";
5400
- var TableRow = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5401
- "tr",
5402
- {
5403
- ref,
5404
- className: cn(
5405
- "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
5406
- className
5407
- ),
5408
- ...props
5409
- }
5410
- ));
5411
- TableRow.displayName = "TableRow";
5412
- var TableHead = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5413
- "th",
5414
- {
5415
- ref,
5416
- className: cn(
5417
- "h-10 px-2 sm:px-3 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
5418
- className
5419
- ),
5420
- ...props
5421
- }
5422
- ));
5423
- TableHead.displayName = "TableHead";
5424
- var TableCell = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5425
- "td",
5426
- {
5427
- ref,
5428
- className: cn(
5429
- "p-2 sm:p-3 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
5430
- className
5431
- ),
5432
- ...props
5433
- }
5434
- ));
5435
- TableCell.displayName = "TableCell";
5436
- var TableCaption = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5437
- "caption",
5438
- {
5439
- ref,
5440
- className: cn("mt-4 text-sm text-muted-foreground", className),
5441
- ...props
5442
- }
5443
- ));
5444
- TableCaption.displayName = "TableCaption";
5445
-
5446
- // src/ui/Tabs.tsx
5447
- import * as React10 from "react";
5448
- import * as TabsPrimitive from "@radix-ui/react-tabs";
5449
- import { jsx as jsx14 } from "react/jsx-runtime";
5450
- var Tabs = TabsPrimitive.Root;
5451
- var TabsList = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14(
5452
- TabsPrimitive.List,
5453
- {
5454
- ref,
5455
- className: cn(
5456
- "inline-flex h-10 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground overflow-x-auto max-w-full",
5457
- className
5458
- ),
5459
- ...props
5460
- }
5461
- ));
5462
- TabsList.displayName = TabsPrimitive.List.displayName;
5463
- var TabsTrigger = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14(
5464
- TabsPrimitive.Trigger,
5465
- {
5466
- ref,
5467
- className: cn(
5468
- "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
5469
- className
5470
- ),
5471
- ...props
5472
- }
5473
- ));
5474
- TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
5475
- var TabsContent = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14(
5476
- TabsPrimitive.Content,
5477
- {
5478
- ref,
5479
- className: cn(
5480
- "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
5481
- className
5482
- ),
5483
- ...props
5484
- }
5485
- ));
5486
- TabsContent.displayName = TabsPrimitive.Content.displayName;
5487
-
5488
- // src/ui/Button.tsx
5489
- import * as React11 from "react";
5490
- import { Slot } from "@radix-ui/react-slot";
5491
- import { cva } from "class-variance-authority";
5492
- import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
5493
- var buttonVariants = cva(
5494
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
5495
- {
5496
- variants: {
5497
- variant: {
5498
- default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
5499
- destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
5500
- outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
5501
- secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
5502
- ghost: "hover:bg-accent hover:text-accent-foreground",
5503
- link: "text-primary underline-offset-4 hover:underline"
5504
- },
5505
- size: {
5506
- default: "h-10 px-4 py-2",
5507
- sm: "h-9 rounded-md px-3 text-xs",
5508
- lg: "h-11 rounded-md px-8",
5509
- icon: "h-10 w-10"
5510
- }
5511
- },
5512
- defaultVariants: {
5513
- variant: "default",
5514
- size: "default"
5515
- }
5516
- }
5517
- );
5518
- var Button = React11.forwardRef(
5519
- ({ className, variant, size, asChild = false, loading = false, disabled, children, ...props }, ref) => {
5520
- const Comp = asChild ? Slot : "button";
5521
- return /* @__PURE__ */ jsxs6(
5522
- Comp,
5523
- {
5524
- className: cn(buttonVariants({ variant, size, className })),
5525
- ref,
5526
- disabled: disabled || loading,
5527
- ...props,
5528
- children: [
5529
- loading && /* @__PURE__ */ jsx15("span", { className: "w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin" }),
5530
- children
5531
- ]
5532
- }
5533
- );
5534
- }
5535
- );
5536
- Button.displayName = "Button";
5537
-
5538
- // src/ui/Input.tsx
5539
- import * as React12 from "react";
5540
- import { jsx as jsx16 } from "react/jsx-runtime";
5541
- var Input = React12.forwardRef(
5542
- ({ className, type, ...props }, ref) => {
5543
- return /* @__PURE__ */ jsx16(
5544
- "input",
5545
- {
5546
- type,
5547
- className: cn(
5548
- "flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
5549
- className
5550
- ),
5551
- ref,
5552
- ...props
5553
- }
5554
- );
5555
- }
5556
- );
5557
- Input.displayName = "Input";
5558
-
5559
- // src/ui/Textarea.tsx
5560
- import * as React13 from "react";
5561
- import { jsx as jsx17 } from "react/jsx-runtime";
5562
- var Textarea = React13.forwardRef(({ className, ...props }, ref) => {
5563
- return /* @__PURE__ */ jsx17(
5564
- "textarea",
5565
- {
5566
- className: cn(
5567
- "flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
5568
- className
5569
- ),
5570
- ref,
5571
- ...props
5572
- }
5573
- );
5574
- });
5575
- Textarea.displayName = "Textarea";
5576
-
5577
- // src/ui/Select.tsx
5578
- import * as React14 from "react";
5579
- import * as SelectPrimitive from "@radix-ui/react-select";
5580
- import { Check, ChevronDown, ChevronUp } from "lucide-react";
5581
- import { jsx as jsx18, jsxs as jsxs7 } from "react/jsx-runtime";
5582
- var Select = SelectPrimitive.Root;
5583
- var SelectGroup = SelectPrimitive.Group;
5584
- var SelectValue = SelectPrimitive.Value;
5585
- var SelectTrigger = React14.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs7(
5586
- SelectPrimitive.Trigger,
5587
- {
5588
- ref,
5589
- className: cn(
5590
- "flex h-10 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
5591
- className
5592
- ),
5593
- ...props,
5594
- children: [
5595
- children,
5596
- /* @__PURE__ */ jsx18(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx18(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
5597
- ]
5598
- }
5599
- ));
5600
- SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
5601
- var SelectScrollUpButton = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(
5602
- SelectPrimitive.ScrollUpButton,
5603
- {
5604
- ref,
5605
- className: cn(
5606
- "flex cursor-default items-center justify-center py-1",
5607
- className
5608
- ),
5609
- ...props,
5610
- children: /* @__PURE__ */ jsx18(ChevronUp, { className: "h-4 w-4" })
5611
- }
5612
- ));
5613
- SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
5614
- var SelectScrollDownButton = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(
5615
- SelectPrimitive.ScrollDownButton,
5616
- {
5617
- ref,
5618
- className: cn(
5619
- "flex cursor-default items-center justify-center py-1",
5620
- className
5621
- ),
5622
- ...props,
5623
- children: /* @__PURE__ */ jsx18(ChevronDown, { className: "h-4 w-4" })
5624
- }
5625
- ));
5626
- SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
5627
- var SelectContent = React14.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx18(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs7(
5628
- SelectPrimitive.Content,
5629
- {
5630
- ref,
5631
- className: cn(
5632
- "relative z-50 max-h-96 min-w-[8rem] max-w-[calc(100vw-2rem)] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
5633
- position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
5634
- className
5635
- ),
5636
- position,
5637
- ...props,
5638
- children: [
5639
- /* @__PURE__ */ jsx18(SelectScrollUpButton, {}),
5640
- /* @__PURE__ */ jsx18(
5641
- SelectPrimitive.Viewport,
5642
- {
5643
- className: cn(
5644
- "p-1",
5645
- position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
5646
- ),
5647
- children
5648
- }
5649
- ),
5650
- /* @__PURE__ */ jsx18(SelectScrollDownButton, {})
5651
- ]
5652
- }
5653
- ) }));
5654
- SelectContent.displayName = SelectPrimitive.Content.displayName;
5655
- var SelectLabel = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(
5656
- SelectPrimitive.Label,
5657
- {
5658
- ref,
5659
- className: cn("px-2 py-1.5 text-sm font-semibold", className),
5660
- ...props
5661
- }
5662
- ));
5663
- SelectLabel.displayName = SelectPrimitive.Label.displayName;
5664
- var SelectItem = React14.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs7(
5665
- SelectPrimitive.Item,
5666
- {
5667
- ref,
5668
- className: cn(
5669
- "relative flex w-full cursor-default select-none items-center rounded-sm py-2 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
5670
- className
5671
- ),
5672
- ...props,
5673
- children: [
5674
- /* @__PURE__ */ jsx18("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx18(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx18(Check, { className: "h-4 w-4" }) }) }),
5675
- /* @__PURE__ */ jsx18(SelectPrimitive.ItemText, { children })
5676
- ]
5677
- }
5678
- ));
5679
- SelectItem.displayName = SelectPrimitive.Item.displayName;
5680
- var SelectSeparator = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(
5681
- SelectPrimitive.Separator,
5682
- {
5683
- ref,
5684
- className: cn("-mx-1 my-1 h-px bg-muted", className),
5685
- ...props
5686
- }
5687
- ));
5688
- SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
5689
-
5690
- // src/ui/Checkbox.tsx
5691
- import * as React15 from "react";
5692
- import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
5693
- import { Check as Check2 } from "lucide-react";
5694
- import { jsx as jsx19 } from "react/jsx-runtime";
5695
- var Checkbox = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
5696
- CheckboxPrimitive.Root,
5697
- {
5698
- ref,
5699
- className: cn(
5700
- "grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
5701
- className
5702
- ),
5703
- ...props,
5704
- children: /* @__PURE__ */ jsx19(
5705
- CheckboxPrimitive.Indicator,
5706
- {
5707
- className: cn("grid place-content-center text-current"),
5708
- children: /* @__PURE__ */ jsx19(Check2, { className: "h-4 w-4" })
5709
- }
5710
- )
5711
- }
5712
- ));
5713
- Checkbox.displayName = CheckboxPrimitive.Root.displayName;
5714
-
5715
- // src/ui/Switch.tsx
5716
- import * as React16 from "react";
5717
- import * as SwitchPrimitives from "@radix-ui/react-switch";
5718
- import { jsx as jsx20 } from "react/jsx-runtime";
5719
- var Switch = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
5720
- SwitchPrimitives.Root,
5721
- {
5722
- className: cn(
5723
- "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
5724
- className
5725
- ),
5726
- ...props,
5727
- ref,
5728
- children: /* @__PURE__ */ jsx20(
5729
- SwitchPrimitives.Thumb,
5730
- {
5731
- className: cn(
5732
- "pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
5733
- )
5734
- }
5735
- )
5736
- }
5737
- ));
5738
- Switch.displayName = SwitchPrimitives.Root.displayName;
5739
-
5740
- // src/ui/Label.tsx
5741
- import * as React17 from "react";
5742
- import * as LabelPrimitive from "@radix-ui/react-label";
5743
- import { cva as cva2 } from "class-variance-authority";
5744
- import { jsx as jsx21 } from "react/jsx-runtime";
5745
- var labelVariants = cva2(
5746
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
5747
- );
5748
- var Label2 = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx21(
5749
- LabelPrimitive.Root,
5750
- {
5751
- ref,
5752
- className: cn(labelVariants(), className),
5753
- ...props
5754
- }
5755
- ));
5756
- Label2.displayName = LabelPrimitive.Root.displayName;
5757
-
5758
- // src/ui/Badge.tsx
5759
- import { cva as cva3 } from "class-variance-authority";
5760
- import { jsx as jsx22 } from "react/jsx-runtime";
5761
- var badgeVariants = cva3(
5762
- "inline-flex items-center rounded-full border font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
5763
- {
5764
- variants: {
5765
- variant: {
5766
- default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
5767
- secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
5768
- destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
5769
- outline: "text-foreground",
5770
- success: "border-transparent bg-success text-success-foreground shadow hover:bg-success/80",
5771
- warning: "border-transparent bg-warning text-warning-foreground shadow hover:bg-warning/80",
5772
- info: "border-transparent bg-info text-info-foreground shadow hover:bg-info/80"
5773
- },
5774
- size: {
5775
- default: "px-2.5 py-0.5 text-xs",
5776
- sm: "px-2 py-px text-[10px]",
5777
- lg: "px-3 py-1 text-sm"
5778
- }
5779
- },
5780
- defaultVariants: {
5781
- variant: "default",
5782
- size: "default"
5783
- }
5784
- }
5785
- );
5786
- function Badge({ className, variant, size, ...props }) {
5787
- return /* @__PURE__ */ jsx22("div", { className: cn(badgeVariants({ variant, size }), className), ...props });
5788
- }
5789
-
5790
- // src/ui/Avatar.tsx
5791
- import * as React18 from "react";
5792
- import * as AvatarPrimitive from "@radix-ui/react-avatar";
5793
- import { jsx as jsx23 } from "react/jsx-runtime";
5794
- var Avatar = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
5795
- AvatarPrimitive.Root,
5796
- {
5797
- ref,
5798
- className: cn(
5799
- "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
5800
- className
5801
- ),
5802
- ...props
5803
- }
5804
- ));
5805
- Avatar.displayName = AvatarPrimitive.Root.displayName;
5806
- var AvatarImage = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
5807
- AvatarPrimitive.Image,
5808
- {
5809
- ref,
5810
- className: cn("aspect-square h-full w-full", className),
5811
- ...props
5812
- }
5813
- ));
5814
- AvatarImage.displayName = AvatarPrimitive.Image.displayName;
5815
- var AvatarFallback = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
5816
- AvatarPrimitive.Fallback,
5817
- {
5818
- ref,
5819
- className: cn(
5820
- "flex h-full w-full items-center justify-center rounded-full bg-muted",
5821
- className
5822
- ),
5823
- ...props
5824
- }
5825
- ));
5826
- AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
5827
-
5828
- // src/ui/Progress.tsx
5829
- import * as React19 from "react";
5830
- import * as ProgressPrimitive from "@radix-ui/react-progress";
5831
- import { jsx as jsx24 } from "react/jsx-runtime";
5832
- var Progress = React19.forwardRef(({ className, value, ...props }, ref) => /* @__PURE__ */ jsx24(
5833
- ProgressPrimitive.Root,
5834
- {
5835
- ref,
5836
- className: cn(
5837
- "relative h-2 w-full overflow-hidden rounded-full bg-primary/20",
5838
- className
5839
- ),
5840
- ...props,
5841
- children: /* @__PURE__ */ jsx24(
5842
- ProgressPrimitive.Indicator,
5843
- {
5844
- className: "h-full w-full flex-1 bg-primary transition-all",
5845
- style: { transform: `translateX(-${100 - (value || 0)}%)` }
5846
- }
5847
- )
5848
- }
5849
- ));
5850
- Progress.displayName = ProgressPrimitive.Root.displayName;
5851
-
5852
- // src/ui/Skeleton.tsx
5853
- import { jsx as jsx25, jsxs as jsxs8 } from "react/jsx-runtime";
5854
- function Skeleton({
5855
- className,
5856
- ...props
5857
- }) {
5858
- return /* @__PURE__ */ jsx25(
5859
- "div",
5860
- {
5861
- className: cn("animate-pulse rounded-md bg-primary/10", className),
5862
- ...props
5863
- }
5864
- );
5865
- }
5866
- function SkeletonText({
5867
- lines = 3,
5868
- lastLineWidth = "60%",
5869
- className = ""
5870
- }) {
5871
- return /* @__PURE__ */ jsx25("div", { className: cn("space-y-2", className), children: Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsx25(
5872
- Skeleton,
5873
- {
5874
- className: "h-4",
5875
- style: { width: i === lines - 1 ? lastLineWidth : "100%" }
5876
- },
5877
- i
5878
- )) });
5879
- }
5880
- function SkeletonCard({ hasImage = false, className = "" }) {
5881
- return /* @__PURE__ */ jsxs8("div", { className: cn("border border-border rounded-lg overflow-hidden", className), children: [
5882
- hasImage && /* @__PURE__ */ jsx25(Skeleton, { className: "w-full h-32 rounded-none" }),
5883
- /* @__PURE__ */ jsxs8("div", { className: "p-4 space-y-3", children: [
5884
- /* @__PURE__ */ jsx25(Skeleton, { className: "h-5 w-3/4" }),
5885
- /* @__PURE__ */ jsx25(SkeletonText, { lines: 2 }),
5886
- /* @__PURE__ */ jsx25(Skeleton, { className: "h-3 w-1/3" })
5887
- ] })
5888
- ] });
5889
- }
5890
- function SkeletonList({ items = 5, className = "" }) {
5891
- return /* @__PURE__ */ jsx25("div", { className: cn("space-y-3", className), children: Array.from({ length: items }).map((_, i) => /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-3 p-3 border border-border rounded-lg", children: [
5892
- /* @__PURE__ */ jsx25(Skeleton, { className: "w-10 h-10 rounded-full" }),
5893
- /* @__PURE__ */ jsxs8("div", { className: "flex-1 space-y-2", children: [
5894
- /* @__PURE__ */ jsx25(Skeleton, { className: "h-4 w-1/3" }),
5895
- /* @__PURE__ */ jsx25(Skeleton, { className: "h-3 w-1/2" })
5896
- ] }),
5897
- /* @__PURE__ */ jsx25(Skeleton, { className: "w-16 h-6" })
5898
- ] }, i)) });
5899
- }
5900
- function SkeletonTable({
5901
- rows = 5,
5902
- columns = 4,
5903
- className = ""
5904
- }) {
5905
- return /* @__PURE__ */ jsxs8("div", { className: cn("border border-border rounded-lg overflow-hidden", className), children: [
5906
- /* @__PURE__ */ jsx25("div", { className: "flex gap-4 p-4 bg-muted/50 border-b border-border", children: Array.from({ length: columns }).map((_, i) => /* @__PURE__ */ jsx25(Skeleton, { className: "h-4 flex-1" }, i)) }),
5907
- Array.from({ length: rows }).map((_, rowIndex) => /* @__PURE__ */ jsx25("div", { className: "flex gap-4 p-4 border-b border-border last:border-0", children: Array.from({ length: columns }).map((_2, colIndex) => /* @__PURE__ */ jsx25(
5908
- Skeleton,
5909
- {
5910
- className: "h-4 flex-1",
5911
- style: { width: colIndex === 0 ? "40%" : void 0 }
5912
- },
5913
- colIndex
5914
- )) }, rowIndex))
5915
- ] });
5916
- }
5917
- function SkeletonAvatar({ size = "md", className = "" }) {
5918
- const sizes = {
5919
- sm: "w-8 h-8",
5920
- md: "w-10 h-10",
5921
- lg: "w-12 h-12"
5922
- };
5923
- return /* @__PURE__ */ jsx25(Skeleton, { className: cn(sizes[size], "rounded-full", className) });
5924
- }
5925
- function LoadingSpinner({ size = "md", className = "" }) {
5926
- const sizes = {
5927
- sm: "w-4 h-4",
5928
- md: "w-6 h-6",
5929
- lg: "w-8 h-8"
5930
- };
5931
- return /* @__PURE__ */ jsx25(
5932
- "div",
5933
- {
5934
- className: cn(sizes[size], "border-2 border-muted border-t-primary rounded-full animate-spin", className)
5935
- }
5936
- );
5937
- }
5938
- function LoadingOverlay({
5939
- children,
5940
- message,
5941
- className = ""
5942
- }) {
5943
- return /* @__PURE__ */ jsxs8("div", { className: cn("flex flex-col items-center justify-center py-16", className), children: [
5944
- /* @__PURE__ */ jsx25(LoadingSpinner, { size: "lg" }),
5945
- message && /* @__PURE__ */ jsx25("p", { className: "mt-4 text-muted-foreground", children: message }),
5946
- children
5947
- ] });
5948
- }
5949
-
5950
- // src/ui/CardGrid.tsx
5951
- import { MoreHorizontal, Trash2 } from "lucide-react";
5952
- import { jsx as jsx26, jsxs as jsxs9 } from "react/jsx-runtime";
5953
- function CardGrid({ children, columns = 3, className = "", ...rest }) {
5954
- const gridCols = {
5955
- 1: "grid-cols-1",
5956
- 2: "grid-cols-1 sm:grid-cols-2",
5957
- 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
5958
- 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
5959
- };
5960
- return /* @__PURE__ */ jsx26("div", { className: cn("grid gap-3 sm:gap-4", gridCols[columns], className), ...rest, children });
5961
- }
5962
- function GridCard({ children, onClick, className = "", hoverable = true, ...rest }) {
5963
- return /* @__PURE__ */ jsx26(
5964
- "div",
5965
- {
5966
- onClick,
5967
- className: cn(
5968
- "group relative bg-card rounded-xl border border-border overflow-hidden transition-all duration-200",
5969
- hoverable && "hover:border-border hover:shadow-card-hover hover:-translate-y-0.5",
5970
- onClick && "cursor-pointer",
5971
- className
5972
- ),
5973
- ...rest,
5974
- children
5975
- }
5976
- );
5977
- }
5978
- function GridCardImage({ src, alt = "", height = "md", className = "" }) {
5979
- const heights = {
5980
- sm: "h-24",
5981
- md: "h-36",
5982
- lg: "h-48"
5983
- };
5984
- return /* @__PURE__ */ jsx26("div", { className: cn(heights[height], "overflow-hidden bg-muted", className), children: /* @__PURE__ */ jsx26(
5985
- "img",
5986
- {
5987
- src,
5988
- alt,
5989
- referrerPolicy: "no-referrer",
5990
- className: "w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
5991
- }
5992
- ) });
5993
- }
5994
- function GridCardHeader({ children, actions, className = "" }) {
5995
- return /* @__PURE__ */ jsxs9("div", { className: cn("flex items-start justify-between gap-2 p-4 pb-2", className), children: [
5996
- /* @__PURE__ */ jsx26("div", { className: "flex-1 min-w-0", children }),
5997
- actions && /* @__PURE__ */ jsx26("div", { className: "sm:opacity-0 sm:group-hover:opacity-100 transition-opacity shrink-0", children: actions })
5998
- ] });
5999
- }
6000
- function GridCardTitle({ children, className = "" }) {
6001
- return /* @__PURE__ */ jsx26("h3", { className: cn("font-semibold text-foreground truncate", className), children });
6002
- }
6003
- function GridCardContent({ children, className = "" }) {
6004
- return /* @__PURE__ */ jsx26("div", { className: cn("px-4 pb-4", className), children });
6005
- }
6006
- function GridCardDescription({ children, lines = 2, className = "" }) {
6007
- const lineClamp = {
6008
- 1: "line-clamp-1",
6009
- 2: "line-clamp-2",
6010
- 3: "line-clamp-3",
6011
- 4: "line-clamp-4"
6012
- };
6013
- return /* @__PURE__ */ jsx26("p", { className: cn("text-sm text-muted-foreground leading-relaxed", lineClamp[lines], className), children });
6014
- }
6015
- function GridCardFooter({ children, className = "" }) {
6016
- return /* @__PURE__ */ jsx26("div", { className: cn("px-4 pb-4 pt-2 text-xs text-muted-foreground", className), children });
6017
- }
6018
- function GridCardBadge({ children, variant = "default", className = "" }) {
6019
- const variants = {
6020
- default: "bg-muted text-muted-foreground border-border",
6021
- success: "bg-success/20 text-success border-success/40",
6022
- warning: "bg-warning/20 text-warning border-warning/40",
6023
- danger: "bg-destructive/20 text-destructive border-destructive/40"
6024
- };
6025
- return /* @__PURE__ */ jsx26("span", { className: cn("inline-flex px-2 py-0.5 text-xs font-medium rounded border", variants[variant], className), children });
6026
- }
6027
- function GridCardActions({ onDelete, onMore }) {
6028
- const handleClick = (e, handler) => {
6029
- e.stopPropagation();
6030
- handler?.();
6031
- };
6032
- return /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1", children: [
6033
- onMore && /* @__PURE__ */ jsx26(
6034
- "button",
6035
- {
6036
- onClick: (e) => handleClick(e, onMore),
6037
- className: "p-2 rounded-lg bg-muted/50 hover:bg-muted text-muted-foreground hover:text-foreground transition-colors",
6038
- children: /* @__PURE__ */ jsx26(MoreHorizontal, { className: "w-4 h-4" })
6039
- }
6040
- ),
6041
- onDelete && /* @__PURE__ */ jsx26(
6042
- "button",
6043
- {
6044
- onClick: (e) => handleClick(e, onDelete),
6045
- className: "p-2 rounded-lg bg-muted/50 hover:bg-destructive/20 text-muted-foreground hover:text-destructive transition-colors",
6046
- children: /* @__PURE__ */ jsx26(Trash2, { className: "w-4 h-4" })
6047
- }
6048
- )
6049
- ] });
6050
- }
6051
- GridCard.Image = GridCardImage;
6052
- GridCard.Header = GridCardHeader;
6053
- GridCard.Title = GridCardTitle;
6054
- GridCard.Content = GridCardContent;
6055
- GridCard.Description = GridCardDescription;
6056
- GridCard.Footer = GridCardFooter;
6057
- GridCard.Badge = GridCardBadge;
6058
- GridCard.Actions = GridCardActions;
6059
-
6060
- // src/ui/Alert.tsx
6061
- import * as React20 from "react";
6062
- import { cva as cva4 } from "class-variance-authority";
6063
- import { jsx as jsx27 } from "react/jsx-runtime";
6064
- var alertVariants = cva4(
6065
- "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
6066
- {
6067
- variants: {
6068
- variant: {
6069
- default: "bg-background text-foreground",
6070
- destructive: "border-destructive/50 text-destructive [&>svg]:text-destructive",
6071
- success: "border-success/50 text-success [&>svg]:text-success",
6072
- warning: "border-warning/50 text-warning [&>svg]:text-warning",
6073
- info: "border-info/50 text-info [&>svg]:text-info"
6074
- }
6075
- },
6076
- defaultVariants: {
6077
- variant: "default"
6078
- }
6079
- }
6080
- );
6081
- var Alert = React20.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx27(
6082
- "div",
6083
- {
6084
- ref,
6085
- role: "alert",
6086
- className: cn(alertVariants({ variant }), className),
6087
- ...props
6088
- }
6089
- ));
6090
- Alert.displayName = "Alert";
6091
- var AlertTitle = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx27(
6092
- "h5",
6093
- {
6094
- ref,
6095
- className: cn("mb-1 font-medium leading-none tracking-tight", className),
6096
- ...props
6097
- }
6098
- ));
6099
- AlertTitle.displayName = "AlertTitle";
6100
- var AlertDescription = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx27(
6101
- "div",
6102
- {
6103
- ref,
6104
- className: cn("text-sm [&_p]:leading-relaxed", className),
6105
- ...props
6106
- }
6107
- ));
6108
- AlertDescription.displayName = "AlertDescription";
6109
-
6110
- // src/ui/Toast.tsx
6111
- import {
6112
- createContext as createContext4,
6113
- useContext as useContext6,
6114
- useState as useState19,
6115
- useCallback as useCallback28,
6116
- useEffect as useEffect22
6117
- } from "react";
6118
- import { jsx as jsx28, jsxs as jsxs10 } from "react/jsx-runtime";
6119
- function CheckCircleIcon({ className }) {
6120
- return /* @__PURE__ */ jsxs10("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
6121
- /* @__PURE__ */ jsx28("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
6122
- /* @__PURE__ */ jsx28("polyline", { points: "22 4 12 14.01 9 11.01" })
6123
- ] });
6124
- }
6125
- function AlertCircleIcon({ className }) {
6126
- return /* @__PURE__ */ jsxs10("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
6127
- /* @__PURE__ */ jsx28("circle", { cx: "12", cy: "12", r: "10" }),
6128
- /* @__PURE__ */ jsx28("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
6129
- /* @__PURE__ */ jsx28("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
6130
- ] });
6131
- }
6132
- function AlertTriangleIcon({ className }) {
6133
- return /* @__PURE__ */ jsxs10("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
6134
- /* @__PURE__ */ jsx28("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
6135
- /* @__PURE__ */ jsx28("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
6136
- /* @__PURE__ */ jsx28("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
6137
- ] });
6138
- }
6139
- function InfoIcon({ className }) {
6140
- return /* @__PURE__ */ jsxs10("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
6141
- /* @__PURE__ */ jsx28("circle", { cx: "12", cy: "12", r: "10" }),
6142
- /* @__PURE__ */ jsx28("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
6143
- /* @__PURE__ */ jsx28("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
6144
- ] });
6145
- }
6146
- function CloseIcon({ className }) {
6147
- return /* @__PURE__ */ jsxs10("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
6148
- /* @__PURE__ */ jsx28("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
6149
- /* @__PURE__ */ jsx28("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
6150
- ] });
6151
- }
6152
- var ToastContext = createContext4(null);
6153
- function useToast() {
6154
- const ctx = useContext6(ToastContext);
6155
- if (!ctx) throw new Error("useToast must be used within ToastProvider");
6156
- return ctx;
6157
- }
6158
- function ToastProvider({
6159
- children,
6160
- position = "bottom-right",
6161
- maxToasts = 5
6162
- }) {
6163
- const [toasts, setToasts] = useState19([]);
6164
- const dismiss = useCallback28((id) => {
6165
- setToasts((prev) => prev.filter((t) => t.id !== id));
6166
- }, []);
6167
- const dismissAll = useCallback28(() => {
6168
- setToasts([]);
6169
- }, []);
6170
- const addToast = useCallback28(
6171
- (options) => {
6172
- const id = Math.random().toString(36).slice(2);
6173
- const duration = options.duration ?? 5e3;
6174
- setToasts((prev) => {
6175
- const next = [...prev, { ...options, id }];
6176
- return next.slice(-maxToasts);
6177
- });
6178
- if (duration > 0) {
6179
- setTimeout(() => dismiss(id), duration);
6180
- }
6181
- },
6182
- [dismiss, maxToasts]
6183
- );
6184
- const toast = useCallback28(
6185
- (options) => addToast(options),
6186
- [addToast]
6187
- );
6188
- const success = useCallback28(
6189
- (title, description) => addToast({ type: "success", title, description }),
6190
- [addToast]
6191
- );
6192
- const error = useCallback28(
6193
- (title, description) => addToast({ type: "error", title, description }),
6194
- [addToast]
6195
- );
6196
- const warning = useCallback28(
6197
- (title, description) => addToast({ type: "warning", title, description }),
6198
- [addToast]
6199
- );
6200
- const info = useCallback28(
6201
- (title, description) => addToast({ type: "info", title, description }),
6202
- [addToast]
6203
- );
6204
- const positionClasses = {
6205
- "top-right": "top-4 right-4",
6206
- "top-left": "top-4 left-4",
6207
- "bottom-right": "bottom-4 right-4",
6208
- "bottom-left": "bottom-4 left-4",
6209
- "top-center": "top-4 left-1/2 -translate-x-1/2",
6210
- "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
6211
- };
6212
- return /* @__PURE__ */ jsxs10(
6213
- ToastContext.Provider,
6214
- {
6215
- value: { toasts, toast, success, error, warning, info, dismiss, dismissAll },
6216
- children: [
6217
- children,
6218
- /* @__PURE__ */ jsx28(
6219
- "div",
6220
- {
6221
- className: `fixed z-[100] flex flex-col gap-2 ${positionClasses[position]}`,
6222
- children: toasts.map((t) => /* @__PURE__ */ jsx28(ToastItem, { toast: t, onDismiss: () => dismiss(t.id) }, t.id))
6223
- }
6224
- )
6225
- ]
6226
- }
6227
- );
6228
- }
6229
- var TOAST_CONFIG = {
6230
- success: { Icon: CheckCircleIcon, accent: "bg-success", icon: "text-success" },
6231
- error: { Icon: AlertCircleIcon, accent: "bg-destructive", icon: "text-destructive" },
6232
- warning: { Icon: AlertTriangleIcon, accent: "bg-warning", icon: "text-warning" },
6233
- info: { Icon: InfoIcon, accent: "bg-info", icon: "text-info" }
6234
- };
6235
- function ToastItem({ toast, onDismiss }) {
6236
- const { Icon: Icon2, accent, icon } = TOAST_CONFIG[toast.type];
6237
- const [exiting, setExiting] = useState19(false);
6238
- useEffect22(() => {
6239
- if (exiting) {
6240
- const timer = setTimeout(onDismiss, 150);
6241
- return () => clearTimeout(timer);
6242
- }
6243
- }, [exiting, onDismiss]);
6244
- return /* @__PURE__ */ jsxs10(
6245
- "div",
6246
- {
6247
- className: `
6248
- relative flex items-start gap-2.5 min-w-[260px] max-w-[360px]
6249
- overflow-hidden rounded-lg border border-border bg-popover
6250
- text-popover-foreground pl-3.5 pr-2 py-2.5 shadow-lg
6251
- ${exiting ? "animate-out fade-out-0 slide-out-to-right-2 duration-150" : "animate-in fade-in-0 slide-in-from-right-2 duration-200"}
6252
- `,
6253
- role: "alert",
6254
- children: [
6255
- /* @__PURE__ */ jsx28("span", { className: `absolute inset-y-0 left-0 w-[3px] ${accent}`, "aria-hidden": true }),
6256
- /* @__PURE__ */ jsx28(Icon2, { className: `mt-0.5 h-4 w-4 shrink-0 ${icon}` }),
6257
- /* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-0", children: [
6258
- /* @__PURE__ */ jsx28("p", { className: "text-[13px] font-medium leading-tight", children: toast.title }),
6259
- toast.description && /* @__PURE__ */ jsx28("p", { className: "mt-0.5 text-xs leading-snug text-muted-foreground", children: toast.description })
6260
- ] }),
6261
- /* @__PURE__ */ jsx28(
6262
- "button",
6263
- {
6264
- onClick: () => setExiting(true),
6265
- className: "-mr-0.5 shrink-0 rounded p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
6266
- "aria-label": "Dismiss",
6267
- children: /* @__PURE__ */ jsx28(CloseIcon, { className: "h-3.5 w-3.5" })
6268
- }
6269
- )
6270
- ]
6271
- }
6272
- );
6273
- }
6274
-
6275
- // src/ui/ErrorBoundary.tsx
6276
- import { AlertTriangle, RefreshCw } from "lucide-react";
6277
- import { jsx as jsx29, jsxs as jsxs11 } from "react/jsx-runtime";
6278
- var REACT_ERROR_TABLE = {
6279
- 300: {
6280
- title: "A component changed how many hooks it runs",
6281
- explanation: "This component called fewer hooks than it did on its previous render.",
6282
- hint: "Almost always an early return placed above a hook. Move every hook (useState, useEffect, useQuery, \u2026) above any conditional return so the same hooks run in the same order on every render."
6283
- },
6284
- 310: {
6285
- title: "A component changed how many hooks it runs",
6286
- explanation: "This component called more hooks than it did on its previous render.",
6287
- hint: "Almost always an early return placed above a hook. Move every hook (useState, useEffect, useQuery, \u2026) above any conditional return so the same hooks run in the same order on every render."
6288
- },
6289
- 301: {
6290
- title: "Too many re-renders",
6291
- explanation: "React hit its render limit because the component updated state while rendering, which triggers an infinite render loop.",
6292
- hint: "Don\u2019t call setState (or a mutation) directly in the render body. Move it into an event handler or an effect with the right dependencies."
6293
- },
6294
- 321: {
6295
- title: "A hook was called in an invalid place",
6296
- explanation: "Hooks can only be called at the top level of a function component or another hook.",
6297
- hint: "Move the hook out of any condition, loop, callback, or plain (non-component) function. This can also mean two copies of React are installed."
6298
- }
6299
- };
6300
- function extractReactErrorCode(message) {
6301
- const patterns = [/react\.dev\/errors\/(\d+)/, /invariant=(\d+)/, /Minified React error #(\d+)/];
6302
- for (const re of patterns) {
6303
- const match = message.match(re);
6304
- if (match) return Number(match[1]);
6305
- }
6306
- return null;
6307
- }
6308
- function errorMessage(error) {
6309
- if (typeof error === "string") return error;
6310
- if (error instanceof Error) return error.message;
6311
- return null;
6312
- }
6313
- function decodeReactError(error) {
6314
- const message = errorMessage(error);
6315
- if (!message) return null;
6316
- const code = extractReactErrorCode(message);
6317
- if (code == null) return null;
6318
- const known = REACT_ERROR_TABLE[code];
6319
- return {
6320
- code,
6321
- docsUrl: `https://react.dev/errors/${code}`,
6322
- title: known?.title ?? `React error #${code}`,
6323
- explanation: known?.explanation ?? "React stopped rendering because of an error.",
6324
- hint: known?.hint ?? "Run the app in development (npm run dev) to see the full, unminified message and the component that failed."
6325
- };
6326
- }
6327
- function ErrorScreen({ error, onReset }) {
6328
- const decoded = decodeReactError(error);
6329
- const rawMessage = error instanceof Error ? error.message : typeof error === "string" ? error : "";
6330
- const stack = error instanceof Error ? error.stack : void 0;
6331
- const reset = onReset ?? (() => window.location.reload());
6332
- return /* @__PURE__ */ jsx29(
6333
- "div",
6334
- {
6335
- "data-testid": "ds-error-boundary",
6336
- className: "flex h-full min-h-[60vh] flex-col items-center justify-center bg-background px-4 py-10 text-foreground",
6337
- children: /* @__PURE__ */ jsxs11("div", { className: "w-full max-w-lg text-center", children: [
6338
- /* @__PURE__ */ jsx29("div", { className: "mb-4 flex justify-center", children: /* @__PURE__ */ jsx29("span", { className: "inline-flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10 text-destructive", children: /* @__PURE__ */ jsx29(AlertTriangle, { className: "h-6 w-6", "aria-hidden": true }) }) }),
6339
- /* @__PURE__ */ jsx29("h1", { className: "text-lg font-semibold tracking-tight", children: decoded?.title ?? "Something went wrong" }),
6340
- decoded?.explanation && /* @__PURE__ */ jsx29("p", { className: "mt-1.5 text-sm text-muted-foreground", children: decoded.explanation }),
6341
- decoded?.hint && /* @__PURE__ */ jsxs11(Alert, { variant: "warning", className: "mt-4 text-left", children: [
6342
- /* @__PURE__ */ jsx29(AlertTitle, { children: "How to fix" }),
6343
- /* @__PURE__ */ jsx29(AlertDescription, { children: decoded.hint })
6344
- ] }),
6345
- rawMessage && /* @__PURE__ */ jsx29("pre", { className: "mt-4 overflow-x-auto rounded-lg border bg-muted/40 px-3 py-2 text-left text-xs text-muted-foreground", children: rawMessage }),
6346
- stack && /* @__PURE__ */ jsxs11("details", { className: "mt-2 text-left", children: [
6347
- /* @__PURE__ */ jsx29("summary", { className: "cursor-pointer text-xs text-muted-foreground", children: "Show stack trace" }),
6348
- /* @__PURE__ */ jsx29("pre", { className: "mt-1 max-h-60 overflow-auto rounded-lg border bg-muted/40 px-3 py-2 text-xs text-muted-foreground", children: stack })
6349
- ] }),
6350
- /* @__PURE__ */ jsxs11("div", { className: "mt-6 flex items-center justify-center gap-3", children: [
6351
- /* @__PURE__ */ jsxs11(Button, { onClick: reset, children: [
6352
- /* @__PURE__ */ jsx29(RefreshCw, { className: "h-4 w-4", "aria-hidden": true }),
6353
- "Reload"
6354
- ] }),
6355
- decoded && /* @__PURE__ */ jsxs11(
6356
- "a",
6357
- {
6358
- href: decoded.docsUrl,
6359
- target: "_blank",
6360
- rel: "noreferrer",
6361
- className: "text-sm text-muted-foreground underline-offset-4 hover:underline",
6362
- children: [
6363
- "React error #",
6364
- decoded.code,
6365
- " reference"
6366
- ]
6367
- }
6368
- )
6369
- ] })
6370
- ] })
6371
- }
6372
- );
6373
- }
6374
-
6375
- // src/ui/EmptyState.tsx
6376
- import { FileText, Search, Inbox, Plus, FolderOpen, Users, AlertCircle } from "lucide-react";
6377
- import { jsx as jsx30, jsxs as jsxs12 } from "react/jsx-runtime";
6378
- function EmptyState({
6379
- icon,
6380
- title,
6381
- description,
6382
- action,
6383
- secondaryAction,
6384
- className = "",
6385
- ...rest
6386
- }) {
6387
- return /* @__PURE__ */ jsxs12("div", { className: cn("flex flex-col items-center justify-center py-16 px-4 text-center", className), ...rest, children: [
6388
- icon && /* @__PURE__ */ jsx30("div", { className: "w-16 h-16 rounded-2xl bg-muted/50 border border-border flex items-center justify-center mb-5", children: /* @__PURE__ */ jsx30("span", { className: "text-muted-foreground", children: icon }) }),
6389
- /* @__PURE__ */ jsx30("h3", { className: "text-lg font-semibold text-foreground mb-2", children: title }),
6390
- description && /* @__PURE__ */ jsx30("p", { className: "text-muted-foreground text-sm max-w-sm mb-6", children: description }),
6391
- (action || secondaryAction) && /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-3", children: [
6392
- action && /* @__PURE__ */ jsxs12(
6393
- "button",
6394
- {
6395
- onClick: action.onClick,
6396
- className: "inline-flex items-center gap-2 px-4 py-2 bg-primary text-primary-foreground rounded-lg font-medium text-sm hover:bg-primary/90 shadow-lg shadow-primary/25 transition-all",
6397
- children: [
6398
- /* @__PURE__ */ jsx30(Plus, { className: "w-4 h-4" }),
6399
- action.label
6400
- ]
6401
- }
6402
- ),
6403
- secondaryAction && /* @__PURE__ */ jsx30(
6404
- "button",
6405
- {
6406
- onClick: secondaryAction.onClick,
6407
- className: "px-4 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors",
6408
- children: secondaryAction.label
6409
- }
6410
- )
6411
- ] })
6412
- ] });
6413
- }
6414
- function EmptyItems({ action, className }) {
6415
- return /* @__PURE__ */ jsx30(
6416
- EmptyState,
6417
- {
6418
- icon: /* @__PURE__ */ jsx30(Inbox, { className: "w-8 h-8" }),
6419
- title: "No items yet",
6420
- description: "Get started by creating your first item.",
6421
- action: action ? { label: action.label, onClick: action.onClick } : void 0,
6422
- className
6423
- }
6424
- );
6425
- }
6426
- function EmptySearch({ query, onClear, className }) {
6427
- return /* @__PURE__ */ jsx30(
6428
- EmptyState,
6429
- {
6430
- icon: /* @__PURE__ */ jsx30(Search, { className: "w-8 h-8" }),
6431
- title: "No results found",
6432
- description: query ? `No results for "${query}". Try a different search term.` : "Try adjusting your search or filters.",
6433
- secondaryAction: onClear ? { label: "Clear search", onClick: onClear } : void 0,
6434
- className
6435
- }
6436
- );
6437
- }
6438
- function EmptyDocuments({ action, className }) {
6439
- return /* @__PURE__ */ jsx30(
6440
- EmptyState,
6441
- {
6442
- icon: /* @__PURE__ */ jsx30(FileText, { className: "w-8 h-8" }),
6443
- title: "No documents",
6444
- description: "Create a document to start writing.",
6445
- action: action ? { label: action.label, onClick: action.onClick } : void 0,
6446
- className
6447
- }
6448
- );
6449
- }
6450
- function EmptyProjects({ action, className }) {
6451
- return /* @__PURE__ */ jsx30(
6452
- EmptyState,
6453
- {
6454
- icon: /* @__PURE__ */ jsx30(FolderOpen, { className: "w-8 h-8" }),
6455
- title: "No projects",
6456
- description: "Create a project to organize your work.",
6457
- action: action ? { label: action.label, onClick: action.onClick } : void 0,
6458
- className
6459
- }
6460
- );
6461
- }
6462
- function EmptyTeam({ action, className }) {
6463
- return /* @__PURE__ */ jsx30(
6464
- EmptyState,
6465
- {
6466
- icon: /* @__PURE__ */ jsx30(Users, { className: "w-8 h-8" }),
6467
- title: "No team members",
6468
- description: "Invite people to collaborate with you.",
6469
- action: action ? { label: action.label, onClick: action.onClick } : void 0,
6470
- className
6471
- }
6472
- );
6473
- }
6474
- function EmptyError({ error, onRetry, className }) {
6475
- return /* @__PURE__ */ jsx30(
6476
- EmptyState,
6477
- {
6478
- icon: /* @__PURE__ */ jsx30(AlertCircle, { className: "w-8 h-8 text-destructive" }),
6479
- title: "Something went wrong",
6480
- description: error || "An error occurred. Please try again.",
6481
- action: onRetry ? { label: "Try again", onClick: onRetry } : void 0,
6482
- className
6483
- }
6484
- );
6485
- }
6486
-
6487
- // src/ui/Dialog.tsx
6488
- import * as React22 from "react";
6489
- import * as DialogPrimitive from "@radix-ui/react-dialog";
6490
- import { X } from "lucide-react";
6491
- import { jsx as jsx31, jsxs as jsxs13 } from "react/jsx-runtime";
6492
- var Dialog = DialogPrimitive.Root;
6493
- var DialogTrigger = DialogPrimitive.Trigger;
6494
- var DialogPortal = DialogPrimitive.Portal;
6495
- var DialogClose = DialogPrimitive.Close;
6496
- var DialogOverlay = React22.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(
6497
- DialogPrimitive.Overlay,
6498
- {
6499
- ref,
6500
- className: cn(
6501
- "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
6502
- className
6503
- ),
6504
- ...props
6505
- }
6506
- ));
6507
- DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
6508
- var DialogContent = React22.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs13(DialogPortal, { children: [
6509
- /* @__PURE__ */ jsx31(DialogOverlay, {}),
6510
- /* @__PURE__ */ jsxs13(
6511
- DialogPrimitive.Content,
6512
- {
6513
- ref,
6514
- className: cn(
6515
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-[calc(100vw-2rem)] sm:max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background/95 backdrop-blur-2xl p-4 sm:p-6 shadow-card-hover duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-2xl",
6516
- className
6517
- ),
6518
- ...props,
6519
- children: [
6520
- children,
6521
- /* @__PURE__ */ jsxs13(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm p-1 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
6522
- /* @__PURE__ */ jsx31(X, { className: "h-4 w-4" }),
6523
- /* @__PURE__ */ jsx31("span", { className: "sr-only", children: "Close" })
6524
- ] })
6525
- ]
6526
- }
6527
- )
6528
- ] }));
6529
- DialogContent.displayName = DialogPrimitive.Content.displayName;
6530
- var DialogHeader = ({
6531
- className,
6532
- ...props
6533
- }) => /* @__PURE__ */ jsx31(
6534
- "div",
6535
- {
6536
- className: cn(
6537
- "flex flex-col space-y-1.5 text-center sm:text-left",
6538
- className
6539
- ),
6540
- ...props
6541
- }
6542
- );
6543
- DialogHeader.displayName = "DialogHeader";
6544
- var DialogFooter = ({
6545
- className,
6546
- ...props
6547
- }) => /* @__PURE__ */ jsx31(
6548
- "div",
6549
- {
6550
- className: cn(
6551
- "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
6552
- className
6553
- ),
6554
- ...props
6555
- }
6556
- );
6557
- DialogFooter.displayName = "DialogFooter";
6558
- var DialogTitle = React22.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(
6559
- DialogPrimitive.Title,
6560
- {
6561
- ref,
6562
- className: cn(
6563
- "text-lg font-semibold leading-none tracking-tight",
6564
- className
6565
- ),
6566
- ...props
6567
- }
6568
- ));
6569
- DialogTitle.displayName = DialogPrimitive.Title.displayName;
6570
- var DialogDescription = React22.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(
6571
- DialogPrimitive.Description,
6572
- {
6573
- ref,
6574
- className: cn("text-sm text-muted-foreground", className),
6575
- ...props
6576
- }
6577
- ));
6578
- DialogDescription.displayName = DialogPrimitive.Description.displayName;
6579
-
6580
- // src/ui/DropdownMenu.tsx
6581
- import * as React23 from "react";
6582
- import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
6583
- import { Check as Check3, ChevronRight, Circle } from "lucide-react";
6584
- import { jsx as jsx32, jsxs as jsxs14 } from "react/jsx-runtime";
6585
- var DropdownMenu = DropdownMenuPrimitive.Root;
6586
- var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
6587
- var DropdownMenuGroup = DropdownMenuPrimitive.Group;
6588
- var DropdownMenuPortal = DropdownMenuPrimitive.Portal;
6589
- var DropdownMenuSub = DropdownMenuPrimitive.Sub;
6590
- var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
6591
- var DropdownMenuSubTrigger = React23.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
6592
- DropdownMenuPrimitive.SubTrigger,
6593
- {
6594
- ref,
6595
- className: cn(
6596
- "flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
6597
- inset && "pl-8",
6598
- className
6599
- ),
6600
- ...props,
6601
- children: [
6602
- children,
6603
- /* @__PURE__ */ jsx32(ChevronRight, { className: "ml-auto" })
6604
- ]
6605
- }
6606
- ));
6607
- DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
6608
- var DropdownMenuSubContent = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx32(
6609
- DropdownMenuPrimitive.SubContent,
6610
- {
6611
- ref,
6612
- className: cn(
6613
- "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
6614
- className
6615
- ),
6616
- ...props
6617
- }
6618
- ));
6619
- DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
6620
- var DropdownMenuContent = React23.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx32(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx32(
6621
- DropdownMenuPrimitive.Content,
6622
- {
6623
- ref,
6624
- sideOffset,
6625
- className: cn(
6626
- "z-50 min-w-[8rem] max-w-[calc(100vw-1rem)] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
6627
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
6628
- className
6629
- ),
6630
- ...props
6631
- }
6632
- ) }));
6633
- DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
6634
- var DropdownMenuItem = React23.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx32(
6635
- DropdownMenuPrimitive.Item,
6636
- {
6637
- ref,
6638
- className: cn(
6639
- "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
6640
- inset && "pl-8",
6641
- className
6642
- ),
6643
- ...props
6644
- }
6645
- ));
6646
- DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
6647
- var DropdownMenuCheckboxItem = React23.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs14(
6648
- DropdownMenuPrimitive.CheckboxItem,
6649
- {
6650
- ref,
6651
- className: cn(
6652
- "relative flex cursor-default select-none items-center rounded-sm py-2 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
6653
- className
6654
- ),
6655
- checked,
6656
- ...props,
6657
- children: [
6658
- /* @__PURE__ */ jsx32("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx32(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx32(Check3, { className: "h-4 w-4" }) }) }),
6659
- children
6660
- ]
6661
- }
6662
- ));
6663
- DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
6664
- var DropdownMenuRadioItem = React23.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
6665
- DropdownMenuPrimitive.RadioItem,
6666
- {
6667
- ref,
6668
- className: cn(
6669
- "relative flex cursor-default select-none items-center rounded-sm py-2 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
6670
- className
6671
- ),
6672
- ...props,
6673
- children: [
6674
- /* @__PURE__ */ jsx32("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx32(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx32(Circle, { className: "h-2 w-2 fill-current" }) }) }),
6675
- children
6676
- ]
6677
- }
6678
- ));
6679
- DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
6680
- var DropdownMenuLabel = React23.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx32(
6681
- DropdownMenuPrimitive.Label,
6682
- {
6683
- ref,
6684
- className: cn(
6685
- "px-2 py-1.5 text-sm font-semibold",
6686
- inset && "pl-8",
6687
- className
6688
- ),
6689
- ...props
6690
- }
6691
- ));
6692
- DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
6693
- var DropdownMenuSeparator = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx32(
6694
- DropdownMenuPrimitive.Separator,
6695
- {
6696
- ref,
6697
- className: cn("-mx-1 my-1 h-px bg-muted", className),
6698
- ...props
6699
- }
6700
- ));
6701
- DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
6702
- var DropdownMenuShortcut = ({
6703
- className,
6704
- ...props
6705
- }) => {
6706
- return /* @__PURE__ */ jsx32(
6707
- "span",
6708
- {
6709
- className: cn("ml-auto text-xs tracking-widest opacity-60", className),
6710
- ...props
6711
- }
6712
- );
6713
- };
6714
- DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
6715
-
6716
- // src/ui/Tooltip.tsx
6717
- import * as React24 from "react";
6718
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
6719
- import { jsx as jsx33 } from "react/jsx-runtime";
6720
- var TooltipProvider = TooltipPrimitive.Provider;
6721
- var Tooltip = TooltipPrimitive.Root;
6722
- var TooltipTrigger = TooltipPrimitive.Trigger;
6723
- var TooltipContent = React24.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx33(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx33(
6724
- TooltipPrimitive.Content,
6725
- {
6726
- ref,
6727
- sideOffset,
6728
- className: cn(
6729
- "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
6730
- className
6731
- ),
6732
- ...props
6733
- }
6734
- ) }));
6735
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
6736
-
6737
- // src/ui/Modal.tsx
6738
- import { jsx as jsx34, jsxs as jsxs15 } from "react/jsx-runtime";
6739
- function Modal({
6740
- open,
6741
- onClose,
6742
- children,
6743
- size = "md",
6744
- className
6745
- }) {
6746
- const sizes = {
6747
- sm: "max-w-[calc(100vw-2rem)] sm:max-w-sm",
6748
- md: "max-w-[calc(100vw-2rem)] sm:max-w-lg",
6749
- lg: "max-w-[calc(100vw-2rem)] sm:max-w-2xl",
6750
- xl: "max-w-[calc(100vw-2rem)] sm:max-w-4xl"
6751
- };
6752
- return /* @__PURE__ */ jsx34(Dialog, { open, onOpenChange: (v) => {
6753
- if (!v) onClose();
6754
- }, children: /* @__PURE__ */ jsx34(DialogContent, { "aria-describedby": void 0, className: cn(sizes[size], "flex flex-col max-h-[85vh]", className), children }) });
6755
- }
6756
- function ModalHeader({ children, className = "" }) {
6757
- return /* @__PURE__ */ jsx34(DialogHeader, { className, children });
6758
- }
6759
- function ModalTitle({ children, className = "" }) {
6760
- return /* @__PURE__ */ jsx34(DialogTitle, { className, children });
6761
- }
6762
- function ModalDescription({ children, className = "" }) {
6763
- return /* @__PURE__ */ jsx34(DialogDescription, { className, children });
6764
- }
6765
- function ModalBody({ children, className = "" }) {
6766
- return /* @__PURE__ */ jsx34("div", { className: cn("flex-1 overflow-y-auto py-4", className), children });
6767
- }
6768
- function ModalFooter({ children, className = "" }) {
6769
- return /* @__PURE__ */ jsx34(DialogFooter, { className, children });
6770
- }
6771
- function ConfirmModal({
6772
- open,
6773
- onClose,
6774
- onConfirm,
6775
- title,
6776
- description,
6777
- confirmText = "Confirm",
6778
- cancelText = "Cancel",
6779
- variant = "destructive",
6780
- loading = false
6781
- }) {
6782
- return /* @__PURE__ */ jsxs15(Modal, { open, onClose, size: "sm", children: [
6783
- /* @__PURE__ */ jsxs15(Modal.Header, { children: [
6784
- /* @__PURE__ */ jsx34(Modal.Title, { children: title }),
6785
- description && /* @__PURE__ */ jsx34(Modal.Description, { children: description })
6786
- ] }),
6787
- /* @__PURE__ */ jsxs15(Modal.Footer, { children: [
6788
- /* @__PURE__ */ jsx34(Button, { variant: "ghost", onClick: onClose, disabled: loading, children: cancelText }),
6789
- /* @__PURE__ */ jsx34(Button, { variant, onClick: onConfirm, loading, children: confirmText })
6790
- ] })
6791
- ] });
6792
- }
6793
- Modal.Header = ModalHeader;
6794
- Modal.Title = ModalTitle;
6795
- Modal.Description = ModalDescription;
6796
- Modal.Body = ModalBody;
6797
- Modal.Footer = ModalFooter;
6798
-
6799
- // src/ui/SearchInput.tsx
6800
- import * as React25 from "react";
6801
- import { Search as Search2, X as X2 } from "lucide-react";
6802
- import { jsx as jsx35, jsxs as jsxs16 } from "react/jsx-runtime";
6803
- var SearchInput = React25.forwardRef(
6804
- ({ className, onClear, value, ...props }, ref) => {
6805
- return /* @__PURE__ */ jsxs16("div", { className: "relative", children: [
6806
- /* @__PURE__ */ jsx35(Search2, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
6807
- /* @__PURE__ */ jsx35(
6808
- Input,
6809
- {
6810
- ref,
6811
- type: "search",
6812
- className: cn("pl-9 pr-9", className),
6813
- value,
6814
- ...props
6815
- }
6816
- ),
6817
- value && onClear && /* @__PURE__ */ jsx35(
6818
- "button",
6819
- {
6820
- type: "button",
6821
- onClick: onClear,
6822
- className: "absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground hover:text-foreground transition-colors",
6823
- children: /* @__PURE__ */ jsx35(X2, { className: "h-4 w-4" })
6824
- }
6825
- )
6826
- ] });
6827
- }
6828
- );
6829
- SearchInput.displayName = "SearchInput";
6830
5871
  export {
6831
- Alert,
6832
- AlertDescription,
6833
- AlertTitle,
5872
+ ASYNC_RESOURCE_DEFAULTS,
6834
5873
  AuthGate,
6835
5874
  AuthOverlay,
6836
- Avatar,
6837
- AvatarFallback,
6838
- AvatarImage,
6839
5875
  Awareness,
6840
- Badge,
6841
- Button,
6842
- Card,
6843
- CardContent,
6844
- CardDescription,
6845
- CardFooter,
6846
- CardGrid,
6847
- CardHeader,
6848
- CardTitle,
6849
- Checkbox,
6850
- ConfirmModal,
6851
5876
  DEEPSPACE_THEME_PROPERTIES,
6852
5877
  DEFAULT_USER_COLORS,
6853
5878
  DeepSpaceAuthProvider,
6854
5879
  DeepSpaceThemeProvider,
6855
- Dialog,
6856
- DialogClose,
6857
- DialogContent,
6858
- DialogDescription,
6859
- DialogFooter,
6860
- DialogHeader,
6861
- DialogOverlay,
6862
- DialogPortal,
6863
- DialogTitle,
6864
- DialogTrigger,
6865
- DropdownMenu,
6866
- DropdownMenuCheckboxItem,
6867
- DropdownMenuContent,
6868
- DropdownMenuGroup,
6869
- DropdownMenuItem,
6870
- DropdownMenuLabel,
6871
- DropdownMenuPortal,
6872
- DropdownMenuRadioGroup,
6873
- DropdownMenuRadioItem,
6874
- DropdownMenuSeparator,
6875
- DropdownMenuShortcut,
6876
- DropdownMenuSub,
6877
- DropdownMenuSubContent,
6878
- DropdownMenuSubTrigger,
6879
- DropdownMenuTrigger,
6880
5880
  ENV,
6881
- EmptyDocuments,
6882
- EmptyError,
6883
- EmptyItems,
6884
- EmptyProjects,
6885
- EmptySearch,
6886
- EmptyState,
6887
- EmptyTeam,
6888
- ErrorScreen,
6889
- GridCard,
6890
5881
  GuestBanner,
6891
- Input,
6892
- Label2 as Label,
6893
- LoadingOverlay,
6894
- LoadingSpinner,
6895
5882
  MSG,
6896
5883
  MSG_AWARENESS,
6897
5884
  MSG_SYNC,
@@ -6900,11 +5887,9 @@ export {
6900
5887
  MSG_SYNC_UPDATE,
6901
5888
  MSG_YJS_AWARENESS,
6902
5889
  MSG_YJS_SYNC,
6903
- Modal,
6904
5890
  PlatformContext,
6905
5891
  PlatformProvider,
6906
5892
  PricingTable,
6907
- Progress,
6908
5893
  ROLES,
6909
5894
  ROLE_ADMIN,
6910
5895
  ROLE_ANONYMOUS,
@@ -6913,56 +5898,20 @@ export {
6913
5898
  RecordProvider,
6914
5899
  RecordScope,
6915
5900
  ScopeRegistryProvider,
6916
- SearchInput,
6917
- Select,
6918
- SelectContent,
6919
- SelectGroup,
6920
- SelectItem,
6921
- SelectLabel,
6922
- SelectSeparator,
6923
- SelectTrigger,
6924
- SelectValue,
6925
- Separator,
6926
5901
  SignedIn,
6927
5902
  SignedOut,
6928
- Skeleton,
6929
- SkeletonAvatar,
6930
- SkeletonCard,
6931
- SkeletonList,
6932
- SkeletonTable,
6933
- SkeletonText,
6934
- Switch,
6935
- Table,
6936
- TableBody,
6937
- TableCaption,
6938
- TableCell,
6939
- TableFooter,
6940
- TableHead,
6941
- TableHeader,
6942
- TableRow,
6943
- Tabs,
6944
- TabsContent,
6945
- TabsList,
6946
- TabsTrigger,
6947
- Textarea,
6948
- ToastProvider,
6949
- Tooltip,
6950
- TooltipContent,
6951
- TooltipProvider,
6952
- TooltipTrigger,
6953
5903
  applyDeepSpaceTheme,
6954
5904
  applyUIThemeTokens,
6955
5905
  authClient,
6956
- badgeVariants,
6957
- buttonVariants,
5906
+ canAutoLoadPagedResource,
5907
+ clampPagedResourceItems,
6958
5908
  clearAuthToken,
6959
5909
  clearDeepSpaceTheme,
6960
5910
  clientBuild,
6961
- cn,
6962
5911
  createDecoder,
6963
5912
  createEncoder,
6964
5913
  decodeAiStreamChunk,
6965
- decodeReactError,
5914
+ deriveLoadState,
6966
5915
  detectEnvironment,
6967
5916
  dispatch,
6968
5917
  encode,
@@ -6980,6 +5929,7 @@ export {
6980
5929
  getConversationParticipantIds,
6981
5930
  getEnvironmentConfig,
6982
5931
  getMessageType,
5932
+ getPagedResourceCooldownMs,
6983
5933
  getPlatformWorkerUrl,
6984
5934
  getThreadCounts,
6985
5935
  getUserColor,
@@ -6988,6 +5938,7 @@ export {
6988
5938
  handleSyncMessage,
6989
5939
  hasContent,
6990
5940
  integration,
5941
+ isAsyncResourceSlow,
6991
5942
  isDMConversation,
6992
5943
  isDarkColor,
6993
5944
  isImageFile,
@@ -7005,7 +5956,11 @@ export {
7005
5956
  signOut,
7006
5957
  toConnectionStatus,
7007
5958
  toUint8Array,
5959
+ useAsyncResource,
7008
5960
  useAuth,
5961
+ useAuthProfileReady,
5962
+ useAuthReady,
5963
+ useAuthStatus,
7009
5964
  useAuthUser,
7010
5965
  useCanvas,
7011
5966
  useChannelMembers,
@@ -7022,6 +5977,7 @@ export {
7022
5977
  useJobs,
7023
5978
  useMessages,
7024
5979
  useMutations,
5980
+ usePagedResource,
7025
5981
  usePlatform,
7026
5982
  usePlatformWS,
7027
5983
  usePosts,
@@ -7034,10 +5990,10 @@ export {
7034
5990
  useRecordContext,
7035
5991
  useSession,
7036
5992
  useSubscription,
7037
- useToast,
7038
5993
  useUser,
7039
5994
  useUserLookup,
7040
5995
  useUsers,
5996
+ useVoiceAgent,
7041
5997
  useYjsField,
7042
5998
  useYjsRoom,
7043
5999
  useYjsText,