jansathi-community-schema 0.1.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.
Files changed (58) hide show
  1. package/README.md +41 -0
  2. package/dist/area.d.ts +37 -0
  3. package/dist/area.d.ts.map +1 -0
  4. package/dist/area.js +51 -0
  5. package/dist/area.js.map +1 -0
  6. package/dist/comment.d.ts +54 -0
  7. package/dist/comment.d.ts.map +1 -0
  8. package/dist/comment.js +63 -0
  9. package/dist/comment.js.map +1 -0
  10. package/dist/constants.d.ts +42 -0
  11. package/dist/constants.d.ts.map +1 -0
  12. package/dist/constants.js +47 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/engagement.d.ts +69 -0
  15. package/dist/engagement.d.ts.map +1 -0
  16. package/dist/engagement.js +50 -0
  17. package/dist/engagement.js.map +1 -0
  18. package/dist/enums.d.ts +149 -0
  19. package/dist/enums.d.ts.map +1 -0
  20. package/dist/enums.js +143 -0
  21. package/dist/enums.js.map +1 -0
  22. package/dist/feed.d.ts +311 -0
  23. package/dist/feed.d.ts.map +1 -0
  24. package/dist/feed.js +102 -0
  25. package/dist/feed.js.map +1 -0
  26. package/dist/group.d.ts +48 -0
  27. package/dist/group.d.ts.map +1 -0
  28. package/dist/group.js +45 -0
  29. package/dist/group.js.map +1 -0
  30. package/dist/index.d.ts +30 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +43 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/media.d.ts +48 -0
  35. package/dist/media.d.ts.map +1 -0
  36. package/dist/media.js +50 -0
  37. package/dist/media.js.map +1 -0
  38. package/dist/post.d.ts +130 -0
  39. package/dist/post.d.ts.map +1 -0
  40. package/dist/post.js +103 -0
  41. package/dist/post.js.map +1 -0
  42. package/dist/profile.d.ts +116 -0
  43. package/dist/profile.d.ts.map +1 -0
  44. package/dist/profile.js +70 -0
  45. package/dist/profile.js.map +1 -0
  46. package/dist/report.d.ts +62 -0
  47. package/dist/report.d.ts.map +1 -0
  48. package/dist/report.js +30 -0
  49. package/dist/report.js.map +1 -0
  50. package/dist/settings.d.ts +66 -0
  51. package/dist/settings.d.ts.map +1 -0
  52. package/dist/settings.js +75 -0
  53. package/dist/settings.js.map +1 -0
  54. package/dist/social.d.ts +95 -0
  55. package/dist/social.d.ts.map +1 -0
  56. package/dist/social.js +85 -0
  57. package/dist/social.js.map +1 -0
  58. package/package.json +50 -0
package/dist/post.js ADDED
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Community post wire shapes.
3
+ *
4
+ * A "post" is the native community content kind (text-primary + media).
5
+ * Lost-and-found and voice-box items show up in the same feed via
6
+ * polymorphic union; their shapes live in their own schema packages
7
+ * and are projected into a `FeedItem` envelope (see `./feed.ts`).
8
+ *
9
+ * @module community-schema/post
10
+ */
11
+ import { z } from 'zod';
12
+ import { areaLineageSnapshotSchema } from './area.js';
13
+ import { POST_MAX_BODY_CHARS, POST_MAX_IMAGES, POST_MAX_VIDEOS, } from './constants.js';
14
+ import { postImageSchema, postVideoSchema } from './media.js';
15
+ import { visibilityLevelSchema } from './enums.js';
16
+ // ─── Author snapshot (denormalised on every post) ──────────────────────────
17
+ /**
18
+ * The author's display info captured at post time. Denormalising
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.
22
+ *
23
+ * The User document remains the source of truth; a background job
24
+ * (or a hook on User.findOneAndUpdate) refreshes recent posts when
25
+ * a user changes their display name or avatar.
26
+ */
27
+ export const postAuthorSnapshotSchema = z.object({
28
+ userId: z.string(),
29
+ displayName: z.string(),
30
+ avatarUrl: z.string().url().optional(),
31
+ /**
32
+ * The author's "local" area label at post time, e.g. "Rohini Sector 15".
33
+ * Powers the byline "<DisplayName> · <localName> · <relativeTime>".
34
+ * Hidden when the author has a private profile and the viewer is
35
+ * not an accepted Connection.
36
+ */
37
+ localName: z.string().optional(),
38
+ });
39
+ // ─── Wire shape — what the server returns ──────────────────────────────────
40
+ /**
41
+ * A community post as it appears in the feed and on the single-post
42
+ * page. Engagement counts are denormalised onto the document for
43
+ * fast feed sorting; the per-user reaction state ("did I upvote this?")
44
+ * is computed at read time and returned in the `viewer` block.
45
+ */
46
+ export const communityPostWireSchema = z.object({
47
+ _id: z.string(),
48
+ contentKind: z.literal('post'),
49
+ author: postAuthorSnapshotSchema,
50
+ // Body
51
+ text: z.string().max(POST_MAX_BODY_CHARS),
52
+ images: z.array(postImageSchema).max(POST_MAX_IMAGES),
53
+ videos: z.array(postVideoSchema).max(POST_MAX_VIDEOS),
54
+ // Audience
55
+ visibilityLevel: visibilityLevelSchema,
56
+ areaLineage: areaLineageSnapshotSchema,
57
+ // Denormalised engagement counters (drive feed sort + card render)
58
+ upvoteCount: z.number().int().nonnegative(),
59
+ commentCount: z.number().int().nonnegative(),
60
+ /** Map of `ReactionType` → count, e.g. { like: 4, love: 1 }. */
61
+ reactionCounts: z.record(z.string(), z.number().int().nonnegative()),
62
+ // Lifecycle
63
+ createdAt: z.string().datetime(),
64
+ /** Last edit timestamp, or null if never edited. Edit window is
65
+ * enforced by the server at write time, not by this schema. */
66
+ editedAt: z.string().datetime().nullable(),
67
+ deletedAt: z.string().datetime().nullable(),
68
+ // Per-viewer state (filled by the server at read time)
69
+ viewer: z
70
+ .object({
71
+ upvoted: z.boolean(),
72
+ /** The reaction the viewer chose, or null. Mutually exclusive
73
+ * with `upvoted` is intentionally NOT enforced — they're two
74
+ * separate axes per the product decision. */
75
+ reaction: z.string().nullable(),
76
+ /** True when the viewer authored the post (controls edit / delete buttons). */
77
+ isAuthor: z.boolean(),
78
+ })
79
+ .optional(),
80
+ });
81
+ // ─── Create / update bodies ────────────────────────────────────────────────
82
+ /**
83
+ * What the client sends to `POST /api/v1/community/posts`. The author
84
+ * is taken from the authenticated request; visibility area is resolved
85
+ * server-side from the user's primary area lineage (the client cannot
86
+ * spoof a different area).
87
+ */
88
+ export const createPostBodySchema = z.object({
89
+ text: z.string().min(1).max(POST_MAX_BODY_CHARS),
90
+ images: z.array(postImageSchema).max(POST_MAX_IMAGES).optional(),
91
+ videos: z.array(postVideoSchema).max(POST_MAX_VIDEOS).optional(),
92
+ /** Default chosen by the client is `local`; the server still validates. */
93
+ visibilityLevel: visibilityLevelSchema,
94
+ });
95
+ /**
96
+ * What the client sends to `PATCH /api/v1/community/posts/:id`. Only
97
+ * the text body is editable — media additions / removals require a new
98
+ * post (matches Twitter / FB convention).
99
+ */
100
+ export const updatePostBodySchema = z.object({
101
+ text: z.string().min(1).max(POST_MAX_BODY_CHARS),
102
+ });
103
+ //# sourceMappingURL=post.js.map
@@ -0,0 +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 {\n POST_MAX_BODY_CHARS,\n POST_MAX_IMAGES,\n POST_MAX_VIDEOS,\n} from './constants.js';\nimport { postImageSchema, postVideoSchema } from './media.js';\nimport { visibilityLevelSchema } from './enums.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// ─── 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\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 // Audience\n visibilityLevel: visibilityLevelSchema,\n areaLineage: areaLineageSnapshotSchema,\n\n // Denormalised engagement counters (drive feed sort + card render)\n upvoteCount: z.number().int().nonnegative(),\n commentCount: 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 // 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 })\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; visibility area is resolved\n * server-side from the user's primary area lineage (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 /** Default chosen by the client is `local`; the server still validates. */\n visibilityLevel: visibilityLevelSchema,\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"]}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Public community-profile wire shape.
3
+ *
4
+ * What every viewer can see about another user's community presence.
5
+ * Differs from the auth/UDP `User` shape — this view is purposely thin
6
+ * and content-engagement-oriented (post count, follower count, …).
7
+ *
8
+ * Privacy gating:
9
+ * - `public` profile: the full shape is returned to any signed-in viewer.
10
+ * - `private` profile: only `userId`, `displayName`, `avatarUrl`, and
11
+ * the viewer's social state are returned to non-Connections. Posts
12
+ * and counters are hidden until a Connection is accepted.
13
+ *
14
+ * @module community-schema/profile
15
+ */
16
+ import { z } from 'zod';
17
+ export declare const publicProfileWireSchema: z.ZodObject<{
18
+ userId: z.ZodString;
19
+ displayName: z.ZodString;
20
+ avatarUrl: z.ZodOptional<z.ZodString>;
21
+ localName: z.ZodOptional<z.ZodString>;
22
+ privacy: z.ZodEnum<{
23
+ public: "public";
24
+ private: "private";
25
+ }>;
26
+ bio: z.ZodOptional<z.ZodString>;
27
+ counters: z.ZodOptional<z.ZodObject<{
28
+ postCount: z.ZodNumber;
29
+ followerCount: z.ZodNumber;
30
+ followingCount: z.ZodNumber;
31
+ connectionCount: z.ZodNumber;
32
+ }, z.core.$strip>>;
33
+ viewer: z.ZodObject<{
34
+ following: z.ZodBoolean;
35
+ connectionStatus: z.ZodNullable<z.ZodEnum<{
36
+ pending: "pending";
37
+ accepted: "accepted";
38
+ declined: "declined";
39
+ blocked: "blocked";
40
+ }>>;
41
+ pendingDirection: z.ZodNullable<z.ZodEnum<{
42
+ sent: "sent";
43
+ received: "received";
44
+ }>>;
45
+ }, z.core.$strip>;
46
+ }, z.core.$strip>;
47
+ export type PublicProfileWire = z.infer<typeof publicProfileWireSchema>;
48
+ /**
49
+ * Lightweight row used in the People tab list. Fewer fields than the
50
+ * full profile to keep the list response small.
51
+ */
52
+ export declare const peopleListItemSchema: z.ZodObject<{
53
+ userId: z.ZodString;
54
+ displayName: z.ZodString;
55
+ avatarUrl: z.ZodOptional<z.ZodString>;
56
+ localName: z.ZodOptional<z.ZodString>;
57
+ privacy: z.ZodEnum<{
58
+ public: "public";
59
+ private: "private";
60
+ }>;
61
+ viewer: z.ZodObject<{
62
+ following: z.ZodBoolean;
63
+ connectionStatus: z.ZodNullable<z.ZodEnum<{
64
+ pending: "pending";
65
+ accepted: "accepted";
66
+ declined: "declined";
67
+ blocked: "blocked";
68
+ }>>;
69
+ pendingDirection: z.ZodNullable<z.ZodEnum<{
70
+ sent: "sent";
71
+ received: "received";
72
+ }>>;
73
+ }, z.core.$strip>;
74
+ }, z.core.$strip>;
75
+ export type PeopleListItem = z.infer<typeof peopleListItemSchema>;
76
+ export declare const peopleQueryParamsSchema: z.ZodObject<{
77
+ q: z.ZodOptional<z.ZodString>;
78
+ level: z.ZodOptional<z.ZodEnum<{
79
+ local: "local";
80
+ district: "district";
81
+ state: "state";
82
+ national: "national";
83
+ global: "global";
84
+ }>>;
85
+ cursor: z.ZodOptional<z.ZodString>;
86
+ pageSize: z.ZodOptional<z.ZodNumber>;
87
+ }, z.core.$strip>;
88
+ export type PeopleQueryParams = z.infer<typeof peopleQueryParamsSchema>;
89
+ export declare const peopleListResponseSchema: z.ZodObject<{
90
+ items: z.ZodArray<z.ZodObject<{
91
+ userId: z.ZodString;
92
+ displayName: z.ZodString;
93
+ avatarUrl: z.ZodOptional<z.ZodString>;
94
+ localName: z.ZodOptional<z.ZodString>;
95
+ privacy: z.ZodEnum<{
96
+ public: "public";
97
+ private: "private";
98
+ }>;
99
+ viewer: z.ZodObject<{
100
+ following: z.ZodBoolean;
101
+ connectionStatus: z.ZodNullable<z.ZodEnum<{
102
+ pending: "pending";
103
+ accepted: "accepted";
104
+ declined: "declined";
105
+ blocked: "blocked";
106
+ }>>;
107
+ pendingDirection: z.ZodNullable<z.ZodEnum<{
108
+ sent: "sent";
109
+ received: "received";
110
+ }>>;
111
+ }, z.core.$strip>;
112
+ }, z.core.$strip>>;
113
+ nextCursor: z.ZodNullable<z.ZodString>;
114
+ }, z.core.$strip>;
115
+ export type PeopleListResponse = z.infer<typeof peopleListResponseSchema>;
116
+ //# sourceMappingURL=profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4BlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;iBAO/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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Public community-profile wire shape.
3
+ *
4
+ * What every viewer can see about another user's community presence.
5
+ * Differs from the auth/UDP `User` shape — this view is purposely thin
6
+ * and content-engagement-oriented (post count, follower count, …).
7
+ *
8
+ * Privacy gating:
9
+ * - `public` profile: the full shape is returned to any signed-in viewer.
10
+ * - `private` profile: only `userId`, `displayName`, `avatarUrl`, and
11
+ * the viewer's social state are returned to non-Connections. Posts
12
+ * and counters are hidden until a Connection is accepted.
13
+ *
14
+ * @module community-schema/profile
15
+ */
16
+ import { z } from 'zod';
17
+ import { PROFILE_MAX_BIO_CHARS } from './constants.js';
18
+ import { profilePrivacySchema, visibilityLevelSchema } from './enums.js';
19
+ import { viewerSocialStateSchema } from './social.js';
20
+ export const publicProfileWireSchema = z.object({
21
+ userId: z.string(),
22
+ displayName: z.string(),
23
+ avatarUrl: z.string().url().optional(),
24
+ /** Author area at view time (resolved server-side). Hidden when
25
+ * privacy is `private` and viewer is not a Connection. */
26
+ localName: z.string().optional(),
27
+ /** Privacy of THIS profile (not the viewer's). Useful for the UI
28
+ * to render a lock chip when the profile is private. */
29
+ privacy: profilePrivacySchema,
30
+ /** Short bio — present only when set by the user. */
31
+ bio: z.string().max(PROFILE_MAX_BIO_CHARS).optional(),
32
+ /** Engagement counters. Hidden on private profiles to non-Connections. */
33
+ counters: z
34
+ .object({
35
+ postCount: z.number().int().nonnegative(),
36
+ followerCount: z.number().int().nonnegative(),
37
+ followingCount: z.number().int().nonnegative(),
38
+ connectionCount: z.number().int().nonnegative(),
39
+ })
40
+ .optional(),
41
+ /** Per-viewer relationship state. Always present (never gated). */
42
+ viewer: viewerSocialStateSchema,
43
+ });
44
+ // ─── People list ────────────────────────────────────────────────────────────
45
+ /**
46
+ * Lightweight row used in the People tab list. Fewer fields than the
47
+ * full profile to keep the list response small.
48
+ */
49
+ export const peopleListItemSchema = z.object({
50
+ userId: z.string(),
51
+ displayName: z.string(),
52
+ avatarUrl: z.string().url().optional(),
53
+ localName: z.string().optional(),
54
+ privacy: profilePrivacySchema,
55
+ viewer: viewerSocialStateSchema,
56
+ });
57
+ export const peopleQueryParamsSchema = z.object({
58
+ /** Free-text search across `displayName`. */
59
+ q: z.string().optional(),
60
+ /** Area-scope filter. When set, server filters to users whose primary
61
+ * area lineage matches the viewer's lineage at the chosen level. */
62
+ level: visibilityLevelSchema.optional(),
63
+ cursor: z.string().optional(),
64
+ pageSize: z.number().int().positive().max(50).optional(),
65
+ });
66
+ export const peopleListResponseSchema = z.object({
67
+ items: z.array(peopleListItemSchema),
68
+ nextCursor: z.string().nullable(),
69
+ });
70
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;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;AAEtD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAEtC;+DAC2D;IAC3D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAEhC;6DACyD;IACzD,OAAO,EAAE,oBAAoB;IAE7B,qDAAqD;IACrD,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,QAAQ,EAAE;IAErD,0EAA0E;IAC1E,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC;QACN,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;QACzC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;QAC7C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;QAC9C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;KAChD,CAAC;SACD,QAAQ,EAAE;IAEb,mEAAmE;IACnE,MAAM,EAAE,uBAAuB;CAChC,CAAC,CAAC;AAGH,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACtC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,OAAO,EAAE,oBAAoB;IAC7B,MAAM,EAAE,uBAAuB;CAChC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,6CAA6C;IAC7C,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxB;yEACqE;IACrE,KAAK,EAAE,qBAAqB,CAAC,QAAQ,EAAE;IACvC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;CACzD,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;IACpC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC","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 social state are returned to non-Connections. Posts\n * and counters are hidden until a Connection is accepted.\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';\n\nexport const publicProfileWireSchema = z.object({\n userId: z.string(),\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 viewer is not a Connection. */\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 to non-Connections. */\n counters: z\n .object({\n postCount: z.number().int().nonnegative(),\n followerCount: z.number().int().nonnegative(),\n followingCount: z.number().int().nonnegative(),\n connectionCount: z.number().int().nonnegative(),\n })\n .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 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"]}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Content-reporting wire shapes for moderation.
3
+ *
4
+ * Any signed-in viewer can report any piece of community content
5
+ * (post / lost-found / voice-box / comment). Reports land in a
6
+ * moderation queue surfaced to admins; admin actions are out of scope
7
+ * for this schema package — the admin endpoints live elsewhere.
8
+ *
9
+ * @module community-schema/report
10
+ */
11
+ import { z } from 'zod';
12
+ export declare const reportContentBodySchema: z.ZodObject<{
13
+ contentKind: z.ZodEnum<{
14
+ post: "post";
15
+ lost_found: "lost_found";
16
+ voice_box: "voice_box";
17
+ }>;
18
+ contentId: z.ZodString;
19
+ reason: z.ZodEnum<{
20
+ spam: "spam";
21
+ harassment: "harassment";
22
+ hate_speech: "hate_speech";
23
+ misinformation: "misinformation";
24
+ sexual_content: "sexual_content";
25
+ violence: "violence";
26
+ self_harm: "self_harm";
27
+ illegal_content: "illegal_content";
28
+ other: "other";
29
+ }>;
30
+ details: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strip>;
32
+ export type ReportContentBody = z.infer<typeof reportContentBodySchema>;
33
+ export declare const reportRecordWireSchema: z.ZodObject<{
34
+ _id: z.ZodString;
35
+ contentKind: z.ZodEnum<{
36
+ post: "post";
37
+ lost_found: "lost_found";
38
+ voice_box: "voice_box";
39
+ }>;
40
+ contentId: z.ZodString;
41
+ reason: z.ZodEnum<{
42
+ spam: "spam";
43
+ harassment: "harassment";
44
+ hate_speech: "hate_speech";
45
+ misinformation: "misinformation";
46
+ sexual_content: "sexual_content";
47
+ violence: "violence";
48
+ self_harm: "self_harm";
49
+ illegal_content: "illegal_content";
50
+ other: "other";
51
+ }>;
52
+ details: z.ZodNullable<z.ZodString>;
53
+ status: z.ZodEnum<{
54
+ pending: "pending";
55
+ reviewing: "reviewing";
56
+ actioned: "actioned";
57
+ dismissed: "dismissed";
58
+ }>;
59
+ createdAt: z.ZodString;
60
+ }, z.core.$strip>;
61
+ export type ReportRecordWire = z.infer<typeof reportRecordWireSchema>;
62
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;iBAOlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAQjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
package/dist/report.js ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Content-reporting wire shapes for moderation.
3
+ *
4
+ * Any signed-in viewer can report any piece of community content
5
+ * (post / lost-found / voice-box / comment). Reports land in a
6
+ * moderation queue surfaced to admins; admin actions are out of scope
7
+ * for this schema package — the admin endpoints live elsewhere.
8
+ *
9
+ * @module community-schema/report
10
+ */
11
+ import { z } from 'zod';
12
+ import { contentKindSchema, reportReasonSchema, reportStatusSchema } from './enums.js';
13
+ export const reportContentBodySchema = z.object({
14
+ contentKind: contentKindSchema,
15
+ contentId: z.string(),
16
+ reason: reportReasonSchema,
17
+ /** Free-text detail. Required when `reason === 'other'`, optional
18
+ * otherwise (the server enforces the conditional via refine). */
19
+ details: z.string().max(2000).optional(),
20
+ });
21
+ export const reportRecordWireSchema = z.object({
22
+ _id: z.string(),
23
+ contentKind: contentKindSchema,
24
+ contentId: z.string(),
25
+ reason: reportReasonSchema,
26
+ details: z.string().nullable(),
27
+ status: reportStatusSchema,
28
+ createdAt: z.string().datetime(),
29
+ });
30
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEvF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,WAAW,EAAE,iBAAiB;IAC9B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,MAAM,EAAE,kBAAkB;IAC1B;sEACkE;IAClE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;CACzC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,WAAW,EAAE,iBAAiB;IAC9B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,MAAM,EAAE,kBAAkB;IAC1B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,MAAM,EAAE,kBAAkB;IAC1B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC","sourcesContent":["/**\n * Content-reporting wire shapes for moderation.\n *\n * Any signed-in viewer can report any piece of community content\n * (post / lost-found / voice-box / comment). Reports land in a\n * moderation queue surfaced to admins; admin actions are out of scope\n * for this schema package — the admin endpoints live elsewhere.\n *\n * @module community-schema/report\n */\n\nimport { z } from 'zod';\nimport { contentKindSchema, reportReasonSchema, reportStatusSchema } from './enums.js';\n\nexport const reportContentBodySchema = z.object({\n contentKind: contentKindSchema,\n contentId: z.string(),\n reason: reportReasonSchema,\n /** Free-text detail. Required when `reason === 'other'`, optional\n * otherwise (the server enforces the conditional via refine). */\n details: z.string().max(2000).optional(),\n});\nexport type ReportContentBody = z.infer<typeof reportContentBodySchema>;\n\nexport const reportRecordWireSchema = z.object({\n _id: z.string(),\n contentKind: contentKindSchema,\n contentId: z.string(),\n reason: reportReasonSchema,\n details: z.string().nullable(),\n status: reportStatusSchema,\n createdAt: z.string().datetime(),\n});\nexport type ReportRecordWire = z.infer<typeof reportRecordWireSchema>;\n"]}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Community settings wire shape.
3
+ *
4
+ * Per-user preferences scoped to the community feature. Read from
5
+ * `GET /api/v1/community/settings` and updated via
6
+ * `PATCH /api/v1/community/settings`. Updates are partial — the client
7
+ * sends only the fields it changes.
8
+ *
9
+ * @module community-schema/settings
10
+ */
11
+ import { z } from 'zod';
12
+ export declare const communitySettingsWireSchema: z.ZodObject<{
13
+ privacy: z.ZodEnum<{
14
+ public: "public";
15
+ private: "private";
16
+ }>;
17
+ defaultPostVisibility: z.ZodEnum<{
18
+ local: "local";
19
+ district: "district";
20
+ state: "state";
21
+ national: "national";
22
+ global: "global";
23
+ }>;
24
+ notifications: z.ZodObject<{
25
+ onFollow: z.ZodBoolean;
26
+ onConnectionRequest: z.ZodBoolean;
27
+ onConnectionAccepted: z.ZodBoolean;
28
+ onComment: z.ZodBoolean;
29
+ onReply: z.ZodBoolean;
30
+ onUpvote: z.ZodBoolean;
31
+ onReaction: z.ZodBoolean;
32
+ onGroupActivity: z.ZodBoolean;
33
+ }, z.core.$strip>;
34
+ }, z.core.$strip>;
35
+ export type CommunitySettingsWire = z.infer<typeof communitySettingsWireSchema>;
36
+ /**
37
+ * PATCH body — every field optional. The server merges over the existing
38
+ * settings. Notifications is a partial sub-shape so the client can
39
+ * toggle one knob at a time.
40
+ */
41
+ export declare const updateCommunitySettingsBodySchema: z.ZodObject<{
42
+ privacy: z.ZodOptional<z.ZodEnum<{
43
+ public: "public";
44
+ private: "private";
45
+ }>>;
46
+ defaultPostVisibility: z.ZodOptional<z.ZodEnum<{
47
+ local: "local";
48
+ district: "district";
49
+ state: "state";
50
+ national: "national";
51
+ global: "global";
52
+ }>>;
53
+ notifications: z.ZodOptional<z.ZodObject<{
54
+ onFollow: z.ZodOptional<z.ZodBoolean>;
55
+ onConnectionRequest: z.ZodOptional<z.ZodBoolean>;
56
+ onConnectionAccepted: z.ZodOptional<z.ZodBoolean>;
57
+ onComment: z.ZodOptional<z.ZodBoolean>;
58
+ onReply: z.ZodOptional<z.ZodBoolean>;
59
+ onUpvote: z.ZodOptional<z.ZodBoolean>;
60
+ onReaction: z.ZodOptional<z.ZodBoolean>;
61
+ onGroupActivity: z.ZodOptional<z.ZodBoolean>;
62
+ }, z.core.$strip>>;
63
+ }, z.core.$strip>;
64
+ export type UpdateCommunitySettingsBody = z.infer<typeof updateCommunitySettingsBodySchema>;
65
+ export declare const COMMUNITY_SETTINGS_DEFAULTS: CommunitySettingsWire;
66
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;iBAyBtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF;;;;GAIG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;;;;;;iBAe5C,CAAC;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAC/C,OAAO,iCAAiC,CACzC,CAAC;AAIF,eAAO,MAAM,2BAA2B,EAAE,qBAazC,CAAC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Community settings wire shape.
3
+ *
4
+ * Per-user preferences scoped to the community feature. Read from
5
+ * `GET /api/v1/community/settings` and updated via
6
+ * `PATCH /api/v1/community/settings`. Updates are partial — the client
7
+ * sends only the fields it changes.
8
+ *
9
+ * @module community-schema/settings
10
+ */
11
+ import { z } from 'zod';
12
+ import { profilePrivacySchema, visibilityLevelSchema } from './enums.js';
13
+ export const communitySettingsWireSchema = z.object({
14
+ /** Profile-level privacy toggle. */
15
+ privacy: profilePrivacySchema,
16
+ /** Default visibility level chosen in the post composer. */
17
+ defaultPostVisibility: visibilityLevelSchema,
18
+ /** Per-event notification toggles. The map is sparse: a missing key
19
+ * means "use the default". */
20
+ notifications: z.object({
21
+ /** Notify me when someone follows me. */
22
+ onFollow: z.boolean(),
23
+ /** Notify me when someone sends me a connection request. */
24
+ onConnectionRequest: z.boolean(),
25
+ /** Notify me when someone accepts my connection request. */
26
+ onConnectionAccepted: z.boolean(),
27
+ /** Notify me when someone comments on my post / lost-found / voice-box. */
28
+ onComment: z.boolean(),
29
+ /** Notify me when someone replies to my comment. */
30
+ onReply: z.boolean(),
31
+ /** Notify me when someone upvotes my content. */
32
+ onUpvote: z.boolean(),
33
+ /** Notify me when someone reacts to my content. */
34
+ onReaction: z.boolean(),
35
+ /** Notify me about activity in groups I'm a member of. */
36
+ onGroupActivity: z.boolean(),
37
+ }),
38
+ });
39
+ /**
40
+ * PATCH body — every field optional. The server merges over the existing
41
+ * settings. Notifications is a partial sub-shape so the client can
42
+ * toggle one knob at a time.
43
+ */
44
+ export const updateCommunitySettingsBodySchema = z.object({
45
+ privacy: profilePrivacySchema.optional(),
46
+ defaultPostVisibility: visibilityLevelSchema.optional(),
47
+ notifications: z
48
+ .object({
49
+ onFollow: z.boolean().optional(),
50
+ onConnectionRequest: z.boolean().optional(),
51
+ onConnectionAccepted: z.boolean().optional(),
52
+ onComment: z.boolean().optional(),
53
+ onReply: z.boolean().optional(),
54
+ onUpvote: z.boolean().optional(),
55
+ onReaction: z.boolean().optional(),
56
+ onGroupActivity: z.boolean().optional(),
57
+ })
58
+ .optional(),
59
+ });
60
+ // ─── Defaults (used by the backend when a user has no settings doc yet) ────
61
+ export const COMMUNITY_SETTINGS_DEFAULTS = {
62
+ privacy: 'public',
63
+ defaultPostVisibility: 'local',
64
+ notifications: {
65
+ onFollow: true,
66
+ onConnectionRequest: true,
67
+ onConnectionAccepted: true,
68
+ onComment: true,
69
+ onReply: true,
70
+ onUpvote: false,
71
+ onReaction: false,
72
+ onGroupActivity: true,
73
+ },
74
+ };
75
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,oCAAoC;IACpC,OAAO,EAAE,oBAAoB;IAC7B,4DAA4D;IAC5D,qBAAqB,EAAE,qBAAqB;IAC5C;mCAC+B;IAC/B,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC;QACtB,yCAAyC;QACzC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;QACrB,4DAA4D;QAC5D,mBAAmB,EAAE,CAAC,CAAC,OAAO,EAAE;QAChC,4DAA4D;QAC5D,oBAAoB,EAAE,CAAC,CAAC,OAAO,EAAE;QACjC,2EAA2E;QAC3E,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;QACtB,oDAAoD;QACpD,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;QACpB,iDAAiD;QACjD,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;QACrB,mDAAmD;QACnD,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;QACvB,0DAA0D;QAC1D,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE;KAC7B,CAAC;CACH,CAAC,CAAC;AAGH;;;;GAIG;AACH,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,CAAC,MAAM,CAAC;IACxD,OAAO,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACxC,qBAAqB,EAAE,qBAAqB,CAAC,QAAQ,EAAE;IACvD,aAAa,EAAE,CAAC;SACb,MAAM,CAAC;QACN,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAChC,mBAAmB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC3C,oBAAoB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC5C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QACjC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC/B,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAChC,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAClC,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KACxC,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAKH,8EAA8E;AAE9E,MAAM,CAAC,MAAM,2BAA2B,GAA0B;IAChE,OAAO,EAAE,QAAQ;IACjB,qBAAqB,EAAE,OAAO;IAC9B,aAAa,EAAE;QACb,QAAQ,EAAE,IAAI;QACd,mBAAmB,EAAE,IAAI;QACzB,oBAAoB,EAAE,IAAI;QAC1B,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,KAAK;QACf,UAAU,EAAE,KAAK;QACjB,eAAe,EAAE,IAAI;KACtB;CACF,CAAC","sourcesContent":["/**\n * Community settings wire shape.\n *\n * Per-user preferences scoped to the community feature. Read from\n * `GET /api/v1/community/settings` and updated via\n * `PATCH /api/v1/community/settings`. Updates are partial — the client\n * sends only the fields it changes.\n *\n * @module community-schema/settings\n */\n\nimport { z } from 'zod';\nimport { profilePrivacySchema, visibilityLevelSchema } from './enums.js';\n\nexport const communitySettingsWireSchema = z.object({\n /** Profile-level privacy toggle. */\n privacy: profilePrivacySchema,\n /** Default visibility level chosen in the post composer. */\n defaultPostVisibility: visibilityLevelSchema,\n /** Per-event notification toggles. The map is sparse: a missing key\n * means \"use the default\". */\n notifications: z.object({\n /** Notify me when someone follows me. */\n onFollow: z.boolean(),\n /** Notify me when someone sends me a connection request. */\n onConnectionRequest: z.boolean(),\n /** Notify me when someone accepts my connection request. */\n onConnectionAccepted: z.boolean(),\n /** Notify me when someone comments on my post / lost-found / voice-box. */\n onComment: z.boolean(),\n /** Notify me when someone replies to my comment. */\n onReply: z.boolean(),\n /** Notify me when someone upvotes my content. */\n onUpvote: z.boolean(),\n /** Notify me when someone reacts to my content. */\n onReaction: z.boolean(),\n /** Notify me about activity in groups I'm a member of. */\n onGroupActivity: z.boolean(),\n }),\n});\nexport type CommunitySettingsWire = z.infer<typeof communitySettingsWireSchema>;\n\n/**\n * PATCH body — every field optional. The server merges over the existing\n * settings. Notifications is a partial sub-shape so the client can\n * toggle one knob at a time.\n */\nexport const updateCommunitySettingsBodySchema = z.object({\n privacy: profilePrivacySchema.optional(),\n defaultPostVisibility: visibilityLevelSchema.optional(),\n notifications: z\n .object({\n onFollow: z.boolean().optional(),\n onConnectionRequest: z.boolean().optional(),\n onConnectionAccepted: z.boolean().optional(),\n onComment: z.boolean().optional(),\n onReply: z.boolean().optional(),\n onUpvote: z.boolean().optional(),\n onReaction: z.boolean().optional(),\n onGroupActivity: z.boolean().optional(),\n })\n .optional(),\n});\nexport type UpdateCommunitySettingsBody = z.infer<\n typeof updateCommunitySettingsBodySchema\n>;\n\n// ─── Defaults (used by the backend when a user has no settings doc yet) ────\n\nexport const COMMUNITY_SETTINGS_DEFAULTS: CommunitySettingsWire = {\n privacy: 'public',\n defaultPostVisibility: 'local',\n notifications: {\n onFollow: true,\n onConnectionRequest: true,\n onConnectionAccepted: true,\n onComment: true,\n onReply: true,\n onUpvote: false,\n onReaction: false,\n onGroupActivity: true,\n },\n};\n"]}