jansathi-community-schema 0.9.0 → 0.10.0
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/comment.d.ts +1 -0
- package/dist/comment.d.ts.map +1 -1
- package/dist/feed.d.ts +13 -0
- package/dist/feed.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/post.d.ts +18 -7
- package/dist/post.d.ts.map +1 -1
- package/dist/post.js +20 -9
- package/dist/post.js.map +1 -1
- package/dist/profile.d.ts +3 -0
- package/dist/profile.d.ts.map +1 -1
- package/dist/profile.js +9 -0
- package/dist/profile.js.map +1 -1
- package/dist/repost.d.ts +2 -0
- package/dist/repost.d.ts.map +1 -1
- package/dist/username.d.ts +123 -0
- package/dist/username.d.ts.map +1 -0
- package/dist/username.js +126 -0
- package/dist/username.js.map +1 -0
- package/package.json +1 -1
package/dist/comment.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare const communityCommentWireSchema: z.ZodObject<{
|
|
|
25
25
|
parentCommentId: z.ZodNullable<z.ZodString>;
|
|
26
26
|
author: z.ZodObject<{
|
|
27
27
|
userId: z.ZodString;
|
|
28
|
+
username: z.ZodString;
|
|
28
29
|
displayName: z.ZodString;
|
|
29
30
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
30
31
|
localName: z.ZodOptional<z.ZodString>;
|
package/dist/comment.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../src/comment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,0BAA0B
|
|
1
|
+
{"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../src/comment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkCrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAI9E,eAAO,MAAM,uBAAuB;;;iBAMlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE,eAAO,MAAM,uBAAuB;;iBAElC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
|
package/dist/feed.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export declare const lostFoundFeedItemSchema: z.ZodObject<{
|
|
|
32
32
|
contentKind: z.ZodLiteral<"lost_found">;
|
|
33
33
|
author: z.ZodObject<{
|
|
34
34
|
userId: z.ZodString;
|
|
35
|
+
username: z.ZodString;
|
|
35
36
|
displayName: z.ZodString;
|
|
36
37
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
37
38
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -66,6 +67,7 @@ export declare const donateItemFeedItemSchema: z.ZodObject<{
|
|
|
66
67
|
contentKind: z.ZodLiteral<"donate_item">;
|
|
67
68
|
author: z.ZodObject<{
|
|
68
69
|
userId: z.ZodString;
|
|
70
|
+
username: z.ZodString;
|
|
69
71
|
displayName: z.ZodString;
|
|
70
72
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
71
73
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -97,6 +99,7 @@ export declare const voiceBoxFeedItemSchema: z.ZodObject<{
|
|
|
97
99
|
contentKind: z.ZodLiteral<"voice_box">;
|
|
98
100
|
author: z.ZodObject<{
|
|
99
101
|
userId: z.ZodString;
|
|
102
|
+
username: z.ZodString;
|
|
100
103
|
displayName: z.ZodString;
|
|
101
104
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
102
105
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -125,6 +128,7 @@ export declare const feedItemSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
125
128
|
contentKind: z.ZodLiteral<"post">;
|
|
126
129
|
author: z.ZodObject<{
|
|
127
130
|
userId: z.ZodString;
|
|
131
|
+
username: z.ZodString;
|
|
128
132
|
displayName: z.ZodString;
|
|
129
133
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
130
134
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -168,6 +172,7 @@ export declare const feedItemSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
168
172
|
_id: z.ZodString;
|
|
169
173
|
author: z.ZodObject<{
|
|
170
174
|
userId: z.ZodString;
|
|
175
|
+
username: z.ZodString;
|
|
171
176
|
displayName: z.ZodString;
|
|
172
177
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
173
178
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -192,6 +197,7 @@ export declare const feedItemSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
192
197
|
contentKind: z.ZodLiteral<"lost_found">;
|
|
193
198
|
author: z.ZodObject<{
|
|
194
199
|
userId: z.ZodString;
|
|
200
|
+
username: z.ZodString;
|
|
195
201
|
displayName: z.ZodString;
|
|
196
202
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
197
203
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -219,6 +225,7 @@ export declare const feedItemSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
219
225
|
contentKind: z.ZodLiteral<"voice_box">;
|
|
220
226
|
author: z.ZodObject<{
|
|
221
227
|
userId: z.ZodString;
|
|
228
|
+
username: z.ZodString;
|
|
222
229
|
displayName: z.ZodString;
|
|
223
230
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
224
231
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -245,6 +252,7 @@ export declare const feedItemSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
245
252
|
contentKind: z.ZodLiteral<"donate_item">;
|
|
246
253
|
author: z.ZodObject<{
|
|
247
254
|
userId: z.ZodString;
|
|
255
|
+
username: z.ZodString;
|
|
248
256
|
displayName: z.ZodString;
|
|
249
257
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
250
258
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -291,6 +299,7 @@ export declare const feedResponseSchema: z.ZodObject<{
|
|
|
291
299
|
contentKind: z.ZodLiteral<"post">;
|
|
292
300
|
author: z.ZodObject<{
|
|
293
301
|
userId: z.ZodString;
|
|
302
|
+
username: z.ZodString;
|
|
294
303
|
displayName: z.ZodString;
|
|
295
304
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
296
305
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -334,6 +343,7 @@ export declare const feedResponseSchema: z.ZodObject<{
|
|
|
334
343
|
_id: z.ZodString;
|
|
335
344
|
author: z.ZodObject<{
|
|
336
345
|
userId: z.ZodString;
|
|
346
|
+
username: z.ZodString;
|
|
337
347
|
displayName: z.ZodString;
|
|
338
348
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
339
349
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -358,6 +368,7 @@ export declare const feedResponseSchema: z.ZodObject<{
|
|
|
358
368
|
contentKind: z.ZodLiteral<"lost_found">;
|
|
359
369
|
author: z.ZodObject<{
|
|
360
370
|
userId: z.ZodString;
|
|
371
|
+
username: z.ZodString;
|
|
361
372
|
displayName: z.ZodString;
|
|
362
373
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
363
374
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -385,6 +396,7 @@ export declare const feedResponseSchema: z.ZodObject<{
|
|
|
385
396
|
contentKind: z.ZodLiteral<"voice_box">;
|
|
386
397
|
author: z.ZodObject<{
|
|
387
398
|
userId: z.ZodString;
|
|
399
|
+
username: z.ZodString;
|
|
388
400
|
displayName: z.ZodString;
|
|
389
401
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
390
402
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -411,6 +423,7 @@ export declare const feedResponseSchema: z.ZodObject<{
|
|
|
411
423
|
contentKind: z.ZodLiteral<"donate_item">;
|
|
412
424
|
author: z.ZodObject<{
|
|
413
425
|
userId: z.ZodString;
|
|
426
|
+
username: z.ZodString;
|
|
414
427
|
displayName: z.ZodString;
|
|
415
428
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
416
429
|
localName: z.ZodOptional<z.ZodString>;
|
package/dist/feed.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feed.d.ts","sourceRoot":"","sources":["../src/feed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMhD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB
|
|
1
|
+
{"version":3,"file":"feed.d.ts","sourceRoot":"","sources":["../src/feed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMhD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4BlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiCnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyBjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAItE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAKzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAItD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;iBAShC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAG7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAG9D,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -29,4 +29,5 @@ export { type ReportContentBody, type ReportContentKind, type ReportRecordWire,
|
|
|
29
29
|
export { type CreateRepostBody, type CreateRepostResponse, createRepostBodySchema, createRepostResponseSchema, } from './repost.js';
|
|
30
30
|
export { type BlockedUsersListResponse, type BlockedUserWire, blockedUsersListResponseSchema, blockedUserWireSchema, COMMUNITY_SETTINGS_DEFAULTS, type CommunitySettingsWire, communitySettingsWireSchema, type UpdateCommunitySettingsBody, updateCommunitySettingsBodySchema, } from './settings.js';
|
|
31
31
|
export { type ToggleFollowResponse, toggleFollowResponseSchema, type ViewerSocialState, viewerSocialStateSchema, } from './social.js';
|
|
32
|
+
export { type CurrentUsernameState, currentUsernameStateSchema, type UpdateUsernameBody, type UpdateUsernameResponse, type Username, type UsernameAvailabilityResponse, type UsernameUnavailableReason, updateUsernameBodySchema, updateUsernameResponseSchema, usernameAvailabilityResponseSchema, USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH, USERNAME_PATTERN, USERNAME_UNAVAILABLE_REASONS, usernameSchema, usernameUnavailableReasonSchema, } from './username.js';
|
|
32
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -44,4 +44,6 @@ export { createRepostBodySchema, createRepostResponseSchema, } from './repost.js
|
|
|
44
44
|
export { blockedUsersListResponseSchema, blockedUserWireSchema, COMMUNITY_SETTINGS_DEFAULTS, communitySettingsWireSchema, updateCommunitySettingsBodySchema, } from './settings.js';
|
|
45
45
|
// ─── Social (follow) ───────────────────────────────────────────────────────
|
|
46
46
|
export { toggleFollowResponseSchema, viewerSocialStateSchema, } from './social.js';
|
|
47
|
+
// ─── Username (URL handle + change / availability) ────────────────────────
|
|
48
|
+
export { currentUsernameStateSchema, updateUsernameBodySchema, updateUsernameResponseSchema, usernameAvailabilityResponseSchema, USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH, USERNAME_PATTERN, USERNAME_UNAVAILABLE_REASONS, usernameSchema, usernameUnavailableReasonSchema, } from './username.js';
|
|
47
49
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * community-schema — Shared Zod schemas + TypeScript types for the\n * Jansathi hyperlocal community feature (feed, posts, engagement,\n * social graph, groups, settings).\n *\n * Single source of truth consumed by reform-backend and every product\n * frontend. The schemas mirror MongoDB / Mongoose document shapes\n * 1:1 so the same Zod validation runs at the controller boundary on\n * the backend and in the form handlers on the client.\n *\n * Cascade-upward visibility semantics: a viewer whose feed level is L\n * sees posts at L and every BROADER level matching their area lineage.\n * See `./enums.ts#VISIBILITY_LEVEL_VALUES` for the level rank table.\n *\n * @module community-schema\n */\n\n// ─── Area lineage snapshot ─────────────────────────────────────────────────\nexport {\n type AreaLineageSnapshot,\n areaLineageSnapshotSchema,\n} from './area.js';\n\n// ─── Comment ───────────────────────────────────────────────────────────────\nexport {\n type CommunityCommentWire,\n type CreateCommentBody,\n communityCommentWireSchema,\n createCommentBodySchema,\n type UpdateCommentBody,\n updateCommentBodySchema,\n} from './comment.js';\n\n// ─── Communities ───────────────────────────────────────────────────────────\nexport {\n COMMUNITY_DISCOVER_SORT_VALUES,\n COMMUNITY_MEMBERSHIP_STATUS_VALUES,\n COMMUNITY_ROLE_VALUES,\n COMMUNITY_TYPE_VALUES,\n type CommunityDiscoverSort,\n type CommunityListQuery,\n type CommunityListResponse,\n type CommunityMembershipStatus,\n type CommunityMembersListResponse,\n type CommunityMemberWire,\n type CommunityRole,\n type CommunityType,\n type CommunityWire,\n type CreateCommunityBody,\n communityDiscoverSortSchema,\n communityListQuerySchema,\n communityListResponseSchema,\n communityMembershipStatusSchema,\n communityMembersListResponseSchema,\n communityMemberWireSchema,\n communityRoleSchema,\n communityTypeSchema,\n communityWireSchema,\n createCommunityBodySchema,\n type JoinCommunityResponse,\n joinCommunityResponseSchema,\n type UpdateCommunityBody,\n type UpdateMemberRoleBody,\n updateCommunityBodySchema,\n updateMemberRoleBodySchema,\n} from './community.js';\n\n// ─── Constants ─────────────────────────────────────────────────────────────\nexport {\n COMMENT_MAX_BODY_CHARS,\n COMMENTS_PAGE_SIZE,\n COMMUNITIES_PAGE_SIZE,\n COMMUNITY_DESCRIPTION_MAX_CHARS,\n COMMUNITY_MEMBERS_PAGE_SIZE,\n COMMUNITY_NAME_MAX_CHARS,\n COMMUNITY_NAME_MIN_CHARS,\n COMMUNITY_SLUG_MAX_CHARS,\n COMMUNITY_SLUG_MIN_CHARS,\n COMMUNITY_SLUG_PATTERN,\n EDIT_GRACE_WINDOW_MS,\n FEED_PAGE_SIZE,\n GROUP_MAX_MEMBERS,\n GROUP_NAME_MAX_CHARS,\n GROUP_NAME_MIN_CHARS,\n PEOPLE_PAGE_SIZE,\n POST_MAX_BODY_CHARS,\n POST_MAX_IMAGE_BYTES,\n POST_MAX_IMAGES,\n POST_MAX_VIDEO_BYTES,\n POST_MAX_VIDEO_SECONDS,\n POST_MAX_VIDEOS,\n PROFILE_MAX_BIO_CHARS,\n REPLIES_PRELOAD_COUNT,\n} from './constants.js';\n\n// ─── Engagement (upvote + reactions) ───────────────────────────────────────\nexport {\n type SetReactionBody,\n type SetReactionResponse,\n setReactionBodySchema,\n setReactionResponseSchema,\n type ToggleUpvoteResponse,\n toggleUpvoteResponseSchema,\n} from './engagement.js';\n\n// ─── Enums ─────────────────────────────────────────────────────────────────\nexport {\n CONTENT_KIND_VALUES,\n type ContentKind,\n contentKindSchema,\n FEED_SORT_VALUES,\n type FeedSort,\n feedSortSchema,\n PROFILE_PRIVACY_VALUES,\n type ProfilePrivacy,\n profilePrivacySchema,\n REACTION_TYPE_VALUES,\n REPORT_REASON_VALUES,\n REPORT_STATUS_VALUES,\n type ReactionType,\n type ReportReason,\n type ReportStatus,\n reactionTypeSchema,\n reportReasonSchema,\n reportStatusSchema,\n VISIBILITY_LEVEL_RANK,\n VISIBILITY_LEVEL_VALUES,\n type VisibilityLevel,\n visibilityLevelSchema,\n} from './enums.js';\n\n// ─── Feed (polymorphic union) ──────────────────────────────────────────────\nexport {\n type DonateItemFeedItem,\n donateItemFeedItemSchema,\n type FeedItem,\n type FeedQueryParams,\n type FeedResponse,\n feedItemSchema,\n feedQueryParamsSchema,\n feedResponseSchema,\n type LostFoundFeedItem,\n lostFoundFeedItemSchema,\n type VoiceBoxFeedItem,\n voiceBoxFeedItemSchema,\n} from './feed.js';\n\n// ─── Groups ────────────────────────────────────────────────────────────────\nexport {\n type AddGroupMembersBody,\n addGroupMembersBodySchema,\n type CommunityGroupWire,\n type CommunityGroupWithMembers,\n type CreateGroupBody,\n communityGroupWireSchema,\n communityGroupWithMembersSchema,\n createGroupBodySchema,\n type GroupMembersListResponse,\n type GroupMemberWire,\n type GroupRole,\n type GroupsListResponse,\n groupMembersListResponseSchema,\n groupMemberWireSchema,\n groupRoleSchema,\n groupsListResponseSchema,\n type UpdateGroupBody,\n updateGroupBodySchema,\n} from './group.js';\n\n// ─── Media ─────────────────────────────────────────────────────────────────\nexport {\n type PostImage,\n type PostVideo,\n postImageSchema,\n postVideoSchema,\n} from './media.js';\n\n// ─── Post ──────────────────────────────────────────────────────────────────\nexport {\n type CommunityPostWire,\n type CreatePostBody,\n communityPostWireSchema,\n createPostBodySchema,\n type PostAuthorSnapshot,\n postAuthorSnapshotSchema,\n type RepostedSource,\n repostedSourceSchema,\n type UpdatePostBody,\n updatePostBodySchema,\n} from './post.js';\n// ─── Profile + People list ─────────────────────────────────────────────────\nexport {\n type PeopleListItem,\n type PeopleListResponse,\n type PeopleQueryParams,\n type ProfileMutuals,\n type PublicProfileWire,\n peopleListItemSchema,\n peopleListResponseSchema,\n peopleQueryParamsSchema,\n profileMutualsSchema,\n publicProfileWireSchema,\n} from './profile.js';\n// ─── Reports (moderation) ──────────────────────────────────────────────────\nexport {\n type ReportContentBody,\n type ReportContentKind,\n type ReportRecordWire,\n type ReportSubmissionResponse,\n type ReportUserBody,\n reportContentBodySchema,\n reportContentKindSchema,\n reportRecordWireSchema,\n reportSubmissionResponseSchema,\n reportUserBodySchema,\n} from './report.js';\n// ─── Repost (quote / amplify) ──────────────────────────────────────────────\nexport {\n type CreateRepostBody,\n type CreateRepostResponse,\n createRepostBodySchema,\n createRepostResponseSchema,\n} from './repost.js';\n\n// ─── Settings ──────────────────────────────────────────────────────────────\nexport {\n type BlockedUsersListResponse,\n type BlockedUserWire,\n blockedUsersListResponseSchema,\n blockedUserWireSchema,\n COMMUNITY_SETTINGS_DEFAULTS,\n type CommunitySettingsWire,\n communitySettingsWireSchema,\n type UpdateCommunitySettingsBody,\n updateCommunitySettingsBodySchema,\n} from './settings.js';\n\n// ─── Social (follow) ───────────────────────────────────────────────────────\nexport {\n type ToggleFollowResponse,\n toggleFollowResponseSchema,\n type ViewerSocialState,\n viewerSocialStateSchema,\n} from './social.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * community-schema — Shared Zod schemas + TypeScript types for the\n * Jansathi hyperlocal community feature (feed, posts, engagement,\n * social graph, groups, settings).\n *\n * Single source of truth consumed by reform-backend and every product\n * frontend. The schemas mirror MongoDB / Mongoose document shapes\n * 1:1 so the same Zod validation runs at the controller boundary on\n * the backend and in the form handlers on the client.\n *\n * Cascade-upward visibility semantics: a viewer whose feed level is L\n * sees posts at L and every BROADER level matching their area lineage.\n * See `./enums.ts#VISIBILITY_LEVEL_VALUES` for the level rank table.\n *\n * @module community-schema\n */\n\n// ─── Area lineage snapshot ─────────────────────────────────────────────────\nexport {\n type AreaLineageSnapshot,\n areaLineageSnapshotSchema,\n} from './area.js';\n\n// ─── Comment ───────────────────────────────────────────────────────────────\nexport {\n type CommunityCommentWire,\n type CreateCommentBody,\n communityCommentWireSchema,\n createCommentBodySchema,\n type UpdateCommentBody,\n updateCommentBodySchema,\n} from './comment.js';\n\n// ─── Communities ───────────────────────────────────────────────────────────\nexport {\n COMMUNITY_DISCOVER_SORT_VALUES,\n COMMUNITY_MEMBERSHIP_STATUS_VALUES,\n COMMUNITY_ROLE_VALUES,\n COMMUNITY_TYPE_VALUES,\n type CommunityDiscoverSort,\n type CommunityListQuery,\n type CommunityListResponse,\n type CommunityMembershipStatus,\n type CommunityMembersListResponse,\n type CommunityMemberWire,\n type CommunityRole,\n type CommunityType,\n type CommunityWire,\n type CreateCommunityBody,\n communityDiscoverSortSchema,\n communityListQuerySchema,\n communityListResponseSchema,\n communityMembershipStatusSchema,\n communityMembersListResponseSchema,\n communityMemberWireSchema,\n communityRoleSchema,\n communityTypeSchema,\n communityWireSchema,\n createCommunityBodySchema,\n type JoinCommunityResponse,\n joinCommunityResponseSchema,\n type UpdateCommunityBody,\n type UpdateMemberRoleBody,\n updateCommunityBodySchema,\n updateMemberRoleBodySchema,\n} from './community.js';\n\n// ─── Constants ─────────────────────────────────────────────────────────────\nexport {\n COMMENT_MAX_BODY_CHARS,\n COMMENTS_PAGE_SIZE,\n COMMUNITIES_PAGE_SIZE,\n COMMUNITY_DESCRIPTION_MAX_CHARS,\n COMMUNITY_MEMBERS_PAGE_SIZE,\n COMMUNITY_NAME_MAX_CHARS,\n COMMUNITY_NAME_MIN_CHARS,\n COMMUNITY_SLUG_MAX_CHARS,\n COMMUNITY_SLUG_MIN_CHARS,\n COMMUNITY_SLUG_PATTERN,\n EDIT_GRACE_WINDOW_MS,\n FEED_PAGE_SIZE,\n GROUP_MAX_MEMBERS,\n GROUP_NAME_MAX_CHARS,\n GROUP_NAME_MIN_CHARS,\n PEOPLE_PAGE_SIZE,\n POST_MAX_BODY_CHARS,\n POST_MAX_IMAGE_BYTES,\n POST_MAX_IMAGES,\n POST_MAX_VIDEO_BYTES,\n POST_MAX_VIDEO_SECONDS,\n POST_MAX_VIDEOS,\n PROFILE_MAX_BIO_CHARS,\n REPLIES_PRELOAD_COUNT,\n} from './constants.js';\n\n// ─── Engagement (upvote + reactions) ───────────────────────────────────────\nexport {\n type SetReactionBody,\n type SetReactionResponse,\n setReactionBodySchema,\n setReactionResponseSchema,\n type ToggleUpvoteResponse,\n toggleUpvoteResponseSchema,\n} from './engagement.js';\n\n// ─── Enums ─────────────────────────────────────────────────────────────────\nexport {\n CONTENT_KIND_VALUES,\n type ContentKind,\n contentKindSchema,\n FEED_SORT_VALUES,\n type FeedSort,\n feedSortSchema,\n PROFILE_PRIVACY_VALUES,\n type ProfilePrivacy,\n profilePrivacySchema,\n REACTION_TYPE_VALUES,\n REPORT_REASON_VALUES,\n REPORT_STATUS_VALUES,\n type ReactionType,\n type ReportReason,\n type ReportStatus,\n reactionTypeSchema,\n reportReasonSchema,\n reportStatusSchema,\n VISIBILITY_LEVEL_RANK,\n VISIBILITY_LEVEL_VALUES,\n type VisibilityLevel,\n visibilityLevelSchema,\n} from './enums.js';\n\n// ─── Feed (polymorphic union) ──────────────────────────────────────────────\nexport {\n type DonateItemFeedItem,\n donateItemFeedItemSchema,\n type FeedItem,\n type FeedQueryParams,\n type FeedResponse,\n feedItemSchema,\n feedQueryParamsSchema,\n feedResponseSchema,\n type LostFoundFeedItem,\n lostFoundFeedItemSchema,\n type VoiceBoxFeedItem,\n voiceBoxFeedItemSchema,\n} from './feed.js';\n\n// ─── Groups ────────────────────────────────────────────────────────────────\nexport {\n type AddGroupMembersBody,\n addGroupMembersBodySchema,\n type CommunityGroupWire,\n type CommunityGroupWithMembers,\n type CreateGroupBody,\n communityGroupWireSchema,\n communityGroupWithMembersSchema,\n createGroupBodySchema,\n type GroupMembersListResponse,\n type GroupMemberWire,\n type GroupRole,\n type GroupsListResponse,\n groupMembersListResponseSchema,\n groupMemberWireSchema,\n groupRoleSchema,\n groupsListResponseSchema,\n type UpdateGroupBody,\n updateGroupBodySchema,\n} from './group.js';\n\n// ─── Media ─────────────────────────────────────────────────────────────────\nexport {\n type PostImage,\n type PostVideo,\n postImageSchema,\n postVideoSchema,\n} from './media.js';\n\n// ─── Post ──────────────────────────────────────────────────────────────────\nexport {\n type CommunityPostWire,\n type CreatePostBody,\n communityPostWireSchema,\n createPostBodySchema,\n type PostAuthorSnapshot,\n postAuthorSnapshotSchema,\n type RepostedSource,\n repostedSourceSchema,\n type UpdatePostBody,\n updatePostBodySchema,\n} from './post.js';\n// ─── Profile + People list ─────────────────────────────────────────────────\nexport {\n type PeopleListItem,\n type PeopleListResponse,\n type PeopleQueryParams,\n type ProfileMutuals,\n type PublicProfileWire,\n peopleListItemSchema,\n peopleListResponseSchema,\n peopleQueryParamsSchema,\n profileMutualsSchema,\n publicProfileWireSchema,\n} from './profile.js';\n// ─── Reports (moderation) ──────────────────────────────────────────────────\nexport {\n type ReportContentBody,\n type ReportContentKind,\n type ReportRecordWire,\n type ReportSubmissionResponse,\n type ReportUserBody,\n reportContentBodySchema,\n reportContentKindSchema,\n reportRecordWireSchema,\n reportSubmissionResponseSchema,\n reportUserBodySchema,\n} from './report.js';\n// ─── Repost (quote / amplify) ──────────────────────────────────────────────\nexport {\n type CreateRepostBody,\n type CreateRepostResponse,\n createRepostBodySchema,\n createRepostResponseSchema,\n} from './repost.js';\n\n// ─── Settings ──────────────────────────────────────────────────────────────\nexport {\n type BlockedUsersListResponse,\n type BlockedUserWire,\n blockedUsersListResponseSchema,\n blockedUserWireSchema,\n COMMUNITY_SETTINGS_DEFAULTS,\n type CommunitySettingsWire,\n communitySettingsWireSchema,\n type UpdateCommunitySettingsBody,\n updateCommunitySettingsBodySchema,\n} from './settings.js';\n\n// ─── Social (follow) ───────────────────────────────────────────────────────\nexport {\n type ToggleFollowResponse,\n toggleFollowResponseSchema,\n type ViewerSocialState,\n viewerSocialStateSchema,\n} from './social.js';\n\n// ─── Username (URL handle + change / availability) ────────────────────────\nexport {\n type CurrentUsernameState,\n currentUsernameStateSchema,\n type UpdateUsernameBody,\n type UpdateUsernameResponse,\n type Username,\n type UsernameAvailabilityResponse,\n type UsernameUnavailableReason,\n updateUsernameBodySchema,\n updateUsernameResponseSchema,\n usernameAvailabilityResponseSchema,\n USERNAME_MAX_LENGTH,\n USERNAME_MIN_LENGTH,\n USERNAME_PATTERN,\n USERNAME_UNAVAILABLE_REASONS,\n usernameSchema,\n usernameUnavailableReasonSchema,\n} from './username.js';\n"]}
|
package/dist/post.d.ts
CHANGED
|
@@ -10,17 +10,25 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { z } from 'zod';
|
|
12
12
|
/**
|
|
13
|
-
* The author's display info
|
|
14
|
-
* `displayName` / `avatarUrl` / `localName` here avoids a $lookup
|
|
15
|
-
* against the User collection on every feed read — feed scans 20–40
|
|
16
|
-
* posts per page and population would be a hot path.
|
|
13
|
+
* The author's display info attached to every feed row.
|
|
17
14
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
* Two classes of fields here:
|
|
16
|
+
*
|
|
17
|
+
* - **Live (refreshed at read time)**: `username`, `displayName`,
|
|
18
|
+
* `avatarUrl`. The projector batch-joins these against the User
|
|
19
|
+
* collection per page, so a name or avatar change instantly
|
|
20
|
+
* propagates to old posts and the byline link always targets the
|
|
21
|
+
* CURRENT username (no stale `/oldhandle` 404 after a rename).
|
|
22
|
+
*
|
|
23
|
+
* - **Snapshotted at write time**: `localName`. This is "where the
|
|
24
|
+
* author was when posting" — a deliberate snapshot, not a stale
|
|
25
|
+
* read of their current location.
|
|
26
|
+
*
|
|
27
|
+
* @module community-schema/post (postAuthorSnapshotSchema)
|
|
21
28
|
*/
|
|
22
29
|
export declare const postAuthorSnapshotSchema: z.ZodObject<{
|
|
23
30
|
userId: z.ZodString;
|
|
31
|
+
username: z.ZodString;
|
|
24
32
|
displayName: z.ZodString;
|
|
25
33
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
26
34
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -51,6 +59,7 @@ export declare const repostedSourceSchema: z.ZodObject<{
|
|
|
51
59
|
_id: z.ZodString;
|
|
52
60
|
author: z.ZodObject<{
|
|
53
61
|
userId: z.ZodString;
|
|
62
|
+
username: z.ZodString;
|
|
54
63
|
displayName: z.ZodString;
|
|
55
64
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
56
65
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -73,6 +82,7 @@ export declare const communityPostWireSchema: z.ZodObject<{
|
|
|
73
82
|
contentKind: z.ZodLiteral<"post">;
|
|
74
83
|
author: z.ZodObject<{
|
|
75
84
|
userId: z.ZodString;
|
|
85
|
+
username: z.ZodString;
|
|
76
86
|
displayName: z.ZodString;
|
|
77
87
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
78
88
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -116,6 +126,7 @@ export declare const communityPostWireSchema: z.ZodObject<{
|
|
|
116
126
|
_id: z.ZodString;
|
|
117
127
|
author: z.ZodObject<{
|
|
118
128
|
userId: z.ZodString;
|
|
129
|
+
username: z.ZodString;
|
|
119
130
|
displayName: z.ZodString;
|
|
120
131
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
121
132
|
localName: z.ZodOptional<z.ZodString>;
|
package/dist/post.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post.d.ts","sourceRoot":"","sources":["../src/post.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"post.d.ts","sourceRoot":"","sources":["../src/post.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,wBAAwB;;;;;;iBAcnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAI1E;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;iBAuB/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAIlE;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyDlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;iBAO/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;iBAE/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
package/dist/post.js
CHANGED
|
@@ -13,26 +13,37 @@ import { areaLineageSnapshotSchema } from './area.js';
|
|
|
13
13
|
import { POST_MAX_BODY_CHARS, POST_MAX_IMAGES, POST_MAX_VIDEOS } from './constants.js';
|
|
14
14
|
import { contentKindSchema } from './enums.js';
|
|
15
15
|
import { postImageSchema, postVideoSchema } from './media.js';
|
|
16
|
+
import { usernameSchema } from './username.js';
|
|
16
17
|
// ─── Author snapshot (denormalised on every post) ──────────────────────────
|
|
17
18
|
/**
|
|
18
|
-
* The author's display info
|
|
19
|
-
* `displayName` / `avatarUrl` / `localName` here avoids a $lookup
|
|
20
|
-
* against the User collection on every feed read — feed scans 20–40
|
|
21
|
-
* posts per page and population would be a hot path.
|
|
19
|
+
* The author's display info attached to every feed row.
|
|
22
20
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* Two classes of fields here:
|
|
22
|
+
*
|
|
23
|
+
* - **Live (refreshed at read time)**: `username`, `displayName`,
|
|
24
|
+
* `avatarUrl`. The projector batch-joins these against the User
|
|
25
|
+
* collection per page, so a name or avatar change instantly
|
|
26
|
+
* propagates to old posts and the byline link always targets the
|
|
27
|
+
* CURRENT username (no stale `/oldhandle` 404 after a rename).
|
|
28
|
+
*
|
|
29
|
+
* - **Snapshotted at write time**: `localName`. This is "where the
|
|
30
|
+
* author was when posting" — a deliberate snapshot, not a stale
|
|
31
|
+
* read of their current location.
|
|
32
|
+
*
|
|
33
|
+
* @module community-schema/post (postAuthorSnapshotSchema)
|
|
26
34
|
*/
|
|
27
35
|
export const postAuthorSnapshotSchema = z.object({
|
|
28
36
|
userId: z.string(),
|
|
37
|
+
/** Public URL handle. Live-joined from User at read time so the
|
|
38
|
+
* byline links to `/<currentUsername>` even after a rename. */
|
|
39
|
+
username: usernameSchema,
|
|
29
40
|
displayName: z.string(),
|
|
30
41
|
avatarUrl: z.string().url().optional(),
|
|
31
42
|
/**
|
|
32
43
|
* The author's "local" area label at post time, e.g. "Rohini Sector 15".
|
|
33
44
|
* Powers the byline "<DisplayName> · <localName> · <relativeTime>".
|
|
34
|
-
*
|
|
35
|
-
*
|
|
45
|
+
* Snapshotted at write time — does NOT track the author's current
|
|
46
|
+
* location.
|
|
36
47
|
*/
|
|
37
48
|
localName: z.string().optional(),
|
|
38
49
|
});
|
package/dist/post.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post.js","sourceRoot":"","sources":["../src/post.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Community post wire shapes.\n *\n * A \"post\" is the native community content kind (text-primary + media).\n * Lost-and-found and voice-box items show up in the same feed via\n * polymorphic union; their shapes live in their own schema packages\n * and are projected into a `FeedItem` envelope (see `./feed.ts`).\n *\n * @module community-schema/post\n */\n\nimport { z } from 'zod';\nimport { areaLineageSnapshotSchema } from './area.js';\nimport { POST_MAX_BODY_CHARS, POST_MAX_IMAGES, POST_MAX_VIDEOS } from './constants.js';\nimport { contentKindSchema } from './enums.js';\nimport { postImageSchema, postVideoSchema } from './media.js';\n\n// ─── Author snapshot (denormalised on every post) ──────────────────────────\n\n/**\n * The author's display info captured at post time. Denormalising\n * `displayName` / `avatarUrl` / `localName` here avoids a $lookup\n * against the User collection on every feed read — feed scans 20–40\n * posts per page and population would be a hot path.\n *\n * The User document remains the source of truth; a background job\n * (or a hook on User.findOneAndUpdate) refreshes recent posts when\n * a user changes their display name or avatar.\n */\nexport const postAuthorSnapshotSchema = z.object({\n userId: z.string(),\n displayName: z.string(),\n avatarUrl: z.string().url().optional(),\n /**\n * The author's \"local\" area label at post time, e.g. \"Rohini Sector 15\".\n * Powers the byline \"<DisplayName> · <localName> · <relativeTime>\".\n * Hidden when the author has a private profile and the viewer is\n * not an accepted Connection.\n */\n localName: z.string().optional(),\n});\nexport type PostAuthorSnapshot = z.infer<typeof postAuthorSnapshotSchema>;\n\n// ─── Reposted source snapshot ──────────────────────────────────────────────\n\n/**\n * Compact embed shape used when a CommunityPost is a repost (caption +\n * optional quote of another item). Modelled after Twitter's quote-tweet\n * embed: byline + truncated text/title + first image + kind badge + the\n * moment-of-creation timestamp.\n *\n * Engagement counts are intentionally NOT included — they'd drift\n * relative to the live source. The card embeds this as a static teaser\n * that links to the source for the live numbers.\n *\n * Backend snapshots these fields at repost-create time from the source\n * row (post text / item title / first photo / status badge), so the\n * embed survives source edits / soft-deletes / hides — the user's\n * reaction at repost time is preserved.\n */\nexport const repostedSourceSchema = z.object({\n /** Which kind was reposted. Lets the embed render the right icon. */\n contentKind: contentKindSchema,\n /** Source row's id — tap-embed navigates to its thread / detail page. */\n _id: z.string(),\n /** Author snapshot of the source at repost time. */\n author: postAuthorSnapshotSchema,\n /** Primary text. For posts: the body text (truncated). For lost_found /\n * voice_box / donate_item: the title. */\n title: z.string(),\n /** Optional secondary line. For posts: unused. For legacy kinds: the\n * description (truncated server-side). */\n body: z.string().optional(),\n /** First image if any. */\n imageUrl: z.string().url().optional(),\n /** Small kind-specific badge:\n * - posts → undefined\n * - lost_found → 'lost' | 'found'\n * - voice_box → 'complaint' | 'suggestion'\n * - donate_item → 'PENDING' | 'VERIFIED' | 'AT_CENTER' | 'DONATED'\n */\n kindBadge: z.string().optional(),\n createdAt: z.string().datetime(),\n});\nexport type RepostedSource = z.infer<typeof repostedSourceSchema>;\n\n// ─── Wire shape — what the server returns ──────────────────────────────────\n\n/**\n * A community post as it appears in the feed and on the single-post\n * page. Engagement counts are denormalised onto the document for\n * fast feed sorting; the per-user reaction state (\"did I upvote this?\")\n * is computed at read time and returned in the `viewer` block.\n */\nexport const communityPostWireSchema = z.object({\n _id: z.string(),\n contentKind: z.literal('post'),\n author: postAuthorSnapshotSchema,\n\n // Body — for a repost, this carries the caption (may be empty).\n text: z.string().max(POST_MAX_BODY_CHARS),\n images: z.array(postImageSchema).max(POST_MAX_IMAGES),\n videos: z.array(postVideoSchema).max(POST_MAX_VIDEOS),\n\n // Authorship area\n /** Snapshot of where the author was at write time. Drives the\n * area-proximity cascade and ranking in feed.service. */\n areaLineage: areaLineageSnapshotSchema,\n /** When set, the post is scoped to a topical community and is NOT\n * surfaced via the geo cascade. The community feed adds an explicit\n * `communityId` filter to its read queries. Posts authored from the\n * global composer leave this null. */\n communityId: z.string().optional(),\n\n // Denormalised engagement counters (drive feed sort + card render)\n upvoteCount: z.number().int().nonnegative(),\n commentCount: z.number().int().nonnegative(),\n /** How many times this post has been reposted. Incremented by the\n * repost endpoint; reposts of reposts are blocked server-side. */\n repostCount: z.number().int().nonnegative(),\n /** Map of `ReactionType` → count, e.g. { like: 4, love: 1 }. */\n reactionCounts: z.record(z.string(), z.number().int().nonnegative()),\n\n /** Source-snapshot when this post is a repost. Absent on regular posts.\n * The wrapper post owns its own engagement counters; this embed is\n * a static teaser of the original at repost time. */\n repostOf: repostedSourceSchema.optional(),\n\n // Lifecycle\n createdAt: z.string().datetime(),\n /** Last edit timestamp, or null if never edited. Edit window is\n * enforced by the server at write time, not by this schema. */\n editedAt: z.string().datetime().nullable(),\n deletedAt: z.string().datetime().nullable(),\n\n // Per-viewer state (filled by the server at read time)\n viewer: z\n .object({\n upvoted: z.boolean(),\n /** The reaction the viewer chose, or null. Mutually exclusive\n * with `upvoted` is intentionally NOT enforced — they're two\n * separate axes per the product decision. */\n reaction: z.string().nullable(),\n /** True when the viewer authored the post (controls edit / delete buttons). */\n isAuthor: z.boolean(),\n /** True when the viewer has already reposted this source. The\n * client uses this to render the repost button as \"already\n * reposted\" rather than as a fresh CTA. */\n reposted: z.boolean(),\n })\n .optional(),\n});\nexport type CommunityPostWire = z.infer<typeof communityPostWireSchema>;\n\n// ─── Create / update bodies ────────────────────────────────────────────────\n\n/**\n * What the client sends to `POST /api/v1/community/posts`. The author\n * is taken from the authenticated request; the area lineage is resolved\n * server-side from the user's `currentLocation` (the client cannot\n * spoof a different area).\n */\nexport const createPostBodySchema = z.object({\n text: z.string().min(1).max(POST_MAX_BODY_CHARS),\n images: z.array(postImageSchema).max(POST_MAX_IMAGES).optional(),\n videos: z.array(postVideoSchema).max(POST_MAX_VIDEOS).optional(),\n /** When set, the post is scoped to a topical community. The author\n * must be an active member; non-members get a 403. */\n communityId: z.string().optional(),\n});\nexport type CreatePostBody = z.infer<typeof createPostBodySchema>;\n\n/**\n * What the client sends to `PATCH /api/v1/community/posts/:id`. Only\n * the text body is editable — media additions / removals require a new\n * post (matches Twitter / FB convention).\n */\nexport const updatePostBodySchema = z.object({\n text: z.string().min(1).max(POST_MAX_BODY_CHARS),\n});\nexport type UpdatePostBody = z.infer<typeof updatePostBodySchema>;\n"]}
|
|
1
|
+
{"version":3,"file":"post.js","sourceRoot":"","sources":["../src/post.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,8EAA8E;AAE9E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB;oEACgE;IAChE,QAAQ,EAAE,cAAc;IACxB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACtC;;;;;OAKG;IACH,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAGH,8EAA8E;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,qEAAqE;IACrE,WAAW,EAAE,iBAAiB;IAC9B,yEAAyE;IACzE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,oDAAoD;IACpD,MAAM,EAAE,wBAAwB;IAChC;8CAC0C;IAC1C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB;+CAC2C;IAC3C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,0BAA0B;IAC1B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACrC;;;;;OAKG;IACH,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAGH,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC9B,MAAM,EAAE,wBAAwB;IAEhC,gEAAgE;IAChE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACzC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC;IACrD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC;IAErD,kBAAkB;IAClB;8DAC0D;IAC1D,WAAW,EAAE,yBAAyB;IACtC;;;2CAGuC;IACvC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAElC,mEAAmE;IACnE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC3C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C;uEACmE;IACnE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC3C,gEAAgE;IAChE,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;IAEpE;;0DAEsD;IACtD,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAEzC,YAAY;IACZ,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC;oEACgE;IAChE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAE3C,uDAAuD;IACvD,MAAM,EAAE,CAAC;SACN,MAAM,CAAC;QACN,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;QACpB;;sDAE8C;QAC9C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC/B,+EAA+E;QAC/E,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;QACrB;;oDAE4C;QAC5C,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;KACtB,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAGH,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC;IAChD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IAChE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IAChE;2DACuD;IACvD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAGH;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC;CACjD,CAAC,CAAC","sourcesContent":["/**\n * Community post wire shapes.\n *\n * A \"post\" is the native community content kind (text-primary + media).\n * Lost-and-found and voice-box items show up in the same feed via\n * polymorphic union; their shapes live in their own schema packages\n * and are projected into a `FeedItem` envelope (see `./feed.ts`).\n *\n * @module community-schema/post\n */\n\nimport { z } from 'zod';\nimport { areaLineageSnapshotSchema } from './area.js';\nimport { POST_MAX_BODY_CHARS, POST_MAX_IMAGES, POST_MAX_VIDEOS } from './constants.js';\nimport { contentKindSchema } from './enums.js';\nimport { postImageSchema, postVideoSchema } from './media.js';\nimport { usernameSchema } from './username.js';\n\n// ─── Author snapshot (denormalised on every post) ──────────────────────────\n\n/**\n * The author's display info attached to every feed row.\n *\n * Two classes of fields here:\n *\n * - **Live (refreshed at read time)**: `username`, `displayName`,\n * `avatarUrl`. The projector batch-joins these against the User\n * collection per page, so a name or avatar change instantly\n * propagates to old posts and the byline link always targets the\n * CURRENT username (no stale `/oldhandle` 404 after a rename).\n *\n * - **Snapshotted at write time**: `localName`. This is \"where the\n * author was when posting\" — a deliberate snapshot, not a stale\n * read of their current location.\n *\n * @module community-schema/post (postAuthorSnapshotSchema)\n */\nexport const postAuthorSnapshotSchema = z.object({\n userId: z.string(),\n /** Public URL handle. Live-joined from User at read time so the\n * byline links to `/<currentUsername>` even after a rename. */\n username: usernameSchema,\n displayName: z.string(),\n avatarUrl: z.string().url().optional(),\n /**\n * The author's \"local\" area label at post time, e.g. \"Rohini Sector 15\".\n * Powers the byline \"<DisplayName> · <localName> · <relativeTime>\".\n * Snapshotted at write time — does NOT track the author's current\n * location.\n */\n localName: z.string().optional(),\n});\nexport type PostAuthorSnapshot = z.infer<typeof postAuthorSnapshotSchema>;\n\n// ─── Reposted source snapshot ──────────────────────────────────────────────\n\n/**\n * Compact embed shape used when a CommunityPost is a repost (caption +\n * optional quote of another item). Modelled after Twitter's quote-tweet\n * embed: byline + truncated text/title + first image + kind badge + the\n * moment-of-creation timestamp.\n *\n * Engagement counts are intentionally NOT included — they'd drift\n * relative to the live source. The card embeds this as a static teaser\n * that links to the source for the live numbers.\n *\n * Backend snapshots these fields at repost-create time from the source\n * row (post text / item title / first photo / status badge), so the\n * embed survives source edits / soft-deletes / hides — the user's\n * reaction at repost time is preserved.\n */\nexport const repostedSourceSchema = z.object({\n /** Which kind was reposted. Lets the embed render the right icon. */\n contentKind: contentKindSchema,\n /** Source row's id — tap-embed navigates to its thread / detail page. */\n _id: z.string(),\n /** Author snapshot of the source at repost time. */\n author: postAuthorSnapshotSchema,\n /** Primary text. For posts: the body text (truncated). For lost_found /\n * voice_box / donate_item: the title. */\n title: z.string(),\n /** Optional secondary line. For posts: unused. For legacy kinds: the\n * description (truncated server-side). */\n body: z.string().optional(),\n /** First image if any. */\n imageUrl: z.string().url().optional(),\n /** Small kind-specific badge:\n * - posts → undefined\n * - lost_found → 'lost' | 'found'\n * - voice_box → 'complaint' | 'suggestion'\n * - donate_item → 'PENDING' | 'VERIFIED' | 'AT_CENTER' | 'DONATED'\n */\n kindBadge: z.string().optional(),\n createdAt: z.string().datetime(),\n});\nexport type RepostedSource = z.infer<typeof repostedSourceSchema>;\n\n// ─── Wire shape — what the server returns ──────────────────────────────────\n\n/**\n * A community post as it appears in the feed and on the single-post\n * page. Engagement counts are denormalised onto the document for\n * fast feed sorting; the per-user reaction state (\"did I upvote this?\")\n * is computed at read time and returned in the `viewer` block.\n */\nexport const communityPostWireSchema = z.object({\n _id: z.string(),\n contentKind: z.literal('post'),\n author: postAuthorSnapshotSchema,\n\n // Body — for a repost, this carries the caption (may be empty).\n text: z.string().max(POST_MAX_BODY_CHARS),\n images: z.array(postImageSchema).max(POST_MAX_IMAGES),\n videos: z.array(postVideoSchema).max(POST_MAX_VIDEOS),\n\n // Authorship area\n /** Snapshot of where the author was at write time. Drives the\n * area-proximity cascade and ranking in feed.service. */\n areaLineage: areaLineageSnapshotSchema,\n /** When set, the post is scoped to a topical community and is NOT\n * surfaced via the geo cascade. The community feed adds an explicit\n * `communityId` filter to its read queries. Posts authored from the\n * global composer leave this null. */\n communityId: z.string().optional(),\n\n // Denormalised engagement counters (drive feed sort + card render)\n upvoteCount: z.number().int().nonnegative(),\n commentCount: z.number().int().nonnegative(),\n /** How many times this post has been reposted. Incremented by the\n * repost endpoint; reposts of reposts are blocked server-side. */\n repostCount: z.number().int().nonnegative(),\n /** Map of `ReactionType` → count, e.g. { like: 4, love: 1 }. */\n reactionCounts: z.record(z.string(), z.number().int().nonnegative()),\n\n /** Source-snapshot when this post is a repost. Absent on regular posts.\n * The wrapper post owns its own engagement counters; this embed is\n * a static teaser of the original at repost time. */\n repostOf: repostedSourceSchema.optional(),\n\n // Lifecycle\n createdAt: z.string().datetime(),\n /** Last edit timestamp, or null if never edited. Edit window is\n * enforced by the server at write time, not by this schema. */\n editedAt: z.string().datetime().nullable(),\n deletedAt: z.string().datetime().nullable(),\n\n // Per-viewer state (filled by the server at read time)\n viewer: z\n .object({\n upvoted: z.boolean(),\n /** The reaction the viewer chose, or null. Mutually exclusive\n * with `upvoted` is intentionally NOT enforced — they're two\n * separate axes per the product decision. */\n reaction: z.string().nullable(),\n /** True when the viewer authored the post (controls edit / delete buttons). */\n isAuthor: z.boolean(),\n /** True when the viewer has already reposted this source. The\n * client uses this to render the repost button as \"already\n * reposted\" rather than as a fresh CTA. */\n reposted: z.boolean(),\n })\n .optional(),\n});\nexport type CommunityPostWire = z.infer<typeof communityPostWireSchema>;\n\n// ─── Create / update bodies ────────────────────────────────────────────────\n\n/**\n * What the client sends to `POST /api/v1/community/posts`. The author\n * is taken from the authenticated request; the area lineage is resolved\n * server-side from the user's `currentLocation` (the client cannot\n * spoof a different area).\n */\nexport const createPostBodySchema = z.object({\n text: z.string().min(1).max(POST_MAX_BODY_CHARS),\n images: z.array(postImageSchema).max(POST_MAX_IMAGES).optional(),\n videos: z.array(postVideoSchema).max(POST_MAX_VIDEOS).optional(),\n /** When set, the post is scoped to a topical community. The author\n * must be an active member; non-members get a 403. */\n communityId: z.string().optional(),\n});\nexport type CreatePostBody = z.infer<typeof createPostBodySchema>;\n\n/**\n * What the client sends to `PATCH /api/v1/community/posts/:id`. Only\n * the text body is editable — media additions / removals require a new\n * post (matches Twitter / FB convention).\n */\nexport const updatePostBodySchema = z.object({\n text: z.string().min(1).max(POST_MAX_BODY_CHARS),\n});\nexport type UpdatePostBody = z.infer<typeof updatePostBodySchema>;\n"]}
|
package/dist/profile.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export declare const profileMutualsSchema: z.ZodObject<{
|
|
|
31
31
|
export type ProfileMutuals = z.infer<typeof profileMutualsSchema>;
|
|
32
32
|
export declare const publicProfileWireSchema: z.ZodObject<{
|
|
33
33
|
userId: z.ZodString;
|
|
34
|
+
username: z.ZodString;
|
|
34
35
|
displayName: z.ZodString;
|
|
35
36
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
36
37
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -60,6 +61,7 @@ export type PublicProfileWire = z.infer<typeof publicProfileWireSchema>;
|
|
|
60
61
|
*/
|
|
61
62
|
export declare const peopleListItemSchema: z.ZodObject<{
|
|
62
63
|
userId: z.ZodString;
|
|
64
|
+
username: z.ZodString;
|
|
63
65
|
displayName: z.ZodString;
|
|
64
66
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
65
67
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -88,6 +90,7 @@ export type PeopleQueryParams = z.infer<typeof peopleQueryParamsSchema>;
|
|
|
88
90
|
export declare const peopleListResponseSchema: z.ZodObject<{
|
|
89
91
|
items: z.ZodArray<z.ZodObject<{
|
|
90
92
|
userId: z.ZodString;
|
|
93
|
+
username: z.ZodString;
|
|
91
94
|
displayName: z.ZodString;
|
|
92
95
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
93
96
|
localName: z.ZodOptional<z.ZodString>;
|
package/dist/profile.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;iBAW/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;iBAwClC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;iBAU/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,uBAAuB;;;;;;;;;;;iBAQlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;iBAGnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
|
package/dist/profile.js
CHANGED
|
@@ -20,6 +20,7 @@ import { z } from 'zod';
|
|
|
20
20
|
import { PROFILE_MAX_BIO_CHARS } from './constants.js';
|
|
21
21
|
import { profilePrivacySchema, visibilityLevelSchema } from './enums.js';
|
|
22
22
|
import { viewerSocialStateSchema } from './social.js';
|
|
23
|
+
import { usernameSchema } from './username.js';
|
|
23
24
|
/**
|
|
24
25
|
* Mini-row used in the "Followed by X, Y + N more" mutuals line on the
|
|
25
26
|
* profile header. The server picks up to 3 sample names + a count of
|
|
@@ -40,6 +41,11 @@ export const profileMutualsSchema = z.object({
|
|
|
40
41
|
});
|
|
41
42
|
export const publicProfileWireSchema = z.object({
|
|
42
43
|
userId: z.string(),
|
|
44
|
+
/** Public URL handle. The profile page lives at `/<username>`; this
|
|
45
|
+
* is the canonical identity surfaced to the viewer. Always present
|
|
46
|
+
* — every user is auto-minted a username at provisioning time and
|
|
47
|
+
* can change it from community Settings (14-day cooldown). */
|
|
48
|
+
username: usernameSchema,
|
|
43
49
|
displayName: z.string(),
|
|
44
50
|
avatarUrl: z.string().url().optional(),
|
|
45
51
|
/** Author area at view time (resolved server-side). Hidden when
|
|
@@ -75,6 +81,9 @@ export const publicProfileWireSchema = z.object({
|
|
|
75
81
|
*/
|
|
76
82
|
export const peopleListItemSchema = z.object({
|
|
77
83
|
userId: z.string(),
|
|
84
|
+
/** Public URL handle (see `publicProfileWireSchema.username`). Always
|
|
85
|
+
* present — the row's display + tap-to-profile link both depend on it. */
|
|
86
|
+
username: usernameSchema,
|
|
78
87
|
displayName: z.string(),
|
|
79
88
|
avatarUrl: z.string().url().optional(),
|
|
80
89
|
localName: z.string().optional(),
|
package/dist/profile.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Public community-profile wire shape.\n *\n * What every viewer can see about another user's community presence.\n * Differs from the auth/UDP `User` shape — this view is purposely thin\n * and content-engagement-oriented (post count, follower count, …).\n *\n * Privacy gating:\n * - `public` profile: the full shape is returned to any signed-in viewer.\n * - `private` profile: only `userId`, `displayName`, `avatarUrl`, and\n * the viewer's follow state are returned to non-followers. Posts and\n * counters are hidden until the viewer follows the profile owner and\n * the owner has accepted (TODO: follow-approval lifecycle — currently\n * \"private\" simply hides counters/posts from anyone who isn't the\n * owner).\n *\n * @module community-schema/profile\n */\n\nimport { z } from 'zod';\nimport { PROFILE_MAX_BIO_CHARS } from './constants.js';\nimport { profilePrivacySchema, visibilityLevelSchema } from './enums.js';\nimport { viewerSocialStateSchema } from './social.js';\nimport { usernameSchema } from './username.js';\n\n/**\n * Mini-row used in the \"Followed by X, Y + N more\" mutuals line on the\n * profile header. The server picks up to 3 sample names + a count of\n * the remaining mutuals so the row reads naturally without paginating\n * the full mutuals list inline.\n */\nexport const profileMutualsSchema = z.object({\n /** Avatar URLs (or single-letter fallbacks via `null`) for the sample\n * mutuals — order is \"show first\" → \"show last\". Capped at 3. */\n avatars: z.array(z.string().url().nullable()).max(3),\n /** Display names matched 1:1 with `avatars` order. Empty when the\n * viewer has no mutuals with the profile owner. */\n sampleNames: z.array(z.string()).max(3),\n /** How many additional mutuals exist beyond the sample. Used to\n * render the trailing \"+ N more\" suffix. Zero when the sample IS\n * the full list. */\n extraCount: z.number().int().nonnegative(),\n});\nexport type ProfileMutuals = z.infer<typeof profileMutualsSchema>;\n\nexport const publicProfileWireSchema = z.object({\n userId: z.string(),\n /** Public URL handle. The profile page lives at `/<username>`; this\n * is the canonical identity surfaced to the viewer. Always present\n * — every user is auto-minted a username at provisioning time and\n * can change it from community Settings (14-day cooldown). */\n username: usernameSchema,\n displayName: z.string(),\n avatarUrl: z.string().url().optional(),\n\n /** Author area at view time (resolved server-side). Hidden when\n * privacy is `private` and the viewer is not the owner. */\n localName: z.string().optional(),\n\n /** Privacy of THIS profile (not the viewer's). Useful for the UI\n * to render a lock chip when the profile is private. */\n privacy: profilePrivacySchema,\n\n /** Short bio — present only when set by the user. */\n bio: z.string().max(PROFILE_MAX_BIO_CHARS).optional(),\n\n /** Engagement counters. Hidden on private profiles when the viewer is\n * not the owner. Three-tuple post-redesign: connections went away\n * when the connection-request feature was removed in v0.9.0. */\n counters: z\n .object({\n postCount: z.number().int().nonnegative(),\n followerCount: z.number().int().nonnegative(),\n followingCount: z.number().int().nonnegative(),\n })\n .optional(),\n\n /** Mutual followees between the viewer and the profile owner. Renders\n * the \"Followed by X, Y + N more\" line. Omitted for self-view (no\n * point telling you about yourself) and when the viewer has no\n * mutuals with the owner. */\n mutuals: profileMutualsSchema.optional(),\n\n /** Per-viewer relationship state. Always present (never gated). */\n viewer: viewerSocialStateSchema,\n});\nexport type PublicProfileWire = z.infer<typeof publicProfileWireSchema>;\n\n// ─── People list ────────────────────────────────────────────────────────────\n\n/**\n * Lightweight row used in the People tab list. Fewer fields than the\n * full profile to keep the list response small.\n */\nexport const peopleListItemSchema = z.object({\n userId: z.string(),\n /** Public URL handle (see `publicProfileWireSchema.username`). Always\n * present — the row's display + tap-to-profile link both depend on it. */\n username: usernameSchema,\n displayName: z.string(),\n avatarUrl: z.string().url().optional(),\n localName: z.string().optional(),\n privacy: profilePrivacySchema,\n viewer: viewerSocialStateSchema,\n});\nexport type PeopleListItem = z.infer<typeof peopleListItemSchema>;\n\nexport const peopleQueryParamsSchema = z.object({\n /** Free-text search across `displayName`. */\n q: z.string().optional(),\n /** Area-scope filter. When set, server filters to users whose primary\n * area lineage matches the viewer's lineage at the chosen level. */\n level: visibilityLevelSchema.optional(),\n cursor: z.string().optional(),\n pageSize: z.number().int().positive().max(50).optional(),\n});\nexport type PeopleQueryParams = z.infer<typeof peopleQueryParamsSchema>;\n\nexport const peopleListResponseSchema = z.object({\n items: z.array(peopleListItemSchema),\n nextCursor: z.string().nullable(),\n});\nexport type PeopleListResponse = z.infer<typeof peopleListResponseSchema>;\n"]}
|
package/dist/repost.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ export declare const createRepostResponseSchema: z.ZodObject<{
|
|
|
41
41
|
contentKind: z.ZodLiteral<"post">;
|
|
42
42
|
author: z.ZodObject<{
|
|
43
43
|
userId: z.ZodString;
|
|
44
|
+
username: z.ZodString;
|
|
44
45
|
displayName: z.ZodString;
|
|
45
46
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
46
47
|
localName: z.ZodOptional<z.ZodString>;
|
|
@@ -84,6 +85,7 @@ export declare const createRepostResponseSchema: z.ZodObject<{
|
|
|
84
85
|
_id: z.ZodString;
|
|
85
86
|
author: z.ZodObject<{
|
|
86
87
|
userId: z.ZodString;
|
|
88
|
+
username: z.ZodString;
|
|
87
89
|
displayName: z.ZodString;
|
|
88
90
|
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
89
91
|
localName: z.ZodOptional<z.ZodString>;
|
package/dist/repost.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repost.d.ts","sourceRoot":"","sources":["../src/repost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;iBASjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,0BAA0B
|
|
1
|
+
{"version":3,"file":"repost.d.ts","sourceRoot":"","sources":["../src/repost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;iBASjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAErC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Username — the public URL handle every user has.
|
|
3
|
+
*
|
|
4
|
+
* The redesign moved profile URLs from `/community/profile/<userId>` to
|
|
5
|
+
* `/<username>`. The username is the single piece of user data the URL
|
|
6
|
+
* needs to encode, so it lives at the top level of the community wire
|
|
7
|
+
* surface (PublicProfileWire, PeopleListItem, PostAuthorSnapshot).
|
|
8
|
+
*
|
|
9
|
+
* Format contract (enforced everywhere — Zod + Mongoose + Settings UI)
|
|
10
|
+
* ===================================================================
|
|
11
|
+
*
|
|
12
|
+
* - **Alphabet**: lowercase ASCII letters, digits, underscore.
|
|
13
|
+
* - **First character**: must be a letter (`a–z`). Prevents handles
|
|
14
|
+
* that read like an internal sentinel (`_admin`, `123abc`).
|
|
15
|
+
* - **Length**: 3–30 characters. Three is short enough for "ali" but
|
|
16
|
+
* long enough that "ab" feels like a typo; 30 is generous for any
|
|
17
|
+
* real name and matches the typical SaaS cap.
|
|
18
|
+
* - **Case**: the canonical form is lowercase. Lookups MUST lowercase
|
|
19
|
+
* before comparison; URL hits that arrive with mixed case 308 to
|
|
20
|
+
* the lowercase canonical at the frontend route boundary.
|
|
21
|
+
*
|
|
22
|
+
* Reserved names
|
|
23
|
+
* ==============
|
|
24
|
+
*
|
|
25
|
+
* The frontend reserves every top-level route segment (`community`,
|
|
26
|
+
* `me`, `dummy`, `chat`, `find-partner`, `search`, `api`, `auth`,
|
|
27
|
+
* `login`, `register`, `settings`, `notifications`, …) plus the bot /
|
|
28
|
+
* SEO file paths (`robots.txt`, `sitemap.xml`, `favicon.ico`). The
|
|
29
|
+
* canonical list lives in `reform-backend/src/services/community/lib/
|
|
30
|
+
* reserved-usernames.ts` so a single source of truth gates both the
|
|
31
|
+
* PATCH endpoint and the auto-mint collision check.
|
|
32
|
+
*
|
|
33
|
+
* Change semantics
|
|
34
|
+
* ================
|
|
35
|
+
*
|
|
36
|
+
* - 14-day cooldown after a successful change (`usernameChangedAt`).
|
|
37
|
+
* - The just-vacated handle is held in a `UsernameReservation` row
|
|
38
|
+
* for 90 days, claimable only by its previous owner during that
|
|
39
|
+
* window. After 90 days the row TTL-expires and the handle becomes
|
|
40
|
+
* publicly available again.
|
|
41
|
+
*
|
|
42
|
+
* @module community-schema/username
|
|
43
|
+
*/
|
|
44
|
+
import { z } from 'zod';
|
|
45
|
+
/** The format regex. Used directly by the Zod schema and re-exported
|
|
46
|
+
* so backend / form helpers can run cheap pre-flight checks without a
|
|
47
|
+
* full parse. */
|
|
48
|
+
export declare const USERNAME_PATTERN: RegExp;
|
|
49
|
+
export declare const USERNAME_MIN_LENGTH = 3;
|
|
50
|
+
export declare const USERNAME_MAX_LENGTH = 30;
|
|
51
|
+
export declare const usernameSchema: z.ZodString;
|
|
52
|
+
export type Username = z.infer<typeof usernameSchema>;
|
|
53
|
+
/** Body for `PATCH /api/v1/community/settings/username`. */
|
|
54
|
+
export declare const updateUsernameBodySchema: z.ZodObject<{
|
|
55
|
+
username: z.ZodString;
|
|
56
|
+
}, z.core.$strip>;
|
|
57
|
+
export type UpdateUsernameBody = z.infer<typeof updateUsernameBodySchema>;
|
|
58
|
+
/**
|
|
59
|
+
* Response after a successful username change.
|
|
60
|
+
*
|
|
61
|
+
* Carries the freshly-set username and the next allowed change moment
|
|
62
|
+
* (cooldownUntil) so the UI can render a "you can change again in N
|
|
63
|
+
* days" disclosure without a follow-up read.
|
|
64
|
+
*/
|
|
65
|
+
export declare const updateUsernameResponseSchema: z.ZodObject<{
|
|
66
|
+
username: z.ZodString;
|
|
67
|
+
cooldownUntil: z.ZodNullable<z.ZodString>;
|
|
68
|
+
}, z.core.$strip>;
|
|
69
|
+
export type UpdateUsernameResponse = z.infer<typeof updateUsernameResponseSchema>;
|
|
70
|
+
/**
|
|
71
|
+
* Reasons a candidate username can be rejected. The composer surfaces a
|
|
72
|
+
* different error string per reason so the user knows whether to pick
|
|
73
|
+
* something else (`taken` / `reserved` / `cooldown`) or to fix the
|
|
74
|
+
* candidate itself (`format`).
|
|
75
|
+
*
|
|
76
|
+
* - `format` — fails the regex / length / first-letter check.
|
|
77
|
+
* - `reserved` — matches a frontend route or the bot/SEO file list.
|
|
78
|
+
* - `taken` — already the active username of another user.
|
|
79
|
+
* - `cooldown` — held in the 90-day reservation window for someone
|
|
80
|
+
* else.
|
|
81
|
+
* - `self` — the candidate is the caller's current username.
|
|
82
|
+
* Returned as a non-blocking signal so the composer
|
|
83
|
+
* can render "this is your current handle" instead of
|
|
84
|
+
* the generic "taken".
|
|
85
|
+
*/
|
|
86
|
+
export declare const USERNAME_UNAVAILABLE_REASONS: readonly ["format", "reserved", "taken", "cooldown", "self"];
|
|
87
|
+
export declare const usernameUnavailableReasonSchema: z.ZodEnum<{
|
|
88
|
+
format: "format";
|
|
89
|
+
reserved: "reserved";
|
|
90
|
+
taken: "taken";
|
|
91
|
+
cooldown: "cooldown";
|
|
92
|
+
self: "self";
|
|
93
|
+
}>;
|
|
94
|
+
export type UsernameUnavailableReason = z.infer<typeof usernameUnavailableReasonSchema>;
|
|
95
|
+
/**
|
|
96
|
+
* Response for `GET /api/v1/community/settings/username/availability?candidate=...`.
|
|
97
|
+
* The caller debounces the keystroke and treats `available: true` as the
|
|
98
|
+
* green flag for the submit button.
|
|
99
|
+
*/
|
|
100
|
+
export declare const usernameAvailabilityResponseSchema: z.ZodObject<{
|
|
101
|
+
candidate: z.ZodString;
|
|
102
|
+
available: z.ZodBoolean;
|
|
103
|
+
reason: z.ZodOptional<z.ZodEnum<{
|
|
104
|
+
format: "format";
|
|
105
|
+
reserved: "reserved";
|
|
106
|
+
taken: "taken";
|
|
107
|
+
cooldown: "cooldown";
|
|
108
|
+
self: "self";
|
|
109
|
+
}>>;
|
|
110
|
+
}, z.core.$strip>;
|
|
111
|
+
export type UsernameAvailabilityResponse = z.infer<typeof usernameAvailabilityResponseSchema>;
|
|
112
|
+
/**
|
|
113
|
+
* Returned by `GET /api/v1/community/settings/username` so the Settings
|
|
114
|
+
* page can render the editor with the current handle + the cooldown
|
|
115
|
+
* state without a separate availability ping.
|
|
116
|
+
*/
|
|
117
|
+
export declare const currentUsernameStateSchema: z.ZodObject<{
|
|
118
|
+
username: z.ZodString;
|
|
119
|
+
lastChangedAt: z.ZodNullable<z.ZodString>;
|
|
120
|
+
cooldownUntil: z.ZodNullable<z.ZodString>;
|
|
121
|
+
}, z.core.$strip>;
|
|
122
|
+
export type CurrentUsernameState = z.infer<typeof currentUsernameStateSchema>;
|
|
123
|
+
//# sourceMappingURL=username.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"username.d.ts","sourceRoot":"","sources":["../src/username.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;kBAEkB;AAClB,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,eAAO,MAAM,cAAc,aAOxB,CAAC;AACJ,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAItD,4DAA4D;AAC5D,eAAO,MAAM,wBAAwB;;iBAEnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B;;;iBAKvC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAIlF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,8DAM/B,CAAC;AACX,eAAO,MAAM,+BAA+B;;;;;;EAAuC,CAAC;AACpF,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAExF;;;;GAIG;AACH,eAAO,MAAM,kCAAkC;;;;;;;;;;iBAM7C,CAAC;AACH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAI9F;;;;GAIG;AACH,eAAO,MAAM,0BAA0B;;;;iBAQrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
|
package/dist/username.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Username — the public URL handle every user has.
|
|
3
|
+
*
|
|
4
|
+
* The redesign moved profile URLs from `/community/profile/<userId>` to
|
|
5
|
+
* `/<username>`. The username is the single piece of user data the URL
|
|
6
|
+
* needs to encode, so it lives at the top level of the community wire
|
|
7
|
+
* surface (PublicProfileWire, PeopleListItem, PostAuthorSnapshot).
|
|
8
|
+
*
|
|
9
|
+
* Format contract (enforced everywhere — Zod + Mongoose + Settings UI)
|
|
10
|
+
* ===================================================================
|
|
11
|
+
*
|
|
12
|
+
* - **Alphabet**: lowercase ASCII letters, digits, underscore.
|
|
13
|
+
* - **First character**: must be a letter (`a–z`). Prevents handles
|
|
14
|
+
* that read like an internal sentinel (`_admin`, `123abc`).
|
|
15
|
+
* - **Length**: 3–30 characters. Three is short enough for "ali" but
|
|
16
|
+
* long enough that "ab" feels like a typo; 30 is generous for any
|
|
17
|
+
* real name and matches the typical SaaS cap.
|
|
18
|
+
* - **Case**: the canonical form is lowercase. Lookups MUST lowercase
|
|
19
|
+
* before comparison; URL hits that arrive with mixed case 308 to
|
|
20
|
+
* the lowercase canonical at the frontend route boundary.
|
|
21
|
+
*
|
|
22
|
+
* Reserved names
|
|
23
|
+
* ==============
|
|
24
|
+
*
|
|
25
|
+
* The frontend reserves every top-level route segment (`community`,
|
|
26
|
+
* `me`, `dummy`, `chat`, `find-partner`, `search`, `api`, `auth`,
|
|
27
|
+
* `login`, `register`, `settings`, `notifications`, …) plus the bot /
|
|
28
|
+
* SEO file paths (`robots.txt`, `sitemap.xml`, `favicon.ico`). The
|
|
29
|
+
* canonical list lives in `reform-backend/src/services/community/lib/
|
|
30
|
+
* reserved-usernames.ts` so a single source of truth gates both the
|
|
31
|
+
* PATCH endpoint and the auto-mint collision check.
|
|
32
|
+
*
|
|
33
|
+
* Change semantics
|
|
34
|
+
* ================
|
|
35
|
+
*
|
|
36
|
+
* - 14-day cooldown after a successful change (`usernameChangedAt`).
|
|
37
|
+
* - The just-vacated handle is held in a `UsernameReservation` row
|
|
38
|
+
* for 90 days, claimable only by its previous owner during that
|
|
39
|
+
* window. After 90 days the row TTL-expires and the handle becomes
|
|
40
|
+
* publicly available again.
|
|
41
|
+
*
|
|
42
|
+
* @module community-schema/username
|
|
43
|
+
*/
|
|
44
|
+
import { z } from 'zod';
|
|
45
|
+
/** The format regex. Used directly by the Zod schema and re-exported
|
|
46
|
+
* so backend / form helpers can run cheap pre-flight checks without a
|
|
47
|
+
* full parse. */
|
|
48
|
+
export const USERNAME_PATTERN = /^[a-z][a-z0-9_]{2,29}$/;
|
|
49
|
+
export const USERNAME_MIN_LENGTH = 3;
|
|
50
|
+
export const USERNAME_MAX_LENGTH = 30;
|
|
51
|
+
export const usernameSchema = z
|
|
52
|
+
.string()
|
|
53
|
+
.min(USERNAME_MIN_LENGTH)
|
|
54
|
+
.max(USERNAME_MAX_LENGTH)
|
|
55
|
+
.regex(USERNAME_PATTERN, 'Usernames use only lowercase letters, digits, and underscore. They must start with a letter.');
|
|
56
|
+
// ─── Change ────────────────────────────────────────────────────────────────
|
|
57
|
+
/** Body for `PATCH /api/v1/community/settings/username`. */
|
|
58
|
+
export const updateUsernameBodySchema = z.object({
|
|
59
|
+
username: usernameSchema,
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* Response after a successful username change.
|
|
63
|
+
*
|
|
64
|
+
* Carries the freshly-set username and the next allowed change moment
|
|
65
|
+
* (cooldownUntil) so the UI can render a "you can change again in N
|
|
66
|
+
* days" disclosure without a follow-up read.
|
|
67
|
+
*/
|
|
68
|
+
export const updateUsernameResponseSchema = z.object({
|
|
69
|
+
username: usernameSchema,
|
|
70
|
+
/** ISO timestamp. Null when there's no cooldown active (i.e. this is
|
|
71
|
+
* the user's first set, or the cooldown has already elapsed). */
|
|
72
|
+
cooldownUntil: z.string().datetime().nullable(),
|
|
73
|
+
});
|
|
74
|
+
// ─── Availability check ───────────────────────────────────────────────────
|
|
75
|
+
/**
|
|
76
|
+
* Reasons a candidate username can be rejected. The composer surfaces a
|
|
77
|
+
* different error string per reason so the user knows whether to pick
|
|
78
|
+
* something else (`taken` / `reserved` / `cooldown`) or to fix the
|
|
79
|
+
* candidate itself (`format`).
|
|
80
|
+
*
|
|
81
|
+
* - `format` — fails the regex / length / first-letter check.
|
|
82
|
+
* - `reserved` — matches a frontend route or the bot/SEO file list.
|
|
83
|
+
* - `taken` — already the active username of another user.
|
|
84
|
+
* - `cooldown` — held in the 90-day reservation window for someone
|
|
85
|
+
* else.
|
|
86
|
+
* - `self` — the candidate is the caller's current username.
|
|
87
|
+
* Returned as a non-blocking signal so the composer
|
|
88
|
+
* can render "this is your current handle" instead of
|
|
89
|
+
* the generic "taken".
|
|
90
|
+
*/
|
|
91
|
+
export const USERNAME_UNAVAILABLE_REASONS = [
|
|
92
|
+
'format',
|
|
93
|
+
'reserved',
|
|
94
|
+
'taken',
|
|
95
|
+
'cooldown',
|
|
96
|
+
'self',
|
|
97
|
+
];
|
|
98
|
+
export const usernameUnavailableReasonSchema = z.enum(USERNAME_UNAVAILABLE_REASONS);
|
|
99
|
+
/**
|
|
100
|
+
* Response for `GET /api/v1/community/settings/username/availability?candidate=...`.
|
|
101
|
+
* The caller debounces the keystroke and treats `available: true` as the
|
|
102
|
+
* green flag for the submit button.
|
|
103
|
+
*/
|
|
104
|
+
export const usernameAvailabilityResponseSchema = z.object({
|
|
105
|
+
candidate: z.string(),
|
|
106
|
+
available: z.boolean(),
|
|
107
|
+
/** Present only when `available` is false (or when the reason is
|
|
108
|
+
* `self` — surfaced as a soft, non-blocking signal). */
|
|
109
|
+
reason: usernameUnavailableReasonSchema.optional(),
|
|
110
|
+
});
|
|
111
|
+
// ─── Cooldown view (read on Settings load) ────────────────────────────────
|
|
112
|
+
/**
|
|
113
|
+
* Returned by `GET /api/v1/community/settings/username` so the Settings
|
|
114
|
+
* page can render the editor with the current handle + the cooldown
|
|
115
|
+
* state without a separate availability ping.
|
|
116
|
+
*/
|
|
117
|
+
export const currentUsernameStateSchema = z.object({
|
|
118
|
+
username: usernameSchema,
|
|
119
|
+
/** ISO timestamp of the most recent change. Null when the username
|
|
120
|
+
* has never been changed (it was auto-minted at provisioning). */
|
|
121
|
+
lastChangedAt: z.string().datetime().nullable(),
|
|
122
|
+
/** ISO timestamp the user can next change. Null when no cooldown is
|
|
123
|
+
* currently in effect. */
|
|
124
|
+
cooldownUntil: z.string().datetime().nullable(),
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=username.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"username.js","sourceRoot":"","sources":["../src/username.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;kBAEkB;AAClB,MAAM,CAAC,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;AAEzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC;KAC5B,MAAM,EAAE;KACR,GAAG,CAAC,mBAAmB,CAAC;KACxB,GAAG,CAAC,mBAAmB,CAAC;KACxB,KAAK,CACJ,gBAAgB,EAChB,8FAA8F,CAC/F,CAAC;AAGJ,8EAA8E;AAE9E,4DAA4D;AAC5D,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,QAAQ,EAAE,cAAc;CACzB,CAAC,CAAC;AAGH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,QAAQ,EAAE,cAAc;IACxB;sEACkE;IAClE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CAChD,CAAC,CAAC;AAGH,6EAA6E;AAE7E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,QAAQ;IACR,UAAU;IACV,OAAO;IACP,UAAU;IACV,MAAM;CACE,CAAC;AACX,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;AAGpF;;;;GAIG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,CAAC,MAAM,CAAC;IACzD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;IACtB;6DACyD;IACzD,MAAM,EAAE,+BAA+B,CAAC,QAAQ,EAAE;CACnD,CAAC,CAAC;AAGH,6EAA6E;AAE7E;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,QAAQ,EAAE,cAAc;IACxB;uEACmE;IACnE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC/C;+BAC2B;IAC3B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CAChD,CAAC,CAAC","sourcesContent":["/**\n * Username — the public URL handle every user has.\n *\n * The redesign moved profile URLs from `/community/profile/<userId>` to\n * `/<username>`. The username is the single piece of user data the URL\n * needs to encode, so it lives at the top level of the community wire\n * surface (PublicProfileWire, PeopleListItem, PostAuthorSnapshot).\n *\n * Format contract (enforced everywhere — Zod + Mongoose + Settings UI)\n * ===================================================================\n *\n * - **Alphabet**: lowercase ASCII letters, digits, underscore.\n * - **First character**: must be a letter (`a–z`). Prevents handles\n * that read like an internal sentinel (`_admin`, `123abc`).\n * - **Length**: 3–30 characters. Three is short enough for \"ali\" but\n * long enough that \"ab\" feels like a typo; 30 is generous for any\n * real name and matches the typical SaaS cap.\n * - **Case**: the canonical form is lowercase. Lookups MUST lowercase\n * before comparison; URL hits that arrive with mixed case 308 to\n * the lowercase canonical at the frontend route boundary.\n *\n * Reserved names\n * ==============\n *\n * The frontend reserves every top-level route segment (`community`,\n * `me`, `dummy`, `chat`, `find-partner`, `search`, `api`, `auth`,\n * `login`, `register`, `settings`, `notifications`, …) plus the bot /\n * SEO file paths (`robots.txt`, `sitemap.xml`, `favicon.ico`). The\n * canonical list lives in `reform-backend/src/services/community/lib/\n * reserved-usernames.ts` so a single source of truth gates both the\n * PATCH endpoint and the auto-mint collision check.\n *\n * Change semantics\n * ================\n *\n * - 14-day cooldown after a successful change (`usernameChangedAt`).\n * - The just-vacated handle is held in a `UsernameReservation` row\n * for 90 days, claimable only by its previous owner during that\n * window. After 90 days the row TTL-expires and the handle becomes\n * publicly available again.\n *\n * @module community-schema/username\n */\n\nimport { z } from 'zod';\n\n/** The format regex. Used directly by the Zod schema and re-exported\n * so backend / form helpers can run cheap pre-flight checks without a\n * full parse. */\nexport const USERNAME_PATTERN = /^[a-z][a-z0-9_]{2,29}$/;\n\nexport const USERNAME_MIN_LENGTH = 3;\nexport const USERNAME_MAX_LENGTH = 30;\n\nexport const usernameSchema = z\n .string()\n .min(USERNAME_MIN_LENGTH)\n .max(USERNAME_MAX_LENGTH)\n .regex(\n USERNAME_PATTERN,\n 'Usernames use only lowercase letters, digits, and underscore. They must start with a letter.',\n );\nexport type Username = z.infer<typeof usernameSchema>;\n\n// ─── Change ────────────────────────────────────────────────────────────────\n\n/** Body for `PATCH /api/v1/community/settings/username`. */\nexport const updateUsernameBodySchema = z.object({\n username: usernameSchema,\n});\nexport type UpdateUsernameBody = z.infer<typeof updateUsernameBodySchema>;\n\n/**\n * Response after a successful username change.\n *\n * Carries the freshly-set username and the next allowed change moment\n * (cooldownUntil) so the UI can render a \"you can change again in N\n * days\" disclosure without a follow-up read.\n */\nexport const updateUsernameResponseSchema = z.object({\n username: usernameSchema,\n /** ISO timestamp. Null when there's no cooldown active (i.e. this is\n * the user's first set, or the cooldown has already elapsed). */\n cooldownUntil: z.string().datetime().nullable(),\n});\nexport type UpdateUsernameResponse = z.infer<typeof updateUsernameResponseSchema>;\n\n// ─── Availability check ───────────────────────────────────────────────────\n\n/**\n * Reasons a candidate username can be rejected. The composer surfaces a\n * different error string per reason so the user knows whether to pick\n * something else (`taken` / `reserved` / `cooldown`) or to fix the\n * candidate itself (`format`).\n *\n * - `format` — fails the regex / length / first-letter check.\n * - `reserved` — matches a frontend route or the bot/SEO file list.\n * - `taken` — already the active username of another user.\n * - `cooldown` — held in the 90-day reservation window for someone\n * else.\n * - `self` — the candidate is the caller's current username.\n * Returned as a non-blocking signal so the composer\n * can render \"this is your current handle\" instead of\n * the generic \"taken\".\n */\nexport const USERNAME_UNAVAILABLE_REASONS = [\n 'format',\n 'reserved',\n 'taken',\n 'cooldown',\n 'self',\n] as const;\nexport const usernameUnavailableReasonSchema = z.enum(USERNAME_UNAVAILABLE_REASONS);\nexport type UsernameUnavailableReason = z.infer<typeof usernameUnavailableReasonSchema>;\n\n/**\n * Response for `GET /api/v1/community/settings/username/availability?candidate=...`.\n * The caller debounces the keystroke and treats `available: true` as the\n * green flag for the submit button.\n */\nexport const usernameAvailabilityResponseSchema = z.object({\n candidate: z.string(),\n available: z.boolean(),\n /** Present only when `available` is false (or when the reason is\n * `self` — surfaced as a soft, non-blocking signal). */\n reason: usernameUnavailableReasonSchema.optional(),\n});\nexport type UsernameAvailabilityResponse = z.infer<typeof usernameAvailabilityResponseSchema>;\n\n// ─── Cooldown view (read on Settings load) ────────────────────────────────\n\n/**\n * Returned by `GET /api/v1/community/settings/username` so the Settings\n * page can render the editor with the current handle + the cooldown\n * state without a separate availability ping.\n */\nexport const currentUsernameStateSchema = z.object({\n username: usernameSchema,\n /** ISO timestamp of the most recent change. Null when the username\n * has never been changed (it was auto-minted at provisioning). */\n lastChangedAt: z.string().datetime().nullable(),\n /** ISO timestamp the user can next change. Null when no cooldown is\n * currently in effect. */\n cooldownUntil: z.string().datetime().nullable(),\n});\nexport type CurrentUsernameState = z.infer<typeof currentUsernameStateSchema>;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jansathi-community-schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Shared Zod schemas + TypeScript types for the Jansathi hyperlocal community feature (feed, posts, engagement, social graph, groups, communities).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|