@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.
@@ -0,0 +1,312 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { SupabaseClient } from '@supabase/supabase-js';
4
+
5
+ /**
6
+ * Universal Content Module - Type Definitions
7
+ * Supabase-powered content management with multi-language support
8
+ */
9
+ type ContentType = 'news' | 'daily' | 'blog' | 'doc' | 'event' | 'announcement' | 'tutorial' | 'case_study' | 'faq' | 'changelog' | 'thought' | 'digest' | 'briefing';
10
+ type ContentStatus = 'draft' | 'scheduled' | 'published' | 'archived';
11
+ type ContentVisibility = 'public' | 'internal' | 'unlisted';
12
+ type SupportedLanguage = 'zh' | 'en' | 'ja' | 'ko' | 'es' | 'de' | 'fr';
13
+ type I18nText = Partial<Record<SupportedLanguage, string>>;
14
+ interface Content {
15
+ id: string;
16
+ slug: string;
17
+ type: ContentType;
18
+ status: ContentStatus;
19
+ visibility: ContentVisibility;
20
+ category_id: string | null;
21
+ title: I18nText;
22
+ description: I18nText;
23
+ content: I18nText;
24
+ cover_image: string | null;
25
+ images: Array<{
26
+ url: string;
27
+ alt?: I18nText;
28
+ }>;
29
+ tags: string[];
30
+ author: string;
31
+ source: string | null;
32
+ source_url: string | null;
33
+ metadata: ContentMetadata;
34
+ seo: SeoData;
35
+ featured: boolean;
36
+ pinned: boolean;
37
+ published_at: string | null;
38
+ scheduled_at: string | null;
39
+ created_at: string;
40
+ updated_at: string;
41
+ sort_order: number;
42
+ view_count: number;
43
+ }
44
+ interface NewsMetadata {
45
+ wechat_msg_id?: string;
46
+ original_author?: string;
47
+ subtype?: 'press' | 'announcement' | 'changelog';
48
+ version?: string;
49
+ }
50
+ interface DailyMetadata {
51
+ date: string;
52
+ market?: Record<string, string>;
53
+ highlights?: string[];
54
+ }
55
+ interface DigestMetadata {
56
+ topic?: string;
57
+ highlights?: string[];
58
+ sources?: string[];
59
+ date?: string;
60
+ }
61
+ type BriefingFrequency = 'daily' | 'weekly' | 'monthly';
62
+ interface BriefingMetadata {
63
+ frequency: BriefingFrequency;
64
+ period: string;
65
+ metrics?: Record<string, number>;
66
+ highlights?: string[];
67
+ tasks_completed?: number;
68
+ tasks_pending?: number;
69
+ }
70
+ interface BlogMetadata {
71
+ reading_time?: number;
72
+ series?: string;
73
+ toc?: boolean;
74
+ }
75
+ interface DocMetadata {
76
+ version?: string;
77
+ prev_slug?: string;
78
+ next_slug?: string;
79
+ }
80
+ interface EventMetadata {
81
+ start_time: string;
82
+ end_time: string;
83
+ location?: {
84
+ type: 'online' | 'offline';
85
+ url?: string;
86
+ address?: string;
87
+ };
88
+ registration_url?: string;
89
+ max_attendees?: number;
90
+ current_attendees?: number;
91
+ }
92
+ type ThoughtType = 'observation' | 'reflection' | 'decision' | 'question' | 'insight' | 'mood';
93
+ type ThoughtMood = 'curious' | 'focused' | 'excited' | 'thoughtful' | 'creative' | 'philosophical' | 'accomplished' | 'inspired' | 'productive' | 'concerned' | 'determined' | 'grateful' | 'contemplative';
94
+ interface ThoughtMediaVideo {
95
+ url: string;
96
+ type: 'mp4' | 'youtube';
97
+ }
98
+ interface ThoughtMediaAudio {
99
+ url: string;
100
+ title?: string;
101
+ duration?: number;
102
+ }
103
+ interface ThoughtProductionLink {
104
+ slug: string;
105
+ title?: I18nText | string;
106
+ type?: 'blog' | 'video' | 'tool';
107
+ }
108
+ interface ThoughtComment {
109
+ user: string;
110
+ content: string;
111
+ time?: string;
112
+ }
113
+ interface ThoughtMetadata {
114
+ thought_type: ThoughtType;
115
+ agent_id: string;
116
+ mood?: ThoughtMood;
117
+ energy?: number;
118
+ images?: string[];
119
+ video?: ThoughtMediaVideo;
120
+ audio?: ThoughtMediaAudio;
121
+ leads_to?: string | ThoughtProductionLink;
122
+ comments?: ThoughtComment[];
123
+ ai_generated?: boolean;
124
+ generated_at?: string;
125
+ model?: string;
126
+ }
127
+ interface CaseStudyMetric {
128
+ label: I18nText;
129
+ before: string;
130
+ after: string;
131
+ }
132
+ interface CaseStudyMetadata {
133
+ product: string;
134
+ productRoute: string;
135
+ client: I18nText;
136
+ industry: I18nText;
137
+ scale: I18nText;
138
+ challenge: I18nText;
139
+ solution: I18nText;
140
+ metrics: CaseStudyMetric[];
141
+ quote: I18nText;
142
+ quotee: I18nText;
143
+ }
144
+ type ContentMetadata = NewsMetadata | DailyMetadata | DigestMetadata | BriefingMetadata | BlogMetadata | DocMetadata | EventMetadata | ThoughtMetadata | CaseStudyMetadata | Record<string, unknown>;
145
+ interface SeoData {
146
+ title?: I18nText;
147
+ description?: I18nText;
148
+ keywords?: string[];
149
+ og_image?: string;
150
+ canonical_url?: string;
151
+ }
152
+ interface Category {
153
+ id: string;
154
+ parent_id: string | null;
155
+ slug: string;
156
+ name: I18nText;
157
+ description: I18nText;
158
+ icon: string | null;
159
+ sort_order: number;
160
+ created_at: string;
161
+ children?: Category[];
162
+ }
163
+ interface ContentQueryParams {
164
+ type?: ContentType;
165
+ category_id?: string;
166
+ tags?: string[];
167
+ featured?: boolean;
168
+ visibility?: ContentVisibility;
169
+ limit?: number;
170
+ offset?: number;
171
+ orderBy?: 'published_at' | 'created_at' | 'sort_order' | 'view_count';
172
+ orderDirection?: 'asc' | 'desc';
173
+ }
174
+ interface CategoryQueryParams {
175
+ parent_id?: string | null;
176
+ includeChildren?: boolean;
177
+ }
178
+ interface CreateContentInput {
179
+ slug: string;
180
+ type: ContentType;
181
+ status?: ContentStatus;
182
+ visibility?: ContentVisibility;
183
+ category_id?: string;
184
+ title: I18nText;
185
+ description?: I18nText;
186
+ content: I18nText;
187
+ cover_image?: string;
188
+ images?: Array<{
189
+ url: string;
190
+ alt?: I18nText;
191
+ }>;
192
+ tags?: string[];
193
+ author?: string;
194
+ source?: string;
195
+ source_url?: string;
196
+ metadata?: ContentMetadata;
197
+ seo?: SeoData;
198
+ featured?: boolean;
199
+ pinned?: boolean;
200
+ published_at?: string;
201
+ scheduled_at?: string;
202
+ }
203
+ type UpdateContentInput = Partial<CreateContentInput>;
204
+
205
+ /**
206
+ * Universal Content Module - Core
207
+ *
208
+ * 工厂函数模式,支持:
209
+ * - 依赖注入(便于测试)
210
+ * - 多实例(多租户场景)
211
+ * - 框架无关(React/Vue/Node.js 通用)
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * // 创建客户端
216
+ * const ucm = createUCMClient({
217
+ * url: 'https://xxx.supabase.co',
218
+ * anonKey: 'eyJxxx',
219
+ * })
220
+ *
221
+ * // 使用 API
222
+ * const posts = await ucm.contents.list({ type: 'blog', limit: 10 })
223
+ * const post = await ucm.contents.getBySlug('hello-world')
224
+ * const categories = await ucm.categories.getTree()
225
+ * ```
226
+ */
227
+
228
+ interface UCMClientConfig {
229
+ /** Supabase project URL */
230
+ url: string;
231
+ /** Supabase anon key (for public read) or service key (for write) */
232
+ anonKey: string;
233
+ /** Optional: custom Supabase client options */
234
+ options?: {
235
+ persistSession?: boolean;
236
+ autoRefreshToken?: boolean;
237
+ };
238
+ }
239
+ interface UCMClient {
240
+ /** Raw Supabase client (for advanced use) */
241
+ supabase: SupabaseClient;
242
+ /** Content operations */
243
+ contents: {
244
+ list: (params?: ContentQueryParams) => Promise<Content[]>;
245
+ getBySlug: (slug: string) => Promise<Content | null>;
246
+ getById: (id: string) => Promise<Content | null>;
247
+ count: (params?: Pick<ContentQueryParams, 'type' | 'category_id' | 'tags' | 'featured' | 'visibility'>) => Promise<number>;
248
+ search: (query: string, type?: string, visibility?: string) => Promise<Content[]>;
249
+ getTags: (type?: string) => Promise<string[]>;
250
+ create: (input: CreateContentInput) => Promise<Content>;
251
+ update: (id: string, input: UpdateContentInput) => Promise<Content>;
252
+ delete: (id: string) => Promise<void>;
253
+ incrementView: (id: string) => Promise<void>;
254
+ };
255
+ /** Category operations */
256
+ categories: {
257
+ list: (params?: CategoryQueryParams) => Promise<Category[]>;
258
+ getTree: () => Promise<Category[]>;
259
+ getBySlug: (slug: string) => Promise<Category | null>;
260
+ getById: (id: string) => Promise<Category | null>;
261
+ getChildren: (parentId: string) => Promise<Category[]>;
262
+ getRoots: () => Promise<Category[]>;
263
+ getBreadcrumb: (categoryId: string) => Promise<Category[]>;
264
+ };
265
+ /** Storage helpers */
266
+ storage: {
267
+ getUrl: (path: string, bucket?: string) => string;
268
+ getImageUrl: (path: string, options?: {
269
+ width?: number;
270
+ height?: number;
271
+ quality?: number;
272
+ format?: string;
273
+ }) => string;
274
+ };
275
+ /** Check if client is configured */
276
+ isConfigured: () => boolean;
277
+ }
278
+
279
+ interface UCMProviderProps {
280
+ /** UCM 配置(url + anonKey) */
281
+ config?: UCMClientConfig;
282
+ /** 或直接传入已创建的客户端(便于测试) */
283
+ client?: UCMClient;
284
+ /** 子组件 */
285
+ children: ReactNode;
286
+ }
287
+ /**
288
+ * UCM Provider
289
+ *
290
+ * 提供两种使用方式:
291
+ * 1. 传入 config,自动创建客户端
292
+ * 2. 传入 client,使用已有客户端(测试场景)
293
+ */
294
+ declare function UCMProvider({ config, client, children }: UCMProviderProps): react_jsx_runtime.JSX.Element;
295
+ /**
296
+ * 获取 UCM 客户端
297
+ *
298
+ * @throws 如果在 UCMProvider 外使用
299
+ */
300
+ declare function useUCM(): UCMClient;
301
+ /**
302
+ * 获取 UCM 客户端(可选,不抛错)
303
+ *
304
+ * 如果在 Provider 外使用,返回 null client
305
+ */
306
+ declare function useUCMOptional(): UCMClient;
307
+ /**
308
+ * 检查 UCM 是否已配置
309
+ */
310
+ declare function useUCMConfigured(): boolean;
311
+
312
+ export { type UCMClient, type UCMClientConfig, UCMProvider, type UCMProviderProps, useUCM, useUCMConfigured, useUCMOptional };
@@ -0,0 +1,312 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { SupabaseClient } from '@supabase/supabase-js';
4
+
5
+ /**
6
+ * Universal Content Module - Type Definitions
7
+ * Supabase-powered content management with multi-language support
8
+ */
9
+ type ContentType = 'news' | 'daily' | 'blog' | 'doc' | 'event' | 'announcement' | 'tutorial' | 'case_study' | 'faq' | 'changelog' | 'thought' | 'digest' | 'briefing';
10
+ type ContentStatus = 'draft' | 'scheduled' | 'published' | 'archived';
11
+ type ContentVisibility = 'public' | 'internal' | 'unlisted';
12
+ type SupportedLanguage = 'zh' | 'en' | 'ja' | 'ko' | 'es' | 'de' | 'fr';
13
+ type I18nText = Partial<Record<SupportedLanguage, string>>;
14
+ interface Content {
15
+ id: string;
16
+ slug: string;
17
+ type: ContentType;
18
+ status: ContentStatus;
19
+ visibility: ContentVisibility;
20
+ category_id: string | null;
21
+ title: I18nText;
22
+ description: I18nText;
23
+ content: I18nText;
24
+ cover_image: string | null;
25
+ images: Array<{
26
+ url: string;
27
+ alt?: I18nText;
28
+ }>;
29
+ tags: string[];
30
+ author: string;
31
+ source: string | null;
32
+ source_url: string | null;
33
+ metadata: ContentMetadata;
34
+ seo: SeoData;
35
+ featured: boolean;
36
+ pinned: boolean;
37
+ published_at: string | null;
38
+ scheduled_at: string | null;
39
+ created_at: string;
40
+ updated_at: string;
41
+ sort_order: number;
42
+ view_count: number;
43
+ }
44
+ interface NewsMetadata {
45
+ wechat_msg_id?: string;
46
+ original_author?: string;
47
+ subtype?: 'press' | 'announcement' | 'changelog';
48
+ version?: string;
49
+ }
50
+ interface DailyMetadata {
51
+ date: string;
52
+ market?: Record<string, string>;
53
+ highlights?: string[];
54
+ }
55
+ interface DigestMetadata {
56
+ topic?: string;
57
+ highlights?: string[];
58
+ sources?: string[];
59
+ date?: string;
60
+ }
61
+ type BriefingFrequency = 'daily' | 'weekly' | 'monthly';
62
+ interface BriefingMetadata {
63
+ frequency: BriefingFrequency;
64
+ period: string;
65
+ metrics?: Record<string, number>;
66
+ highlights?: string[];
67
+ tasks_completed?: number;
68
+ tasks_pending?: number;
69
+ }
70
+ interface BlogMetadata {
71
+ reading_time?: number;
72
+ series?: string;
73
+ toc?: boolean;
74
+ }
75
+ interface DocMetadata {
76
+ version?: string;
77
+ prev_slug?: string;
78
+ next_slug?: string;
79
+ }
80
+ interface EventMetadata {
81
+ start_time: string;
82
+ end_time: string;
83
+ location?: {
84
+ type: 'online' | 'offline';
85
+ url?: string;
86
+ address?: string;
87
+ };
88
+ registration_url?: string;
89
+ max_attendees?: number;
90
+ current_attendees?: number;
91
+ }
92
+ type ThoughtType = 'observation' | 'reflection' | 'decision' | 'question' | 'insight' | 'mood';
93
+ type ThoughtMood = 'curious' | 'focused' | 'excited' | 'thoughtful' | 'creative' | 'philosophical' | 'accomplished' | 'inspired' | 'productive' | 'concerned' | 'determined' | 'grateful' | 'contemplative';
94
+ interface ThoughtMediaVideo {
95
+ url: string;
96
+ type: 'mp4' | 'youtube';
97
+ }
98
+ interface ThoughtMediaAudio {
99
+ url: string;
100
+ title?: string;
101
+ duration?: number;
102
+ }
103
+ interface ThoughtProductionLink {
104
+ slug: string;
105
+ title?: I18nText | string;
106
+ type?: 'blog' | 'video' | 'tool';
107
+ }
108
+ interface ThoughtComment {
109
+ user: string;
110
+ content: string;
111
+ time?: string;
112
+ }
113
+ interface ThoughtMetadata {
114
+ thought_type: ThoughtType;
115
+ agent_id: string;
116
+ mood?: ThoughtMood;
117
+ energy?: number;
118
+ images?: string[];
119
+ video?: ThoughtMediaVideo;
120
+ audio?: ThoughtMediaAudio;
121
+ leads_to?: string | ThoughtProductionLink;
122
+ comments?: ThoughtComment[];
123
+ ai_generated?: boolean;
124
+ generated_at?: string;
125
+ model?: string;
126
+ }
127
+ interface CaseStudyMetric {
128
+ label: I18nText;
129
+ before: string;
130
+ after: string;
131
+ }
132
+ interface CaseStudyMetadata {
133
+ product: string;
134
+ productRoute: string;
135
+ client: I18nText;
136
+ industry: I18nText;
137
+ scale: I18nText;
138
+ challenge: I18nText;
139
+ solution: I18nText;
140
+ metrics: CaseStudyMetric[];
141
+ quote: I18nText;
142
+ quotee: I18nText;
143
+ }
144
+ type ContentMetadata = NewsMetadata | DailyMetadata | DigestMetadata | BriefingMetadata | BlogMetadata | DocMetadata | EventMetadata | ThoughtMetadata | CaseStudyMetadata | Record<string, unknown>;
145
+ interface SeoData {
146
+ title?: I18nText;
147
+ description?: I18nText;
148
+ keywords?: string[];
149
+ og_image?: string;
150
+ canonical_url?: string;
151
+ }
152
+ interface Category {
153
+ id: string;
154
+ parent_id: string | null;
155
+ slug: string;
156
+ name: I18nText;
157
+ description: I18nText;
158
+ icon: string | null;
159
+ sort_order: number;
160
+ created_at: string;
161
+ children?: Category[];
162
+ }
163
+ interface ContentQueryParams {
164
+ type?: ContentType;
165
+ category_id?: string;
166
+ tags?: string[];
167
+ featured?: boolean;
168
+ visibility?: ContentVisibility;
169
+ limit?: number;
170
+ offset?: number;
171
+ orderBy?: 'published_at' | 'created_at' | 'sort_order' | 'view_count';
172
+ orderDirection?: 'asc' | 'desc';
173
+ }
174
+ interface CategoryQueryParams {
175
+ parent_id?: string | null;
176
+ includeChildren?: boolean;
177
+ }
178
+ interface CreateContentInput {
179
+ slug: string;
180
+ type: ContentType;
181
+ status?: ContentStatus;
182
+ visibility?: ContentVisibility;
183
+ category_id?: string;
184
+ title: I18nText;
185
+ description?: I18nText;
186
+ content: I18nText;
187
+ cover_image?: string;
188
+ images?: Array<{
189
+ url: string;
190
+ alt?: I18nText;
191
+ }>;
192
+ tags?: string[];
193
+ author?: string;
194
+ source?: string;
195
+ source_url?: string;
196
+ metadata?: ContentMetadata;
197
+ seo?: SeoData;
198
+ featured?: boolean;
199
+ pinned?: boolean;
200
+ published_at?: string;
201
+ scheduled_at?: string;
202
+ }
203
+ type UpdateContentInput = Partial<CreateContentInput>;
204
+
205
+ /**
206
+ * Universal Content Module - Core
207
+ *
208
+ * 工厂函数模式,支持:
209
+ * - 依赖注入(便于测试)
210
+ * - 多实例(多租户场景)
211
+ * - 框架无关(React/Vue/Node.js 通用)
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * // 创建客户端
216
+ * const ucm = createUCMClient({
217
+ * url: 'https://xxx.supabase.co',
218
+ * anonKey: 'eyJxxx',
219
+ * })
220
+ *
221
+ * // 使用 API
222
+ * const posts = await ucm.contents.list({ type: 'blog', limit: 10 })
223
+ * const post = await ucm.contents.getBySlug('hello-world')
224
+ * const categories = await ucm.categories.getTree()
225
+ * ```
226
+ */
227
+
228
+ interface UCMClientConfig {
229
+ /** Supabase project URL */
230
+ url: string;
231
+ /** Supabase anon key (for public read) or service key (for write) */
232
+ anonKey: string;
233
+ /** Optional: custom Supabase client options */
234
+ options?: {
235
+ persistSession?: boolean;
236
+ autoRefreshToken?: boolean;
237
+ };
238
+ }
239
+ interface UCMClient {
240
+ /** Raw Supabase client (for advanced use) */
241
+ supabase: SupabaseClient;
242
+ /** Content operations */
243
+ contents: {
244
+ list: (params?: ContentQueryParams) => Promise<Content[]>;
245
+ getBySlug: (slug: string) => Promise<Content | null>;
246
+ getById: (id: string) => Promise<Content | null>;
247
+ count: (params?: Pick<ContentQueryParams, 'type' | 'category_id' | 'tags' | 'featured' | 'visibility'>) => Promise<number>;
248
+ search: (query: string, type?: string, visibility?: string) => Promise<Content[]>;
249
+ getTags: (type?: string) => Promise<string[]>;
250
+ create: (input: CreateContentInput) => Promise<Content>;
251
+ update: (id: string, input: UpdateContentInput) => Promise<Content>;
252
+ delete: (id: string) => Promise<void>;
253
+ incrementView: (id: string) => Promise<void>;
254
+ };
255
+ /** Category operations */
256
+ categories: {
257
+ list: (params?: CategoryQueryParams) => Promise<Category[]>;
258
+ getTree: () => Promise<Category[]>;
259
+ getBySlug: (slug: string) => Promise<Category | null>;
260
+ getById: (id: string) => Promise<Category | null>;
261
+ getChildren: (parentId: string) => Promise<Category[]>;
262
+ getRoots: () => Promise<Category[]>;
263
+ getBreadcrumb: (categoryId: string) => Promise<Category[]>;
264
+ };
265
+ /** Storage helpers */
266
+ storage: {
267
+ getUrl: (path: string, bucket?: string) => string;
268
+ getImageUrl: (path: string, options?: {
269
+ width?: number;
270
+ height?: number;
271
+ quality?: number;
272
+ format?: string;
273
+ }) => string;
274
+ };
275
+ /** Check if client is configured */
276
+ isConfigured: () => boolean;
277
+ }
278
+
279
+ interface UCMProviderProps {
280
+ /** UCM 配置(url + anonKey) */
281
+ config?: UCMClientConfig;
282
+ /** 或直接传入已创建的客户端(便于测试) */
283
+ client?: UCMClient;
284
+ /** 子组件 */
285
+ children: ReactNode;
286
+ }
287
+ /**
288
+ * UCM Provider
289
+ *
290
+ * 提供两种使用方式:
291
+ * 1. 传入 config,自动创建客户端
292
+ * 2. 传入 client,使用已有客户端(测试场景)
293
+ */
294
+ declare function UCMProvider({ config, client, children }: UCMProviderProps): react_jsx_runtime.JSX.Element;
295
+ /**
296
+ * 获取 UCM 客户端
297
+ *
298
+ * @throws 如果在 UCMProvider 外使用
299
+ */
300
+ declare function useUCM(): UCMClient;
301
+ /**
302
+ * 获取 UCM 客户端(可选,不抛错)
303
+ *
304
+ * 如果在 Provider 外使用,返回 null client
305
+ */
306
+ declare function useUCMOptional(): UCMClient;
307
+ /**
308
+ * 检查 UCM 是否已配置
309
+ */
310
+ declare function useUCMConfigured(): boolean;
311
+
312
+ export { type UCMClient, type UCMClientConfig, UCMProvider, type UCMProviderProps, useUCM, useUCMConfigured, useUCMOptional };