@productcraft/social 0.8.0 → 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/README.md CHANGED
@@ -14,8 +14,8 @@ Social's surface splits two ways — both reach the same data but differ in auth
14
14
 
15
15
  | Caller | URL prefix | Auth | What you do |
16
16
  |---|---|---|---|
17
- | **PlatformUser admin** | `/v1/workspaces/{workspaceId}/...` | cookie or PAK | Create communities, run moderation, read analytics. |
18
- | **Customer backend** | `/v1/communities/{communityId}/...` | PAK + `X-Acting-As: <actor_id>` header | Day-to-day reads/writes on behalf of an EndUser. |
17
+ | **PlatformUser admin** | `/v1/workspaces/{workspace_id}/...` | cookie or PAK | Create communities, run moderation, read analytics. |
18
+ | **Customer backend** | `/v1/communities/{community_id}/...` | PAK + `X-Acting-As: <actor_id>` header | Day-to-day reads/writes on behalf of an EndUser. |
19
19
 
20
20
  The customer backend acts on behalf of one of its EndUsers via the `X-Acting-As` header — the SDK passes whatever you put in headers straight through, so a per-request wrapper that injects the acting actor id is idiomatic.
21
21
 
@@ -28,9 +28,9 @@ import { Social } from "@productcraft/social";
28
28
  const social = new Social();
29
29
 
30
30
  const { data, error } = await social.client.POST(
31
- "/v1/workspaces/{workspaceId}/communities",
31
+ "/v1/workspaces/{workspace_id}/communities",
32
32
  {
33
- params: { path: { workspaceId: "<workspace-uuid>" } },
33
+ params: { path: { workspace_id: "<workspace-uuid>" } },
34
34
  body: { display_name: "Founders Club", slug: "founders" },
35
35
  },
36
36
  );
@@ -42,10 +42,10 @@ const { data, error } = await social.client.POST(
42
42
  const actor_id = "<actor-uuid>"; // the EndUser's Social actor id
43
43
 
44
44
  const { data, error } = await social.client.POST(
45
- "/v1/communities/{communityId}/posts",
45
+ "/v1/communities/{community_id}/posts",
46
46
  {
47
47
  params: {
48
- path: { communityId: "<community-uuid>" },
48
+ path: { community_id: "<community-uuid>" },
49
49
  header: { "X-Acting-As": actor_id },
50
50
  },
51
51
  body: {
@@ -62,6 +62,24 @@ const { data, error } = await social.client.POST(
62
62
 
63
63
  Social's wire is snake_case both at the DTO level and in TS types — there's no name translation layer for this surface. Use snake_case keys in `body` to match what the API actually accepts.
64
64
 
65
+ ## Migrating from 0.x to 1.0
66
+
67
+ 1.0 renames every **path parameter** to snake_case, to match the rest of the ProductCraft APIs: `{communityId}` is now `{community_id}`, `{actorId}` is `{actor_id}`, `{srcActorId}` is `{src_actor_id}`, and so on. Request URLs are unchanged, so nothing breaks at runtime; the change is in the TypeScript path keys and in `params.path`:
68
+
69
+ ```ts
70
+ // 0.x
71
+ await social.client.GET("/v1/communities/{communityId}/posts/{postId}", {
72
+ params: { path: { communityId, postId } },
73
+ });
74
+
75
+ // 1.0
76
+ await social.client.GET("/v1/communities/{community_id}/posts/{post_id}", {
77
+ params: { path: { community_id: communityId, post_id: postId } },
78
+ });
79
+ ```
80
+
81
+ Where a route names a target actor next to the acting `actor_id`, the target got its own name: `posts/{post_id}/tags/{tagged_actor_id}/approve`, `actors/{tagged_actor_id}/tagged`, `actors/{owner_actor_id}/highlights`, `lists/{list_id}/members/{member_actor_id}`, `conversations/{conversation_id}/members/{member_actor_id}`. A search-and-replace of the placeholders plus the `path` keys is the whole migration. Post `attributes` now read back with the keys exactly as you stored them (`imageUrl` stays `imageUrl`); before, the API returned them snake_cased.
82
+
65
83
  ## Credentials from the environment
66
84
 
67
85
  Server-side, omit `auth` and the client reads your workspace key from the environment:
@@ -95,20 +113,20 @@ new Social({
95
113
  ```ts
96
114
  // Create a post
97
115
  await social.client.POST(
98
- "/v1/communities/{communityId}/posts",
99
- { params: { path: { communityId } }, body: { text: "..." } },
116
+ "/v1/communities/{community_id}/posts",
117
+ { params: { path: { community_id: communityId } }, body: { text: "..." } },
100
118
  );
101
119
 
102
120
  // Get the actor's ranked home feed
103
121
  await social.client.GET(
104
- "/v1/communities/{communityId}/actors/{actorId}/feed",
105
- { params: { path: { communityId, actorId } } },
122
+ "/v1/communities/{community_id}/actors/{actor_id}/feed",
123
+ { params: { path: { community_id: communityId, actor_id: actorId } } },
106
124
  );
107
125
 
108
126
  // Discover (community-wide ranked feed, not personalised to follows)
109
127
  await social.client.GET(
110
- "/v1/communities/{communityId}/discover-feed",
111
- { params: { path: { communityId } } },
128
+ "/v1/communities/{community_id}/discover-feed",
129
+ { params: { path: { community_id: communityId } } },
112
130
  );
113
131
 
114
132
  // React / unreact / bookmark / quote / repost — same shape, different paths
@@ -119,13 +137,13 @@ await social.client.GET(
119
137
  ```ts
120
138
  // Post a story (24h TTL)
121
139
  await social.client.POST(
122
- "/v1/communities/{communityId}/stories",
140
+ "/v1/communities/{community_id}/stories",
123
141
  { params: { ... }, body: { media_url: "...", visibility: "close_friends" } },
124
142
  );
125
143
 
126
144
  // Story tray (the bubble row at the top of the home screen)
127
145
  await social.client.GET(
128
- "/v1/communities/{communityId}/actors/{actorId}/story-tray",
146
+ "/v1/communities/{community_id}/actors/{actor_id}/story-tray",
129
147
  { ... },
130
148
  );
131
149
  ```
@@ -135,12 +153,12 @@ await social.client.GET(
135
153
  ```ts
136
154
  // Follow / unfollow
137
155
  await social.client.PUT(
138
- "/v1/communities/{communityId}/follows/{srcActorId}/{dstActorId}",
156
+ "/v1/communities/{community_id}/follows/{src_actor_id}/{dst_actor_id}",
139
157
  { ... },
140
158
  );
141
159
 
142
160
  // Block / mute / restrict — same shape, different paths
143
- // Close friends, hashtag follows, muted terms — all under /actors/{actorId}/...
161
+ // Close friends, hashtag follows, muted terms — all under /actors/{actor_id}/...
144
162
  ```
145
163
 
146
164
  ### Notifications
@@ -148,19 +166,19 @@ await social.client.PUT(
148
166
  ```ts
149
167
  // List
150
168
  await social.client.GET(
151
- "/v1/communities/{communityId}/actors/{actorId}/notifications",
169
+ "/v1/communities/{community_id}/actors/{actor_id}/notifications",
152
170
  { ... },
153
171
  );
154
172
 
155
173
  // Unread count for the bell badge
156
174
  await social.client.GET(
157
- "/v1/communities/{communityId}/actors/{actorId}/notifications/unread-count",
175
+ "/v1/communities/{community_id}/actors/{actor_id}/notifications/unread-count",
158
176
  { ... },
159
177
  );
160
178
 
161
179
  // Mark all read
162
180
  await social.client.POST(
163
- "/v1/communities/{communityId}/actors/{actorId}/notifications/read-all",
181
+ "/v1/communities/{community_id}/actors/{actor_id}/notifications/read-all",
164
182
  { ... },
165
183
  );
166
184
  ```
@@ -170,13 +188,13 @@ await social.client.POST(
170
188
  ```ts
171
189
  // Start / open a conversation
172
190
  await social.client.POST(
173
- "/v1/communities/{communityId}/conversations",
191
+ "/v1/communities/{community_id}/conversations",
174
192
  { params: { ... }, body: { members: ["act_a", "act_b"] } },
175
193
  );
176
194
 
177
195
  // Send a message
178
196
  await social.client.POST(
179
- "/v1/communities/{communityId}/conversations/{conversationId}/messages",
197
+ "/v1/communities/{community_id}/conversations/{conversation_id}/messages",
180
198
  { ... },
181
199
  );
182
200
  ```
@@ -186,19 +204,19 @@ await social.client.POST(
186
204
  ```ts
187
205
  // List flags
188
206
  await social.client.GET(
189
- "/v1/workspaces/{workspaceId}/communities/{communityId}/moderation/flags",
207
+ "/v1/workspaces/{workspace_id}/communities/{community_id}/moderation/flags",
190
208
  { ... },
191
209
  );
192
210
 
193
211
  // Act on a flag (resolve / dismiss / take action on the target)
194
212
  await social.client.POST(
195
- "/v1/workspaces/{workspaceId}/communities/{communityId}/moderation/flags/{flagId}/actions",
213
+ "/v1/workspaces/{workspace_id}/communities/{community_id}/moderation/flags/{flag_id}/actions",
196
214
  { params: { ... }, body: { action: "remove_content", note: "..." } },
197
215
  );
198
216
 
199
217
  // Shadow-ban an actor
200
218
  await social.client.PUT(
201
- "/v1/workspaces/{workspaceId}/communities/{communityId}/moderation/actors/{actorId}/shadow-ban",
219
+ "/v1/workspaces/{workspace_id}/communities/{community_id}/moderation/actors/{actor_id}/shadow-ban",
202
220
  { ... },
203
221
  );
204
222
  ```