@rocapine/community-core 0.5.0 → 0.8.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/README.md CHANGED
@@ -24,7 +24,9 @@ const config: CommunityConfig = {
24
24
 
25
25
  // Product vocabulary
26
26
  appName: "My App", // pushes, inbox, broadcast fallback title
27
- anonymousAuthorFallback: "Someone", // shown when an author has no username yet
27
+ // Shown when an author has no username yet. A function receives the host
28
+ // locale (`host.getLocale()`), e.g. (locale) => t("anonymous", { lng: locale }).
29
+ anonymousAuthorFallback: "Someone",
28
30
 
29
31
  // Topics — nothing hardcoded. `id` resolves to `topics.<id>` in the UI
30
32
  // package's i18n catalog (see packages/ui/README.md); the app supplies
package/lib/config.d.ts CHANGED
@@ -59,7 +59,8 @@ export type CommunityFeedConfig = {
59
59
  export type CommunityConfig = {
60
60
  supabase: SupabaseClient | null;
61
61
  appName: string;
62
- anonymousAuthorFallback: string;
62
+ /** Shown for authors without a display name. A function receives the host locale. */
63
+ anonymousAuthorFallback: string | ((locale: string) => string);
63
64
  topics: CommunityTopicDef[];
64
65
  modules: CommunityModules;
65
66
  host?: CommunityHostAdapters;
@@ -73,6 +74,8 @@ export type ResolvedCommunityConfig = CommunityConfig & {
73
74
  host: RequiredCommunityHostAdapters;
74
75
  feed: CommunityFeedConfig;
75
76
  requireClient(): SupabaseClient;
77
+ /** `anonymousAuthorFallback` resolved against `host.getLocale()`. */
78
+ authorFallback(): string;
76
79
  composeTopics(): CommunityTopicDef[];
77
80
  isOfficialTopic(id: string): boolean;
78
81
  };
package/lib/config.js CHANGED
@@ -40,6 +40,10 @@ function resolveConfig(config) {
40
40
  }
41
41
  return resolved.supabase;
42
42
  },
43
+ authorFallback() {
44
+ const fallback = resolved.anonymousAuthorFallback;
45
+ return typeof fallback === "function" ? fallback(host.getLocale()) : fallback;
46
+ },
43
47
  composeTopics() {
44
48
  return resolved.topics.filter((topic) => !topic.officialOnly);
45
49
  },
package/lib/hooks.js CHANGED
@@ -245,6 +245,7 @@ function useUpdateProfile() {
245
245
  hasBio: !!input.bio,
246
246
  hasAvatar: !!input.avatarUrl,
247
247
  handleChanged: !!input.handle,
248
+ usernameChanged: !!input.username,
248
249
  });
249
250
  },
250
251
  });
package/lib/service.d.ts CHANGED
@@ -124,19 +124,22 @@ export declare function deleteOwnComment(cfg: ResolvedCommunityConfig, commentId
124
124
  * signature and translated to the Edge Function's expected `avatarPath` body
125
125
  * key at the call site below.
126
126
  */
127
+ /** `username` is the display name shown on posts; `handle` the @handle. All fields are moderated server-side. */
127
128
  export type UpdateProfileInput = {
129
+ username?: string;
128
130
  handle?: string;
129
131
  bio?: string;
130
132
  avatarUrl?: string;
131
133
  };
132
134
  export type UpdateProfileResult = {
133
135
  status: "ok";
136
+ username: string | null;
134
137
  handle: string | null;
135
138
  bio: string | null;
136
139
  avatarUrl: string | null;
137
140
  } | {
138
141
  status: "rejected";
139
- field: "handle" | "bio" | "avatar";
142
+ field: "username" | "handle" | "bio" | "avatar";
140
143
  reason?: string;
141
144
  } | {
142
145
  status: "error";
package/lib/service.js CHANGED
@@ -188,7 +188,7 @@ async function toFeedPosts(cfg, client, rows, uid) {
188
188
  fetchPollData(cfg, rows.filter((r) => (r.poll_options ?? []).length > 0).map((r) => r.id), uid),
189
189
  fetchReactionSummaries(cfg, postIds),
190
190
  ]);
191
- return rows.map((r) => (0, models_1.mapPostRow)(r, uid, cfg.anonymousAuthorFallback, cfg.topics, liked, pollData, reactionData, cfg.feed.transformPost));
191
+ return rows.map((r) => (0, models_1.mapPostRow)(r, uid, cfg.authorFallback(), cfg.topics, liked, pollData, reactionData, cfg.feed.transformPost));
192
192
  }
193
193
  /**
194
194
  * One feed page, newest first. RLS already excludes other users' hidden and
@@ -249,7 +249,7 @@ async function fetchProfile(cfg, userId) {
249
249
  .single();
250
250
  if (error)
251
251
  throw error;
252
- return (0, models_1.mapProfileRow)(data, cfg.anonymousAuthorFallback);
252
+ return (0, models_1.mapProfileRow)(data, cfg.authorFallback());
253
253
  }
254
254
  /**
255
255
  * One user's posts, newest first (no pinned ordering — a profile page is
@@ -327,7 +327,7 @@ async function fetchThread(cfg, postId) {
327
327
  const { data, error } = await query;
328
328
  if (error)
329
329
  throw error;
330
- return (data ?? []).map((r) => (0, models_1.mapCommentRow)(r, uid, cfg.anonymousAuthorFallback));
330
+ return (data ?? []).map((r) => (0, models_1.mapCommentRow)(r, uid, cfg.authorFallback()));
331
331
  }
332
332
  /**
333
333
  * Insert a post as 'pending' (invisible to others until moderated). Returns id.
@@ -472,9 +472,9 @@ async function deleteOwnComment(cfg, commentId) {
472
472
  */
473
473
  async function updateProfile(cfg, input) {
474
474
  const client = cfg.requireClient();
475
- const { handle, bio, avatarUrl } = input;
475
+ const { username, handle, bio, avatarUrl } = input;
476
476
  const { data, error } = await client.functions.invoke("update-profile", {
477
- body: { handle, bio, avatarPath: avatarUrl },
477
+ body: { username, handle, bio, avatarPath: avatarUrl },
478
478
  });
479
479
  if (!error)
480
480
  return data;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rocapine/community-core",
3
- "version": "0.5.0",
3
+ "version": "0.8.1",
4
4
  "description": "Headless Supabase-backed community backend: identity, feed/thread/moderation services, and React Query hooks.",
5
5
  "license": "MIT",
6
6
  "repository": {