@nby.ai/ucm 1.0.1

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 ADDED
@@ -0,0 +1,759 @@
1
+ // src/core.ts
2
+ import { createClient } from "@supabase/supabase-js";
3
+
4
+ // src/types.ts
5
+ function getLocalizedText(text, locale, fallback = "en") {
6
+ if (!text) return "";
7
+ return text[locale] || text[fallback] || Object.values(text)[0] || "";
8
+ }
9
+ function buildCategoryTree(categories) {
10
+ const map = /* @__PURE__ */ new Map();
11
+ const roots = [];
12
+ categories.forEach((cat) => {
13
+ map.set(cat.id, { ...cat, children: [] });
14
+ });
15
+ categories.forEach((cat) => {
16
+ const node = map.get(cat.id);
17
+ if (cat.parent_id && map.has(cat.parent_id)) {
18
+ map.get(cat.parent_id).children.push(node);
19
+ } else {
20
+ roots.push(node);
21
+ }
22
+ });
23
+ const sortByOrder = (a, b) => a.sort_order - b.sort_order;
24
+ roots.sort(sortByOrder);
25
+ roots.forEach((root) => root.children?.sort(sortByOrder));
26
+ return roots;
27
+ }
28
+
29
+ // src/core.ts
30
+ function createUCMClient(config) {
31
+ const { url, anonKey, options = {} } = config;
32
+ if (!url || !anonKey) {
33
+ throw new Error("UCM: url and anonKey are required");
34
+ }
35
+ const supabase = createClient(url, anonKey, {
36
+ auth: {
37
+ persistSession: options.persistSession ?? false,
38
+ autoRefreshToken: options.autoRefreshToken ?? false
39
+ }
40
+ });
41
+ const contents = {
42
+ async list(params = {}) {
43
+ const {
44
+ type,
45
+ category_id,
46
+ tags,
47
+ featured,
48
+ visibility,
49
+ // v2.0: 可见性筛选
50
+ limit = 20,
51
+ offset = 0,
52
+ orderBy = "published_at",
53
+ orderDirection = "desc"
54
+ } = params;
55
+ let query = supabase.from("contents").select("*").order("pinned", { ascending: false }).order(orderBy, { ascending: orderDirection === "asc", nullsFirst: false }).range(offset, offset + limit - 1);
56
+ if (type) query = query.eq("type", type);
57
+ if (category_id) query = query.eq("category_id", category_id);
58
+ if (tags && tags.length > 0) query = query.overlaps("tags", tags);
59
+ if (featured !== void 0) query = query.eq("featured", featured);
60
+ if (visibility) query = query.eq("visibility", visibility);
61
+ const { data, error } = await query;
62
+ if (error) {
63
+ throw new Error(`UCM: Failed to fetch contents: ${error.message}`);
64
+ }
65
+ return data || [];
66
+ },
67
+ async getBySlug(slug) {
68
+ const { data, error } = await supabase.from("contents").select("*").eq("slug", slug).single();
69
+ if (error) {
70
+ if (error.code === "PGRST116") return null;
71
+ throw new Error(`UCM: Failed to fetch content: ${error.message}`);
72
+ }
73
+ return data;
74
+ },
75
+ async getById(id) {
76
+ const { data, error } = await supabase.from("contents").select("*").eq("id", id).single();
77
+ if (error) {
78
+ if (error.code === "PGRST116") return null;
79
+ throw new Error(`UCM: Failed to fetch content: ${error.message}`);
80
+ }
81
+ return data;
82
+ },
83
+ async count(params = {}) {
84
+ const { type, category_id, tags, featured, visibility } = params;
85
+ let query = supabase.from("contents").select("*", { count: "exact", head: true });
86
+ if (type) query = query.eq("type", type);
87
+ if (category_id) query = query.eq("category_id", category_id);
88
+ if (tags && tags.length > 0) query = query.overlaps("tags", tags);
89
+ if (featured !== void 0) query = query.eq("featured", featured);
90
+ if (visibility) query = query.eq("visibility", visibility);
91
+ const { count, error } = await query;
92
+ if (error) {
93
+ console.error("UCM: Failed to get count:", error);
94
+ return 0;
95
+ }
96
+ return count || 0;
97
+ },
98
+ async create(input) {
99
+ const { data, error } = await supabase.from("contents").insert(input).select().single();
100
+ if (error) {
101
+ throw new Error(`UCM: Failed to create content: ${error.message}`);
102
+ }
103
+ return data;
104
+ },
105
+ async update(id, input) {
106
+ const { data, error } = await supabase.from("contents").update(input).eq("id", id).select().single();
107
+ if (error) {
108
+ throw new Error(`UCM: Failed to update content: ${error.message}`);
109
+ }
110
+ return data;
111
+ },
112
+ async delete(id) {
113
+ const { error } = await supabase.from("contents").delete().eq("id", id);
114
+ if (error) {
115
+ throw new Error(`UCM: Failed to delete content: ${error.message}`);
116
+ }
117
+ },
118
+ async incrementView(id) {
119
+ try {
120
+ await supabase.rpc("increment_view_count", { content_id: id });
121
+ } catch {
122
+ }
123
+ },
124
+ async search(query, type, visibility = "public") {
125
+ if (!query || query.trim().length === 0) {
126
+ return [];
127
+ }
128
+ const { data, error } = await supabase.rpc("search_contents", {
129
+ search_query: query.trim(),
130
+ content_type: type || null,
131
+ content_visibility: visibility
132
+ });
133
+ if (error) {
134
+ throw new Error(`UCM: Failed to search contents: ${error.message}`);
135
+ }
136
+ return data || [];
137
+ },
138
+ async getTags(type) {
139
+ let query = supabase.from("contents").select("tags");
140
+ if (type) {
141
+ query = query.eq("type", type);
142
+ }
143
+ const { data, error } = await query;
144
+ if (error) {
145
+ console.error("UCM: Failed to fetch tags:", error);
146
+ return [];
147
+ }
148
+ const allTags = /* @__PURE__ */ new Set();
149
+ data?.forEach((item) => {
150
+ if (item.tags && Array.isArray(item.tags)) {
151
+ item.tags.forEach((tag) => allTags.add(tag));
152
+ }
153
+ });
154
+ return Array.from(allTags).sort((a, b) => a.localeCompare(b));
155
+ }
156
+ };
157
+ const categories = {
158
+ async list(params = {}) {
159
+ const { parent_id } = params;
160
+ let query = supabase.from("categories").select("*").order("sort_order");
161
+ if (parent_id !== void 0) {
162
+ if (parent_id === null) {
163
+ query = query.is("parent_id", null);
164
+ } else {
165
+ query = query.eq("parent_id", parent_id);
166
+ }
167
+ }
168
+ const { data, error } = await query;
169
+ if (error) {
170
+ throw new Error(`UCM: Failed to fetch categories: ${error.message}`);
171
+ }
172
+ return data || [];
173
+ },
174
+ async getTree() {
175
+ const allCategories = await this.list();
176
+ return buildCategoryTree(allCategories);
177
+ },
178
+ async getBySlug(slug) {
179
+ const { data, error } = await supabase.from("categories").select("*").eq("slug", slug).single();
180
+ if (error) {
181
+ if (error.code === "PGRST116") return null;
182
+ throw new Error(`UCM: Failed to fetch category: ${error.message}`);
183
+ }
184
+ return data;
185
+ },
186
+ async getById(id) {
187
+ const { data, error } = await supabase.from("categories").select("*").eq("id", id).single();
188
+ if (error) {
189
+ if (error.code === "PGRST116") return null;
190
+ throw new Error(`UCM: Failed to fetch category: ${error.message}`);
191
+ }
192
+ return data;
193
+ },
194
+ async getChildren(parentId) {
195
+ return this.list({ parent_id: parentId });
196
+ },
197
+ async getRoots() {
198
+ return this.list({ parent_id: null });
199
+ },
200
+ async getBreadcrumb(categoryId) {
201
+ const breadcrumb = [];
202
+ let currentId = categoryId;
203
+ while (currentId) {
204
+ const category = await this.getById(currentId);
205
+ if (!category) break;
206
+ breadcrumb.unshift(category);
207
+ currentId = category.parent_id;
208
+ }
209
+ return breadcrumb;
210
+ }
211
+ };
212
+ const storage = {
213
+ getUrl(path, bucket = "content-images") {
214
+ if (!path) return "";
215
+ if (path.startsWith("http")) return path;
216
+ return `${url}/storage/v1/object/public/${bucket}/${path}`;
217
+ },
218
+ getImageUrl(path, options2) {
219
+ const baseUrl = this.getUrl(path);
220
+ if (!baseUrl || !options2) return baseUrl;
221
+ const params = new URLSearchParams();
222
+ if (options2.width) params.set("width", options2.width.toString());
223
+ if (options2.height) params.set("height", options2.height.toString());
224
+ if (options2.quality) params.set("quality", options2.quality.toString());
225
+ if (options2.format) params.set("format", options2.format);
226
+ const queryString = params.toString();
227
+ return queryString ? `${baseUrl}?${queryString}` : baseUrl;
228
+ }
229
+ };
230
+ return {
231
+ supabase,
232
+ contents,
233
+ categories,
234
+ storage,
235
+ isConfigured: () => true
236
+ };
237
+ }
238
+ function createNullClient() {
239
+ const nullSupabase = null;
240
+ return {
241
+ supabase: nullSupabase,
242
+ contents: {
243
+ list: async () => [],
244
+ getBySlug: async () => null,
245
+ getById: async () => null,
246
+ count: async () => 0,
247
+ search: async () => [],
248
+ getTags: async () => [],
249
+ create: async () => {
250
+ throw new Error("UCM: Client not configured");
251
+ },
252
+ update: async () => {
253
+ throw new Error("UCM: Client not configured");
254
+ },
255
+ delete: async () => {
256
+ throw new Error("UCM: Client not configured");
257
+ },
258
+ incrementView: async () => {
259
+ }
260
+ },
261
+ categories: {
262
+ list: async () => [],
263
+ getTree: async () => [],
264
+ getBySlug: async () => null,
265
+ getById: async () => null,
266
+ getChildren: async () => [],
267
+ getRoots: async () => [],
268
+ getBreadcrumb: async () => []
269
+ },
270
+ storage: {
271
+ getUrl: () => "",
272
+ getImageUrl: () => ""
273
+ },
274
+ isConfigured: () => false
275
+ };
276
+ }
277
+
278
+ // src/react.tsx
279
+ import { createContext, useContext, useMemo } from "react";
280
+ import { jsx } from "react/jsx-runtime";
281
+ var UCMContext = createContext(null);
282
+ function UCMProvider({ config, client, children }) {
283
+ const ucmClient = useMemo(() => {
284
+ if (client) {
285
+ return client;
286
+ }
287
+ if (config?.url && config?.anonKey) {
288
+ return createUCMClient(config);
289
+ }
290
+ console.warn("UCM: No config provided, using null client");
291
+ return createNullClient();
292
+ }, [config?.url, config?.anonKey, client]);
293
+ return /* @__PURE__ */ jsx(UCMContext.Provider, { value: ucmClient, children });
294
+ }
295
+ function useUCM() {
296
+ const context = useContext(UCMContext);
297
+ if (!context) {
298
+ throw new Error("useUCM must be used within a UCMProvider");
299
+ }
300
+ return context;
301
+ }
302
+ function useUCMOptional() {
303
+ const context = useContext(UCMContext);
304
+ return context || createNullClient();
305
+ }
306
+ function useUCMConfigured() {
307
+ const ucm = useUCMOptional();
308
+ return ucm.isConfigured();
309
+ }
310
+
311
+ // src/hooks.ts
312
+ import { useCallback, useEffect, useMemo as useMemo2, useRef, useState } from "react";
313
+ import {
314
+ useQuery,
315
+ useInfiniteQuery,
316
+ useMutation,
317
+ useQueryClient
318
+ } from "@tanstack/react-query";
319
+ var ucmKeys = {
320
+ all: ["ucm"],
321
+ contents: () => [...ucmKeys.all, "contents"],
322
+ contentsList: (params) => [...ucmKeys.contents(), "list", params],
323
+ contentsInfinite: (params) => [...ucmKeys.contents(), "infinite", params],
324
+ content: (identifier) => [...ucmKeys.contents(), "detail", identifier],
325
+ contentsCount: (params) => [...ucmKeys.contents(), "count", params],
326
+ contentsTags: (type) => [...ucmKeys.contents(), "tags", type],
327
+ contentsSearch: (query, type) => [...ucmKeys.contents(), "search", query, type],
328
+ contentsAdjacent: (slug, type) => [...ucmKeys.contents(), "adjacent", slug, type],
329
+ categories: () => [...ucmKeys.all, "categories"],
330
+ categoriesList: (params) => [...ucmKeys.categories(), "list", params],
331
+ categoriesTree: () => [...ucmKeys.categories(), "tree"],
332
+ category: (identifier) => [...ucmKeys.categories(), "detail", identifier],
333
+ categoryBreadcrumb: (id) => [...ucmKeys.categories(), "breadcrumb", id]
334
+ };
335
+ function useContents(options = {}) {
336
+ const ucm = useUCMOptional();
337
+ const queryClient = useQueryClient();
338
+ const {
339
+ type,
340
+ category_id,
341
+ tags,
342
+ featured,
343
+ visibility,
344
+ limit = 20,
345
+ orderBy = "published_at",
346
+ orderDirection = "desc",
347
+ autoLoad = true,
348
+ paginated = true
349
+ } = options;
350
+ const queryParams = useMemo2(
351
+ () => ({
352
+ type,
353
+ category_id,
354
+ tags,
355
+ featured,
356
+ visibility,
357
+ limit,
358
+ orderBy,
359
+ orderDirection
360
+ }),
361
+ [
362
+ type,
363
+ category_id,
364
+ tags,
365
+ featured,
366
+ visibility,
367
+ limit,
368
+ orderBy,
369
+ orderDirection
370
+ ]
371
+ );
372
+ const { data: total = 0 } = useQuery({
373
+ queryKey: ucmKeys.contentsCount({
374
+ type,
375
+ category_id,
376
+ tags,
377
+ featured,
378
+ visibility
379
+ }),
380
+ queryFn: () => ucm.contents.count({ type, category_id, tags, featured, visibility }),
381
+ enabled: ucm.isConfigured() && autoLoad
382
+ });
383
+ const {
384
+ data,
385
+ isLoading,
386
+ isFetchingNextPage,
387
+ error,
388
+ hasNextPage,
389
+ fetchNextPage,
390
+ refetch
391
+ } = useInfiniteQuery({
392
+ queryKey: ucmKeys.contentsInfinite(queryParams),
393
+ queryFn: async ({ pageParam = 0 }) => {
394
+ return ucm.contents.list({
395
+ ...queryParams,
396
+ offset: pageParam * limit
397
+ });
398
+ },
399
+ getNextPageParam: (lastPage, allPages) => {
400
+ if (lastPage.length < limit) {
401
+ return void 0;
402
+ }
403
+ return allPages.length;
404
+ },
405
+ initialPageParam: 0,
406
+ enabled: ucm.isConfigured() && autoLoad
407
+ });
408
+ const contents = data?.pages.flat() ?? [];
409
+ const page = data?.pages.length ?? 0;
410
+ const load = useCallback(async () => {
411
+ await refetch();
412
+ }, [refetch]);
413
+ const loadMore = useCallback(async () => {
414
+ if (hasNextPage) {
415
+ await fetchNextPage();
416
+ }
417
+ }, [fetchNextPage, hasNextPage]);
418
+ const refresh = useCallback(async () => {
419
+ await refetch();
420
+ }, [refetch]);
421
+ const reset = useCallback(() => {
422
+ queryClient.removeQueries({
423
+ queryKey: ucmKeys.contentsInfinite(queryParams)
424
+ });
425
+ }, [queryClient, queryParams]);
426
+ return {
427
+ contents,
428
+ isLoading,
429
+ isLoadingMore: isFetchingNextPage,
430
+ error,
431
+ total,
432
+ hasMore: paginated ? hasNextPage ?? false : false,
433
+ page,
434
+ load,
435
+ loadMore,
436
+ refresh,
437
+ reset
438
+ };
439
+ }
440
+ function useContent(options = {}) {
441
+ const ucm = useUCMOptional();
442
+ const { slug, id, autoLoad = true, trackView = true } = options;
443
+ const viewTrackedRef = useRef(false);
444
+ const identifier = useMemo2(() => ({ slug, id }), [slug, id]);
445
+ const incrementViewMutation = useMutation({
446
+ mutationFn: (contentId) => ucm.contents.incrementView(contentId)
447
+ });
448
+ const {
449
+ data: content,
450
+ isLoading,
451
+ error,
452
+ refetch
453
+ } = useQuery({
454
+ queryKey: ucmKeys.content(identifier),
455
+ queryFn: async () => {
456
+ if (slug) {
457
+ return ucm.contents.getBySlug(slug);
458
+ }
459
+ if (id) {
460
+ return ucm.contents.getById(id);
461
+ }
462
+ return null;
463
+ },
464
+ enabled: ucm.isConfigured() && autoLoad && !!(slug || id)
465
+ });
466
+ useEffect(() => {
467
+ if (content && trackView && !viewTrackedRef.current) {
468
+ viewTrackedRef.current = true;
469
+ incrementViewMutation.mutate(content.id);
470
+ }
471
+ }, [content, trackView]);
472
+ useEffect(() => {
473
+ viewTrackedRef.current = false;
474
+ }, [slug, id]);
475
+ const load = useCallback(async () => {
476
+ await refetch();
477
+ }, [refetch]);
478
+ const refresh = useCallback(async () => {
479
+ viewTrackedRef.current = true;
480
+ await refetch();
481
+ }, [refetch]);
482
+ return {
483
+ content: content ?? null,
484
+ isLoading,
485
+ error,
486
+ notFound: !isLoading && !error && !content && !!(slug || id),
487
+ load,
488
+ refresh
489
+ };
490
+ }
491
+ function useCategories(options = {}) {
492
+ const ucm = useUCMOptional();
493
+ const { parentId, asTree = false, autoLoad = true } = options;
494
+ const listQuery = useQuery({
495
+ queryKey: ucmKeys.categoriesList({ parentId }),
496
+ queryFn: async () => {
497
+ if (parentId === null) {
498
+ return ucm.categories.getRoots();
499
+ }
500
+ if (parentId) {
501
+ return ucm.categories.getChildren(parentId);
502
+ }
503
+ return ucm.categories.list();
504
+ },
505
+ enabled: ucm.isConfigured() && autoLoad
506
+ });
507
+ const treeQuery = useQuery({
508
+ queryKey: ucmKeys.categoriesTree(),
509
+ queryFn: () => ucm.categories.getTree(),
510
+ enabled: ucm.isConfigured() && autoLoad && asTree
511
+ });
512
+ const load = useCallback(async () => {
513
+ await Promise.all([
514
+ listQuery.refetch(),
515
+ asTree ? treeQuery.refetch() : Promise.resolve()
516
+ ]);
517
+ }, [listQuery, treeQuery, asTree]);
518
+ const refresh = useCallback(async () => {
519
+ await load();
520
+ }, [load]);
521
+ return {
522
+ categories: listQuery.data ?? [],
523
+ tree: treeQuery.data ?? [],
524
+ isLoading: listQuery.isLoading || asTree && treeQuery.isLoading,
525
+ error: listQuery.error || treeQuery.error,
526
+ load,
527
+ refresh
528
+ };
529
+ }
530
+ function useCategory(options = {}) {
531
+ const ucm = useUCMOptional();
532
+ const { slug, id, autoLoad = true } = options;
533
+ const identifier = useMemo2(() => ({ slug, id }), [slug, id]);
534
+ const {
535
+ data: category,
536
+ isLoading,
537
+ error,
538
+ refetch
539
+ } = useQuery({
540
+ queryKey: ucmKeys.category(identifier),
541
+ queryFn: async () => {
542
+ if (slug) {
543
+ return ucm.categories.getBySlug(slug);
544
+ }
545
+ if (id) {
546
+ return ucm.categories.getById(id);
547
+ }
548
+ return null;
549
+ },
550
+ enabled: ucm.isConfigured() && autoLoad && !!(slug || id)
551
+ });
552
+ const load = useCallback(async () => {
553
+ await refetch();
554
+ }, [refetch]);
555
+ return {
556
+ category: category ?? null,
557
+ isLoading,
558
+ error,
559
+ notFound: !isLoading && !error && !category && !!(slug || id),
560
+ load
561
+ };
562
+ }
563
+ function useCategoryBreadcrumb(categoryId) {
564
+ const ucm = useUCMOptional();
565
+ const {
566
+ data: breadcrumb,
567
+ isLoading,
568
+ error,
569
+ refetch
570
+ } = useQuery({
571
+ queryKey: ucmKeys.categoryBreadcrumb(categoryId ?? ""),
572
+ queryFn: () => ucm.categories.getBreadcrumb(categoryId),
573
+ enabled: ucm.isConfigured() && !!categoryId
574
+ });
575
+ const load = useCallback(async () => {
576
+ await refetch();
577
+ }, [refetch]);
578
+ return {
579
+ breadcrumb: breadcrumb ?? [],
580
+ isLoading,
581
+ error,
582
+ load
583
+ };
584
+ }
585
+ function useAdjacentContents(options) {
586
+ const ucm = useUCMOptional();
587
+ const { slug, type = "blog", autoLoad = true } = options;
588
+ const {
589
+ data: adjacent,
590
+ isLoading,
591
+ error,
592
+ refetch
593
+ } = useQuery({
594
+ queryKey: ucmKeys.contentsAdjacent(slug, type),
595
+ queryFn: async () => {
596
+ const current = await ucm.contents.getBySlug(slug);
597
+ if (!current || !current.published_at) {
598
+ return { prev: null, next: null };
599
+ }
600
+ const allContents = await ucm.contents.list({
601
+ type,
602
+ limit: 100,
603
+ orderBy: "published_at",
604
+ orderDirection: "desc"
605
+ });
606
+ const currentIndex = allContents.findIndex((c) => c.slug === slug);
607
+ let prev = null;
608
+ let next = null;
609
+ if (currentIndex !== -1) {
610
+ if (currentIndex > 0) {
611
+ next = allContents[currentIndex - 1];
612
+ }
613
+ if (currentIndex < allContents.length - 1) {
614
+ prev = allContents[currentIndex + 1];
615
+ }
616
+ }
617
+ return { prev, next };
618
+ },
619
+ enabled: ucm.isConfigured() && autoLoad && !!slug
620
+ });
621
+ const load = useCallback(async () => {
622
+ await refetch();
623
+ }, [refetch]);
624
+ return {
625
+ adjacent: adjacent ?? { prev: null, next: null },
626
+ isLoading,
627
+ error,
628
+ load
629
+ };
630
+ }
631
+ function useSearchContents(options = {}) {
632
+ const ucm = useUCMOptional();
633
+ const { type, debounceMs = 300 } = options;
634
+ const [query, setQuery] = useState("");
635
+ const [debouncedQuery, setDebouncedQuery] = useState("");
636
+ const debounceTimerRef = useRef(null);
637
+ useEffect(() => {
638
+ if (debounceTimerRef.current) {
639
+ clearTimeout(debounceTimerRef.current);
640
+ }
641
+ debounceTimerRef.current = setTimeout(() => {
642
+ setDebouncedQuery(query);
643
+ }, debounceMs);
644
+ return () => {
645
+ if (debounceTimerRef.current) {
646
+ clearTimeout(debounceTimerRef.current);
647
+ }
648
+ };
649
+ }, [query, debounceMs]);
650
+ const {
651
+ data: results,
652
+ isLoading: isSearching,
653
+ error
654
+ } = useQuery({
655
+ queryKey: ucmKeys.contentsSearch(debouncedQuery, type),
656
+ queryFn: () => ucm.contents.search(debouncedQuery.trim(), type),
657
+ enabled: ucm.isConfigured() && debouncedQuery.trim().length > 0
658
+ });
659
+ const search = useCallback((searchQuery) => {
660
+ setQuery(searchQuery);
661
+ }, []);
662
+ const clear = useCallback(() => {
663
+ setQuery("");
664
+ setDebouncedQuery("");
665
+ }, []);
666
+ return {
667
+ results: results ?? [],
668
+ isSearching: isSearching || query !== debouncedQuery,
669
+ error,
670
+ query,
671
+ search,
672
+ clear
673
+ };
674
+ }
675
+ function useTags(options = {}) {
676
+ const ucm = useUCMOptional();
677
+ const { type, autoLoad = true } = options;
678
+ const {
679
+ data: tags,
680
+ isLoading,
681
+ error,
682
+ refetch
683
+ } = useQuery({
684
+ queryKey: ucmKeys.contentsTags(type),
685
+ queryFn: () => ucm.contents.getTags(type),
686
+ enabled: ucm.isConfigured() && autoLoad
687
+ });
688
+ const load = useCallback(async () => {
689
+ await refetch();
690
+ }, [refetch]);
691
+ const refresh = useCallback(async () => {
692
+ await refetch();
693
+ }, [refetch]);
694
+ return {
695
+ tags: tags ?? [],
696
+ isLoading,
697
+ error,
698
+ load,
699
+ refresh
700
+ };
701
+ }
702
+ function useThoughts(options = {}) {
703
+ const { agentId, thoughtType, limit = 10, autoLoad = true } = options;
704
+ const {
705
+ contents,
706
+ isLoading,
707
+ isLoadingMore,
708
+ error,
709
+ hasMore,
710
+ total,
711
+ load,
712
+ loadMore,
713
+ refresh
714
+ } = useContents({
715
+ type: "thought",
716
+ limit,
717
+ autoLoad,
718
+ orderBy: "created_at",
719
+ orderDirection: "desc",
720
+ paginated: true
721
+ });
722
+ const thoughts = contents.filter((c) => {
723
+ const metadata = c.metadata;
724
+ if (agentId && metadata?.agent_id !== agentId) return false;
725
+ if (thoughtType && metadata?.thought_type !== thoughtType) return false;
726
+ return true;
727
+ });
728
+ return {
729
+ thoughts,
730
+ isLoading,
731
+ isLoadingMore,
732
+ error,
733
+ hasMore,
734
+ total,
735
+ load,
736
+ loadMore,
737
+ refresh
738
+ };
739
+ }
740
+ export {
741
+ UCMProvider,
742
+ buildCategoryTree,
743
+ createNullClient,
744
+ createUCMClient,
745
+ getLocalizedText,
746
+ useAdjacentContents,
747
+ useCategories,
748
+ useCategory,
749
+ useCategoryBreadcrumb,
750
+ useContent,
751
+ useContents,
752
+ useSearchContents,
753
+ useTags,
754
+ useThoughts,
755
+ useUCM,
756
+ useUCMConfigured,
757
+ useUCMOptional
758
+ };
759
+ //# sourceMappingURL=index.js.map