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/feed.js ADDED
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Feed wire shapes — polymorphic union of community posts, lost-and-
3
+ * found reports, and voice-box (complaints + suggestions).
4
+ *
5
+ * The feed is a SINGLE list typed as `FeedItem = Post | LostFound | VoiceBox`.
6
+ * The client discriminates on `contentKind` and renders the matching
7
+ * card component.
8
+ *
9
+ * Strategy notes (server-side):
10
+ * - Read-time fanout. The server runs ONE parallel query per kind
11
+ * filtered by the same area-lineage match and the same cascade-
12
+ * upward visibility rule, then merges and sorts by `hot` score.
13
+ * - Cursor-based pagination. The cursor is opaque (base64 of
14
+ * `<sortKey>|<_id>`) so we can swap sort algorithms without a
15
+ * breaking change.
16
+ * - LostFound / VoiceBox shapes are pruned to the fields the feed
17
+ * card needs — they keep their richer detail-page shape in their
18
+ * own schemas (lost-found-schema, voice-box-schema if/when those
19
+ * get factored out).
20
+ *
21
+ * @module community-schema/feed
22
+ */
23
+ import { z } from 'zod';
24
+ import { FEED_PAGE_SIZE } from './constants.js';
25
+ import { feedSortSchema, visibilityLevelSchema } from './enums.js';
26
+ import { communityPostWireSchema, postAuthorSnapshotSchema } from './post.js';
27
+ // ─── Per-kind feed envelopes ───────────────────────────────────────────────
28
+ /**
29
+ * Lost-and-found item projected into the feed. Mirrors the engagement
30
+ * + author shape every feed card needs, plus a small handful of
31
+ * lost-found-specific fields used by the card.
32
+ */
33
+ export const lostFoundFeedItemSchema = z.object({
34
+ _id: z.string(),
35
+ contentKind: z.literal('lost_found'),
36
+ author: postAuthorSnapshotSchema,
37
+ /** `'lost'` or `'found'` — drives the card chip colour. */
38
+ kind: z.enum(['lost', 'found']),
39
+ title: z.string(),
40
+ description: z.string(),
41
+ /** Single primary image rendered on the card. */
42
+ imageUrl: z.string().url().optional(),
43
+ /** Inherited engagement axis — same shape as posts. */
44
+ upvoteCount: z.number().int().nonnegative(),
45
+ commentCount: z.number().int().nonnegative(),
46
+ reactionCounts: z.record(z.string(), z.number().int().nonnegative()),
47
+ createdAt: z.string().datetime(),
48
+ viewer: z
49
+ .object({
50
+ upvoted: z.boolean(),
51
+ reaction: z.string().nullable(),
52
+ isAuthor: z.boolean(),
53
+ })
54
+ .optional(),
55
+ });
56
+ /**
57
+ * Voice-box (complaint or suggestion) item projected into the feed.
58
+ */
59
+ export const voiceBoxFeedItemSchema = z.object({
60
+ _id: z.string(),
61
+ contentKind: z.literal('voice_box'),
62
+ author: postAuthorSnapshotSchema,
63
+ /** `'complaint'` or `'suggestion'` — drives the card chip colour. */
64
+ kind: z.enum(['complaint', 'suggestion']),
65
+ title: z.string(),
66
+ description: z.string(),
67
+ upvoteCount: z.number().int().nonnegative(),
68
+ commentCount: z.number().int().nonnegative(),
69
+ reactionCounts: z.record(z.string(), z.number().int().nonnegative()),
70
+ createdAt: z.string().datetime(),
71
+ viewer: z
72
+ .object({
73
+ upvoted: z.boolean(),
74
+ reaction: z.string().nullable(),
75
+ isAuthor: z.boolean(),
76
+ })
77
+ .optional(),
78
+ });
79
+ // ─── Polymorphic union ─────────────────────────────────────────────────────
80
+ export const feedItemSchema = z.discriminatedUnion('contentKind', [
81
+ communityPostWireSchema,
82
+ lostFoundFeedItemSchema,
83
+ voiceBoxFeedItemSchema,
84
+ ]);
85
+ // ─── Query + response ──────────────────────────────────────────────────────
86
+ export const feedQueryParamsSchema = z.object({
87
+ /** The viewer's chosen feed level. Cascade-upward semantics apply. */
88
+ level: visibilityLevelSchema,
89
+ /** Sort algorithm. Defaults to `hot` server-side when omitted. */
90
+ sort: feedSortSchema.optional(),
91
+ /** Opaque pagination cursor returned by the previous page. */
92
+ cursor: z.string().optional(),
93
+ /** Page size; defaults to `FEED_PAGE_SIZE` server-side. */
94
+ pageSize: z.number().int().positive().max(50).optional(),
95
+ });
96
+ export const feedResponseSchema = z.object({
97
+ items: z.array(feedItemSchema),
98
+ nextCursor: z.string().nullable(),
99
+ });
100
+ // Re-export so consumers don't have to also import constants.ts.
101
+ export { FEED_PAGE_SIZE };
102
+ //# sourceMappingURL=feed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed.js","sourceRoot":"","sources":["../src/feed.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Feed wire shapes — polymorphic union of community posts, lost-and-\n * found reports, and voice-box (complaints + suggestions).\n *\n * The feed is a SINGLE list typed as `FeedItem = Post | LostFound | VoiceBox`.\n * The client discriminates on `contentKind` and renders the matching\n * card component.\n *\n * Strategy notes (server-side):\n * - Read-time fanout. The server runs ONE parallel query per kind\n * filtered by the same area-lineage match and the same cascade-\n * upward visibility rule, then merges and sorts by `hot` score.\n * - Cursor-based pagination. The cursor is opaque (base64 of\n * `<sortKey>|<_id>`) so we can swap sort algorithms without a\n * breaking change.\n * - LostFound / VoiceBox shapes are pruned to the fields the feed\n * card needs — they keep their richer detail-page shape in their\n * own schemas (lost-found-schema, voice-box-schema if/when those\n * get factored out).\n *\n * @module community-schema/feed\n */\n\nimport { z } from 'zod';\nimport { FEED_PAGE_SIZE } from './constants.js';\nimport { feedSortSchema, visibilityLevelSchema } from './enums.js';\nimport { communityPostWireSchema, postAuthorSnapshotSchema } from './post.js';\n\n// ─── Per-kind feed envelopes ───────────────────────────────────────────────\n\n/**\n * Lost-and-found item projected into the feed. Mirrors the engagement\n * + author shape every feed card needs, plus a small handful of\n * lost-found-specific fields used by the card.\n */\nexport const lostFoundFeedItemSchema = z.object({\n _id: z.string(),\n contentKind: z.literal('lost_found'),\n author: postAuthorSnapshotSchema,\n\n /** `'lost'` or `'found'` — drives the card chip colour. */\n kind: z.enum(['lost', 'found']),\n title: z.string(),\n description: z.string(),\n /** Single primary image rendered on the card. */\n imageUrl: z.string().url().optional(),\n\n /** Inherited engagement axis — same shape as posts. */\n upvoteCount: z.number().int().nonnegative(),\n commentCount: z.number().int().nonnegative(),\n reactionCounts: z.record(z.string(), z.number().int().nonnegative()),\n\n createdAt: z.string().datetime(),\n\n viewer: z\n .object({\n upvoted: z.boolean(),\n reaction: z.string().nullable(),\n isAuthor: z.boolean(),\n })\n .optional(),\n});\nexport type LostFoundFeedItem = z.infer<typeof lostFoundFeedItemSchema>;\n\n/**\n * Voice-box (complaint or suggestion) item projected into the feed.\n */\nexport const voiceBoxFeedItemSchema = z.object({\n _id: z.string(),\n contentKind: z.literal('voice_box'),\n author: postAuthorSnapshotSchema,\n\n /** `'complaint'` or `'suggestion'` — drives the card chip colour. */\n kind: z.enum(['complaint', 'suggestion']),\n title: z.string(),\n description: z.string(),\n\n upvoteCount: z.number().int().nonnegative(),\n commentCount: z.number().int().nonnegative(),\n reactionCounts: z.record(z.string(), z.number().int().nonnegative()),\n\n createdAt: z.string().datetime(),\n\n viewer: z\n .object({\n upvoted: z.boolean(),\n reaction: z.string().nullable(),\n isAuthor: z.boolean(),\n })\n .optional(),\n});\nexport type VoiceBoxFeedItem = z.infer<typeof voiceBoxFeedItemSchema>;\n\n// ─── Polymorphic union ─────────────────────────────────────────────────────\n\nexport const feedItemSchema = z.discriminatedUnion('contentKind', [\n communityPostWireSchema,\n lostFoundFeedItemSchema,\n voiceBoxFeedItemSchema,\n]);\nexport type FeedItem = z.infer<typeof feedItemSchema>;\n\n// ─── Query + response ──────────────────────────────────────────────────────\n\nexport const feedQueryParamsSchema = z.object({\n /** The viewer's chosen feed level. Cascade-upward semantics apply. */\n level: visibilityLevelSchema,\n /** Sort algorithm. Defaults to `hot` server-side when omitted. */\n sort: feedSortSchema.optional(),\n /** Opaque pagination cursor returned by the previous page. */\n cursor: z.string().optional(),\n /** Page size; defaults to `FEED_PAGE_SIZE` server-side. */\n pageSize: z.number().int().positive().max(50).optional(),\n});\nexport type FeedQueryParams = z.infer<typeof feedQueryParamsSchema>;\n\nexport const feedResponseSchema = z.object({\n items: z.array(feedItemSchema),\n nextCursor: z.string().nullable(),\n});\nexport type FeedResponse = z.infer<typeof feedResponseSchema>;\n\n// Re-export so consumers don't have to also import constants.ts.\nexport { FEED_PAGE_SIZE };\n"]}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * User-created group chat wire shapes for the Community → Chat tab.
3
+ *
4
+ * The community-scoped group chats are wire-compatible with the
5
+ * generic `Conversation` shape on chat-server (so a community group
6
+ * shows up in the inbox like any other conversation). What lives here
7
+ * is the COMMUNITY-side metadata used to create + administer the group
8
+ * before chat-server takes over.
9
+ *
10
+ * @module community-schema/group
11
+ */
12
+ import { z } from 'zod';
13
+ export declare const groupRoleSchema: z.ZodEnum<{
14
+ owner: "owner";
15
+ admin: "admin";
16
+ member: "member";
17
+ }>;
18
+ export type GroupRole = z.infer<typeof groupRoleSchema>;
19
+ export declare const communityGroupWireSchema: z.ZodObject<{
20
+ _id: z.ZodString;
21
+ conversationId: z.ZodString;
22
+ name: z.ZodString;
23
+ description: z.ZodOptional<z.ZodString>;
24
+ imageUrl: z.ZodOptional<z.ZodString>;
25
+ createdByUserId: z.ZodString;
26
+ memberCount: z.ZodNumber;
27
+ createdAt: z.ZodString;
28
+ viewer: z.ZodOptional<z.ZodObject<{
29
+ role: z.ZodEnum<{
30
+ owner: "owner";
31
+ admin: "admin";
32
+ member: "member";
33
+ }>;
34
+ joinedAt: z.ZodString;
35
+ }, z.core.$strip>>;
36
+ }, z.core.$strip>;
37
+ export type CommunityGroupWire = z.infer<typeof communityGroupWireSchema>;
38
+ export declare const createGroupBodySchema: z.ZodObject<{
39
+ name: z.ZodString;
40
+ description: z.ZodOptional<z.ZodString>;
41
+ memberUserIds: z.ZodArray<z.ZodString>;
42
+ }, z.core.$strip>;
43
+ export type CreateGroupBody = z.infer<typeof createGroupBodySchema>;
44
+ export declare const addGroupMembersBodySchema: z.ZodObject<{
45
+ userIds: z.ZodArray<z.ZodString>;
46
+ }, z.core.$strip>;
47
+ export type AddGroupMembersBody = z.infer<typeof addGroupMembersBodySchema>;
48
+ //# sourceMappingURL=group.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../src/group.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,eAAe;;;;EAAuC,CAAC;AACpE,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;iBAmBnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAI1E,eAAO,MAAM,qBAAqB;;;;iBAKhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAIpE,eAAO,MAAM,yBAAyB;;iBAEpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC"}
package/dist/group.js ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * User-created group chat wire shapes for the Community → Chat tab.
3
+ *
4
+ * The community-scoped group chats are wire-compatible with the
5
+ * generic `Conversation` shape on chat-server (so a community group
6
+ * shows up in the inbox like any other conversation). What lives here
7
+ * is the COMMUNITY-side metadata used to create + administer the group
8
+ * before chat-server takes over.
9
+ *
10
+ * @module community-schema/group
11
+ */
12
+ import { z } from 'zod';
13
+ import { GROUP_MAX_MEMBERS, GROUP_NAME_MAX_CHARS, GROUP_NAME_MIN_CHARS, } from './constants.js';
14
+ export const groupRoleSchema = z.enum(['owner', 'admin', 'member']);
15
+ export const communityGroupWireSchema = z.object({
16
+ _id: z.string(),
17
+ /** The chat-server conversation id this group is bound to. */
18
+ conversationId: z.string(),
19
+ name: z.string().min(GROUP_NAME_MIN_CHARS).max(GROUP_NAME_MAX_CHARS),
20
+ description: z.string().max(500).optional(),
21
+ /** Group avatar / cover image. */
22
+ imageUrl: z.string().url().optional(),
23
+ createdByUserId: z.string(),
24
+ memberCount: z.number().int().nonnegative(),
25
+ createdAt: z.string().datetime(),
26
+ /** Per-viewer state — included when the viewer is a member. */
27
+ viewer: z
28
+ .object({
29
+ role: groupRoleSchema,
30
+ joinedAt: z.string().datetime(),
31
+ })
32
+ .optional(),
33
+ });
34
+ // ─── Create body ────────────────────────────────────────────────────────────
35
+ export const createGroupBodySchema = z.object({
36
+ name: z.string().min(GROUP_NAME_MIN_CHARS).max(GROUP_NAME_MAX_CHARS),
37
+ description: z.string().max(500).optional(),
38
+ /** Initial member user ids (excluding the creator who becomes owner). */
39
+ memberUserIds: z.array(z.string()).max(GROUP_MAX_MEMBERS - 1),
40
+ });
41
+ // ─── Add / remove members ──────────────────────────────────────────────────
42
+ export const addGroupMembersBodySchema = z.object({
43
+ userIds: z.array(z.string()).min(1).max(50),
44
+ });
45
+ //# sourceMappingURL=group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group.js","sourceRoot":"","sources":["../src/group.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AAExB,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGpE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,8DAA8D;IAC9D,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;IAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACpE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC3C,kCAAkC;IAClC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACrC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;IAC3B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC3C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAEhC,+DAA+D;IAC/D,MAAM,EAAE,CAAC;SACN,MAAM,CAAC;QACN,IAAI,EAAE,eAAe;QACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAChC,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAGH,+EAA+E;AAE/E,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACpE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC3C,yEAAyE;IACzE,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,iBAAiB,GAAG,CAAC,CAAC;CAC9D,CAAC,CAAC;AAGH,8EAA8E;AAE9E,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;CAC5C,CAAC,CAAC","sourcesContent":["/**\n * User-created group chat wire shapes for the Community → Chat tab.\n *\n * The community-scoped group chats are wire-compatible with the\n * generic `Conversation` shape on chat-server (so a community group\n * shows up in the inbox like any other conversation). What lives here\n * is the COMMUNITY-side metadata used to create + administer the group\n * before chat-server takes over.\n *\n * @module community-schema/group\n */\n\nimport { z } from 'zod';\nimport {\n GROUP_MAX_MEMBERS,\n GROUP_NAME_MAX_CHARS,\n GROUP_NAME_MIN_CHARS,\n} from './constants.js';\n\nexport const groupRoleSchema = z.enum(['owner', 'admin', 'member']);\nexport type GroupRole = z.infer<typeof groupRoleSchema>;\n\nexport const communityGroupWireSchema = z.object({\n _id: z.string(),\n /** The chat-server conversation id this group is bound to. */\n conversationId: z.string(),\n name: z.string().min(GROUP_NAME_MIN_CHARS).max(GROUP_NAME_MAX_CHARS),\n description: z.string().max(500).optional(),\n /** Group avatar / cover image. */\n imageUrl: z.string().url().optional(),\n createdByUserId: z.string(),\n memberCount: z.number().int().nonnegative(),\n createdAt: z.string().datetime(),\n\n /** Per-viewer state — included when the viewer is a member. */\n viewer: z\n .object({\n role: groupRoleSchema,\n joinedAt: z.string().datetime(),\n })\n .optional(),\n});\nexport type CommunityGroupWire = z.infer<typeof communityGroupWireSchema>;\n\n// ─── Create body ────────────────────────────────────────────────────────────\n\nexport const createGroupBodySchema = z.object({\n name: z.string().min(GROUP_NAME_MIN_CHARS).max(GROUP_NAME_MAX_CHARS),\n description: z.string().max(500).optional(),\n /** Initial member user ids (excluding the creator who becomes owner). */\n memberUserIds: z.array(z.string()).max(GROUP_MAX_MEMBERS - 1),\n});\nexport type CreateGroupBody = z.infer<typeof createGroupBodySchema>;\n\n// ─── Add / remove members ──────────────────────────────────────────────────\n\nexport const addGroupMembersBodySchema = z.object({\n userIds: z.array(z.string()).min(1).max(50),\n});\nexport type AddGroupMembersBody = z.infer<typeof addGroupMembersBodySchema>;\n"]}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * community-schema — Shared Zod schemas + TypeScript types for the
3
+ * Jansathi hyperlocal community feature (feed, posts, engagement,
4
+ * social graph, groups, settings).
5
+ *
6
+ * Single source of truth consumed by reform-backend and every product
7
+ * frontend. The schemas mirror MongoDB / Mongoose document shapes
8
+ * 1:1 so the same Zod validation runs at the controller boundary on
9
+ * the backend and in the form handlers on the client.
10
+ *
11
+ * Cascade-upward visibility semantics: a viewer whose feed level is L
12
+ * sees posts at L and every BROADER level matching their area lineage.
13
+ * See `./enums.ts#VISIBILITY_LEVEL_VALUES` for the level rank table.
14
+ *
15
+ * @module community-schema
16
+ */
17
+ export { type AreaLineageSnapshot, areaLineageSnapshotSchema, } from './area.js';
18
+ export { type CommunityCommentWire, communityCommentWireSchema, type CreateCommentBody, createCommentBodySchema, type UpdateCommentBody, updateCommentBodySchema, } from './comment.js';
19
+ export { COMMENT_MAX_BODY_CHARS, COMMENTS_PAGE_SIZE, EDIT_GRACE_WINDOW_MS, FEED_PAGE_SIZE, GROUP_MAX_MEMBERS, GROUP_NAME_MAX_CHARS, GROUP_NAME_MIN_CHARS, PEOPLE_PAGE_SIZE, POST_MAX_BODY_CHARS, POST_MAX_IMAGE_BYTES, POST_MAX_IMAGES, POST_MAX_VIDEO_BYTES, POST_MAX_VIDEO_SECONDS, POST_MAX_VIDEOS, PROFILE_MAX_BIO_CHARS, REPLIES_PRELOAD_COUNT, } from './constants.js';
20
+ export { type SetReactionBody, setReactionBodySchema, type SetReactionResponse, setReactionResponseSchema, type ToggleUpvoteResponse, toggleUpvoteResponseSchema, } from './engagement.js';
21
+ export { CONNECTION_STATUS_VALUES, type ConnectionStatus, connectionStatusSchema, CONTENT_KIND_VALUES, type ContentKind, contentKindSchema, FEED_SORT_VALUES, type FeedSort, feedSortSchema, PROFILE_PRIVACY_VALUES, type ProfilePrivacy, profilePrivacySchema, REACTION_TYPE_VALUES, type ReactionType, reactionTypeSchema, REPORT_REASON_VALUES, type ReportReason, reportReasonSchema, REPORT_STATUS_VALUES, type ReportStatus, reportStatusSchema, VISIBILITY_LEVEL_RANK, VISIBILITY_LEVEL_VALUES, type VisibilityLevel, visibilityLevelSchema, } from './enums.js';
22
+ export { type FeedItem, type FeedQueryParams, type FeedResponse, feedItemSchema, feedQueryParamsSchema, feedResponseSchema, type LostFoundFeedItem, lostFoundFeedItemSchema, type VoiceBoxFeedItem, voiceBoxFeedItemSchema, } from './feed.js';
23
+ export { type AddGroupMembersBody, addGroupMembersBodySchema, type CommunityGroupWire, communityGroupWireSchema, type CreateGroupBody, createGroupBodySchema, type GroupRole, groupRoleSchema, } from './group.js';
24
+ export { type PostImage, postImageSchema, type PostVideo, postVideoSchema, } from './media.js';
25
+ export { type CommunityPostWire, communityPostWireSchema, type CreatePostBody, createPostBodySchema, type PostAuthorSnapshot, postAuthorSnapshotSchema, type UpdatePostBody, updatePostBodySchema, } from './post.js';
26
+ export { type PeopleListItem, type PeopleListResponse, type PeopleQueryParams, peopleListItemSchema, peopleListResponseSchema, peopleQueryParamsSchema, type PublicProfileWire, publicProfileWireSchema, } from './profile.js';
27
+ export { type ReportContentBody, reportContentBodySchema, type ReportRecordWire, reportRecordWireSchema, } from './report.js';
28
+ export { COMMUNITY_SETTINGS_DEFAULTS, type CommunitySettingsWire, communitySettingsWireSchema, type UpdateCommunitySettingsBody, updateCommunitySettingsBodySchema, } from './settings.js';
29
+ export { type ConnectionDecisionBody, connectionDecisionBodySchema, type ConnectionRecordWire, connectionRecordWireSchema, type SendConnectionRequestResponse, sendConnectionRequestResponseSchema, type ToggleFollowResponse, toggleFollowResponseSchema, type ViewerSocialState, viewerSocialStateSchema, } from './social.js';
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * community-schema — Shared Zod schemas + TypeScript types for the
3
+ * Jansathi hyperlocal community feature (feed, posts, engagement,
4
+ * social graph, groups, settings).
5
+ *
6
+ * Single source of truth consumed by reform-backend and every product
7
+ * frontend. The schemas mirror MongoDB / Mongoose document shapes
8
+ * 1:1 so the same Zod validation runs at the controller boundary on
9
+ * the backend and in the form handlers on the client.
10
+ *
11
+ * Cascade-upward visibility semantics: a viewer whose feed level is L
12
+ * sees posts at L and every BROADER level matching their area lineage.
13
+ * See `./enums.ts#VISIBILITY_LEVEL_VALUES` for the level rank table.
14
+ *
15
+ * @module community-schema
16
+ */
17
+ // ─── Area lineage snapshot ─────────────────────────────────────────────────
18
+ export { areaLineageSnapshotSchema, } from './area.js';
19
+ // ─── Comment ───────────────────────────────────────────────────────────────
20
+ export { communityCommentWireSchema, createCommentBodySchema, updateCommentBodySchema, } from './comment.js';
21
+ // ─── Constants ─────────────────────────────────────────────────────────────
22
+ export { COMMENT_MAX_BODY_CHARS, COMMENTS_PAGE_SIZE, EDIT_GRACE_WINDOW_MS, FEED_PAGE_SIZE, GROUP_MAX_MEMBERS, GROUP_NAME_MAX_CHARS, GROUP_NAME_MIN_CHARS, PEOPLE_PAGE_SIZE, POST_MAX_BODY_CHARS, POST_MAX_IMAGE_BYTES, POST_MAX_IMAGES, POST_MAX_VIDEO_BYTES, POST_MAX_VIDEO_SECONDS, POST_MAX_VIDEOS, PROFILE_MAX_BIO_CHARS, REPLIES_PRELOAD_COUNT, } from './constants.js';
23
+ // ─── Engagement (upvote + reactions) ───────────────────────────────────────
24
+ export { setReactionBodySchema, setReactionResponseSchema, toggleUpvoteResponseSchema, } from './engagement.js';
25
+ // ─── Enums ─────────────────────────────────────────────────────────────────
26
+ export { CONNECTION_STATUS_VALUES, connectionStatusSchema, CONTENT_KIND_VALUES, contentKindSchema, FEED_SORT_VALUES, feedSortSchema, PROFILE_PRIVACY_VALUES, profilePrivacySchema, REACTION_TYPE_VALUES, reactionTypeSchema, REPORT_REASON_VALUES, reportReasonSchema, REPORT_STATUS_VALUES, reportStatusSchema, VISIBILITY_LEVEL_RANK, VISIBILITY_LEVEL_VALUES, visibilityLevelSchema, } from './enums.js';
27
+ // ─── Feed (polymorphic union) ──────────────────────────────────────────────
28
+ export { feedItemSchema, feedQueryParamsSchema, feedResponseSchema, lostFoundFeedItemSchema, voiceBoxFeedItemSchema, } from './feed.js';
29
+ // ─── Groups ────────────────────────────────────────────────────────────────
30
+ export { addGroupMembersBodySchema, communityGroupWireSchema, createGroupBodySchema, groupRoleSchema, } from './group.js';
31
+ // ─── Media ─────────────────────────────────────────────────────────────────
32
+ export { postImageSchema, postVideoSchema, } from './media.js';
33
+ // ─── Post ──────────────────────────────────────────────────────────────────
34
+ export { communityPostWireSchema, createPostBodySchema, postAuthorSnapshotSchema, updatePostBodySchema, } from './post.js';
35
+ // ─── Profile + People list ─────────────────────────────────────────────────
36
+ export { peopleListItemSchema, peopleListResponseSchema, peopleQueryParamsSchema, publicProfileWireSchema, } from './profile.js';
37
+ // ─── Reports (moderation) ──────────────────────────────────────────────────
38
+ export { reportContentBodySchema, reportRecordWireSchema, } from './report.js';
39
+ // ─── Settings ──────────────────────────────────────────────────────────────
40
+ export { COMMUNITY_SETTINGS_DEFAULTS, communitySettingsWireSchema, updateCommunitySettingsBodySchema, } from './settings.js';
41
+ // ─── Social (follow + connection) ──────────────────────────────────────────
42
+ export { connectionDecisionBodySchema, connectionRecordWireSchema, sendConnectionRequestResponseSchema, toggleFollowResponseSchema, viewerSocialStateSchema, } from './social.js';
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,8EAA8E;AAC9E,OAAO,EAEL,yBAAyB,GAC1B,MAAM,WAAW,CAAC;AAEnB,8EAA8E;AAC9E,OAAO,EAEL,0BAA0B,EAE1B,uBAAuB,EAEvB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAEtB,8EAA8E;AAC9E,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAExB,8EAA8E;AAC9E,OAAO,EAEL,qBAAqB,EAErB,yBAAyB,EAEzB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AAEzB,8EAA8E;AAC9E,OAAO,EACL,wBAAwB,EAExB,sBAAsB,EACtB,mBAAmB,EAEnB,iBAAiB,EACjB,gBAAgB,EAEhB,cAAc,EACd,sBAAsB,EAEtB,oBAAoB,EACpB,oBAAoB,EAEpB,kBAAkB,EAClB,oBAAoB,EAEpB,kBAAkB,EAClB,oBAAoB,EAEpB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EAEvB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAEpB,8EAA8E;AAC9E,OAAO,EAIL,cAAc,EACd,qBAAqB,EACrB,kBAAkB,EAElB,uBAAuB,EAEvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAEnB,8EAA8E;AAC9E,OAAO,EAEL,yBAAyB,EAEzB,wBAAwB,EAExB,qBAAqB,EAErB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,8EAA8E;AAC9E,OAAO,EAEL,eAAe,EAEf,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,8EAA8E;AAC9E,OAAO,EAEL,uBAAuB,EAEvB,oBAAoB,EAEpB,wBAAwB,EAExB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AAEnB,8EAA8E;AAC9E,OAAO,EAIL,oBAAoB,EACpB,wBAAwB,EACxB,uBAAuB,EAEvB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAEtB,8EAA8E;AAC9E,OAAO,EAEL,uBAAuB,EAEvB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,8EAA8E;AAC9E,OAAO,EACL,2BAA2B,EAE3B,2BAA2B,EAE3B,iCAAiC,GAClC,MAAM,eAAe,CAAC;AAEvB,8EAA8E;AAC9E,OAAO,EAEL,4BAA4B,EAE5B,0BAA0B,EAE1B,mCAAmC,EAEnC,0BAA0B,EAE1B,uBAAuB,GACxB,MAAM,aAAa,CAAC","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 communityCommentWireSchema,\n type CreateCommentBody,\n createCommentBodySchema,\n type UpdateCommentBody,\n updateCommentBodySchema,\n} from './comment.js';\n\n// ─── Constants ─────────────────────────────────────────────────────────────\nexport {\n COMMENT_MAX_BODY_CHARS,\n COMMENTS_PAGE_SIZE,\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 setReactionBodySchema,\n type SetReactionResponse,\n setReactionResponseSchema,\n type ToggleUpvoteResponse,\n toggleUpvoteResponseSchema,\n} from './engagement.js';\n\n// ─── Enums ─────────────────────────────────────────────────────────────────\nexport {\n CONNECTION_STATUS_VALUES,\n type ConnectionStatus,\n connectionStatusSchema,\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 type ReactionType,\n reactionTypeSchema,\n REPORT_REASON_VALUES,\n type ReportReason,\n reportReasonSchema,\n REPORT_STATUS_VALUES,\n type ReportStatus,\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 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 communityGroupWireSchema,\n type CreateGroupBody,\n createGroupBodySchema,\n type GroupRole,\n groupRoleSchema,\n} from './group.js';\n\n// ─── Media ─────────────────────────────────────────────────────────────────\nexport {\n type PostImage,\n postImageSchema,\n type PostVideo,\n postVideoSchema,\n} from './media.js';\n\n// ─── Post ──────────────────────────────────────────────────────────────────\nexport {\n type CommunityPostWire,\n communityPostWireSchema,\n type CreatePostBody,\n createPostBodySchema,\n type PostAuthorSnapshot,\n postAuthorSnapshotSchema,\n type UpdatePostBody,\n updatePostBodySchema,\n} from './post.js';\n\n// ─── Profile + People list ─────────────────────────────────────────────────\nexport {\n type PeopleListItem,\n type PeopleListResponse,\n type PeopleQueryParams,\n peopleListItemSchema,\n peopleListResponseSchema,\n peopleQueryParamsSchema,\n type PublicProfileWire,\n publicProfileWireSchema,\n} from './profile.js';\n\n// ─── Reports (moderation) ──────────────────────────────────────────────────\nexport {\n type ReportContentBody,\n reportContentBodySchema,\n type ReportRecordWire,\n reportRecordWireSchema,\n} from './report.js';\n\n// ─── Settings ──────────────────────────────────────────────────────────────\nexport {\n COMMUNITY_SETTINGS_DEFAULTS,\n type CommunitySettingsWire,\n communitySettingsWireSchema,\n type UpdateCommunitySettingsBody,\n updateCommunitySettingsBodySchema,\n} from './settings.js';\n\n// ─── Social (follow + connection) ──────────────────────────────────────────\nexport {\n type ConnectionDecisionBody,\n connectionDecisionBodySchema,\n type ConnectionRecordWire,\n connectionRecordWireSchema,\n type SendConnectionRequestResponse,\n sendConnectionRequestResponseSchema,\n type ToggleFollowResponse,\n toggleFollowResponseSchema,\n type ViewerSocialState,\n viewerSocialStateSchema,\n} from './social.js';\n"]}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Media-asset wire shapes for community posts.
3
+ *
4
+ * Uploads land in the shared file service (same GCS bucket the rest of
5
+ * Jansathi uses) and the result — a signed URL + thumbnail + a small
6
+ * set of metadata — is what the post-create endpoint accepts.
7
+ *
8
+ * Why the wire shape carries width/height/duration: feed cards need
9
+ * those to size the preview without loading the full asset (avoids
10
+ * layout shift). Thumbnails are server-generated for videos and
11
+ * server-compressed-variants for images.
12
+ *
13
+ * @module community-schema/media
14
+ */
15
+ import { z } from 'zod';
16
+ /**
17
+ * An image attached to a community post.
18
+ *
19
+ * `width` / `height` are reported by the upload pipeline (sharp on the
20
+ * backend or Image-API on the client) so the feed card can render an
21
+ * intrinsic-size box and avoid CLS.
22
+ */
23
+ export declare const postImageSchema: z.ZodObject<{
24
+ url: z.ZodString;
25
+ thumbnailUrl: z.ZodOptional<z.ZodString>;
26
+ width: z.ZodNumber;
27
+ height: z.ZodNumber;
28
+ bytes: z.ZodNumber;
29
+ alt: z.ZodOptional<z.ZodString>;
30
+ }, z.core.$strip>;
31
+ export type PostImage = z.infer<typeof postImageSchema>;
32
+ /**
33
+ * A video attached to a community post.
34
+ *
35
+ * Required `duration` is enforced at upload time so we never have to
36
+ * probe the asset in the feed query. `thumbnailUrl` is a poster frame
37
+ * extracted on the backend.
38
+ */
39
+ export declare const postVideoSchema: z.ZodObject<{
40
+ url: z.ZodString;
41
+ thumbnailUrl: z.ZodString;
42
+ width: z.ZodNumber;
43
+ height: z.ZodNumber;
44
+ bytes: z.ZodNumber;
45
+ duration: z.ZodNumber;
46
+ }, z.core.$strip>;
47
+ export type PostVideo = z.infer<typeof postVideoSchema>;
48
+ //# sourceMappingURL=media.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;;;iBAS1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;;;iBAQ1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC"}
package/dist/media.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Media-asset wire shapes for community posts.
3
+ *
4
+ * Uploads land in the shared file service (same GCS bucket the rest of
5
+ * Jansathi uses) and the result — a signed URL + thumbnail + a small
6
+ * set of metadata — is what the post-create endpoint accepts.
7
+ *
8
+ * Why the wire shape carries width/height/duration: feed cards need
9
+ * those to size the preview without loading the full asset (avoids
10
+ * layout shift). Thumbnails are server-generated for videos and
11
+ * server-compressed-variants for images.
12
+ *
13
+ * @module community-schema/media
14
+ */
15
+ import { z } from 'zod';
16
+ import { POST_MAX_IMAGE_BYTES, POST_MAX_VIDEO_BYTES, POST_MAX_VIDEO_SECONDS, } from './constants.js';
17
+ /**
18
+ * An image attached to a community post.
19
+ *
20
+ * `width` / `height` are reported by the upload pipeline (sharp on the
21
+ * backend or Image-API on the client) so the feed card can render an
22
+ * intrinsic-size box and avoid CLS.
23
+ */
24
+ export const postImageSchema = z.object({
25
+ url: z.string().url(),
26
+ thumbnailUrl: z.string().url().optional(),
27
+ width: z.number().int().positive(),
28
+ height: z.number().int().positive(),
29
+ /** Original byte size at upload time. The pipeline rejects >cap. */
30
+ bytes: z.number().int().positive().max(POST_MAX_IMAGE_BYTES),
31
+ /** Author-supplied alt text. Optional but recommended for a11y. */
32
+ alt: z.string().max(280).optional(),
33
+ });
34
+ /**
35
+ * A video attached to a community post.
36
+ *
37
+ * Required `duration` is enforced at upload time so we never have to
38
+ * probe the asset in the feed query. `thumbnailUrl` is a poster frame
39
+ * extracted on the backend.
40
+ */
41
+ export const postVideoSchema = z.object({
42
+ url: z.string().url(),
43
+ thumbnailUrl: z.string().url(),
44
+ width: z.number().int().positive(),
45
+ height: z.number().int().positive(),
46
+ bytes: z.number().int().positive().max(POST_MAX_VIDEO_BYTES),
47
+ /** Duration in seconds. Hard-capped per `POST_MAX_VIDEO_SECONDS`. */
48
+ duration: z.number().positive().max(POST_MAX_VIDEO_SECONDS),
49
+ });
50
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AAExB;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACrB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACzC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACnC,oEAAoE;IACpE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAC5D,mEAAmE;IACnE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAGH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACrB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAC5D,qEAAqE;IACrE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,sBAAsB,CAAC;CAC5D,CAAC,CAAC","sourcesContent":["/**\n * Media-asset wire shapes for community posts.\n *\n * Uploads land in the shared file service (same GCS bucket the rest of\n * Jansathi uses) and the result — a signed URL + thumbnail + a small\n * set of metadata — is what the post-create endpoint accepts.\n *\n * Why the wire shape carries width/height/duration: feed cards need\n * those to size the preview without loading the full asset (avoids\n * layout shift). Thumbnails are server-generated for videos and\n * server-compressed-variants for images.\n *\n * @module community-schema/media\n */\n\nimport { z } from 'zod';\nimport {\n POST_MAX_IMAGE_BYTES,\n POST_MAX_VIDEO_BYTES,\n POST_MAX_VIDEO_SECONDS,\n} from './constants.js';\n\n/**\n * An image attached to a community post.\n *\n * `width` / `height` are reported by the upload pipeline (sharp on the\n * backend or Image-API on the client) so the feed card can render an\n * intrinsic-size box and avoid CLS.\n */\nexport const postImageSchema = z.object({\n url: z.string().url(),\n thumbnailUrl: z.string().url().optional(),\n width: z.number().int().positive(),\n height: z.number().int().positive(),\n /** Original byte size at upload time. The pipeline rejects >cap. */\n bytes: z.number().int().positive().max(POST_MAX_IMAGE_BYTES),\n /** Author-supplied alt text. Optional but recommended for a11y. */\n alt: z.string().max(280).optional(),\n});\nexport type PostImage = z.infer<typeof postImageSchema>;\n\n/**\n * A video attached to a community post.\n *\n * Required `duration` is enforced at upload time so we never have to\n * probe the asset in the feed query. `thumbnailUrl` is a poster frame\n * extracted on the backend.\n */\nexport const postVideoSchema = z.object({\n url: z.string().url(),\n thumbnailUrl: z.string().url(),\n width: z.number().int().positive(),\n height: z.number().int().positive(),\n bytes: z.number().int().positive().max(POST_MAX_VIDEO_BYTES),\n /** Duration in seconds. Hard-capped per `POST_MAX_VIDEO_SECONDS`. */\n duration: z.number().positive().max(POST_MAX_VIDEO_SECONDS),\n});\nexport type PostVideo = z.infer<typeof postVideoSchema>;\n"]}
package/dist/post.d.ts ADDED
@@ -0,0 +1,130 @@
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
+ /**
13
+ * The author's display info captured at post time. Denormalising
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.
17
+ *
18
+ * The User document remains the source of truth; a background job
19
+ * (or a hook on User.findOneAndUpdate) refreshes recent posts when
20
+ * a user changes their display name or avatar.
21
+ */
22
+ export declare const postAuthorSnapshotSchema: z.ZodObject<{
23
+ userId: z.ZodString;
24
+ displayName: z.ZodString;
25
+ avatarUrl: z.ZodOptional<z.ZodString>;
26
+ localName: z.ZodOptional<z.ZodString>;
27
+ }, z.core.$strip>;
28
+ export type PostAuthorSnapshot = z.infer<typeof postAuthorSnapshotSchema>;
29
+ /**
30
+ * A community post as it appears in the feed and on the single-post
31
+ * page. Engagement counts are denormalised onto the document for
32
+ * fast feed sorting; the per-user reaction state ("did I upvote this?")
33
+ * is computed at read time and returned in the `viewer` block.
34
+ */
35
+ export declare const communityPostWireSchema: z.ZodObject<{
36
+ _id: z.ZodString;
37
+ contentKind: z.ZodLiteral<"post">;
38
+ author: z.ZodObject<{
39
+ userId: z.ZodString;
40
+ displayName: z.ZodString;
41
+ avatarUrl: z.ZodOptional<z.ZodString>;
42
+ localName: z.ZodOptional<z.ZodString>;
43
+ }, z.core.$strip>;
44
+ text: z.ZodString;
45
+ images: z.ZodArray<z.ZodObject<{
46
+ url: z.ZodString;
47
+ thumbnailUrl: z.ZodOptional<z.ZodString>;
48
+ width: z.ZodNumber;
49
+ height: z.ZodNumber;
50
+ bytes: z.ZodNumber;
51
+ alt: z.ZodOptional<z.ZodString>;
52
+ }, z.core.$strip>>;
53
+ videos: z.ZodArray<z.ZodObject<{
54
+ url: z.ZodString;
55
+ thumbnailUrl: z.ZodString;
56
+ width: z.ZodNumber;
57
+ height: z.ZodNumber;
58
+ bytes: z.ZodNumber;
59
+ duration: z.ZodNumber;
60
+ }, z.core.$strip>>;
61
+ visibilityLevel: z.ZodEnum<{
62
+ local: "local";
63
+ district: "district";
64
+ state: "state";
65
+ national: "national";
66
+ global: "global";
67
+ }>;
68
+ areaLineage: z.ZodObject<{
69
+ countryId: z.ZodOptional<z.ZodString>;
70
+ stateId: z.ZodOptional<z.ZodString>;
71
+ districtId: z.ZodOptional<z.ZodString>;
72
+ localId: z.ZodOptional<z.ZodString>;
73
+ localName: z.ZodOptional<z.ZodString>;
74
+ }, z.core.$strip>;
75
+ upvoteCount: z.ZodNumber;
76
+ commentCount: z.ZodNumber;
77
+ reactionCounts: z.ZodRecord<z.ZodString, z.ZodNumber>;
78
+ createdAt: z.ZodString;
79
+ editedAt: z.ZodNullable<z.ZodString>;
80
+ deletedAt: z.ZodNullable<z.ZodString>;
81
+ viewer: z.ZodOptional<z.ZodObject<{
82
+ upvoted: z.ZodBoolean;
83
+ reaction: z.ZodNullable<z.ZodString>;
84
+ isAuthor: z.ZodBoolean;
85
+ }, z.core.$strip>>;
86
+ }, z.core.$strip>;
87
+ export type CommunityPostWire = z.infer<typeof communityPostWireSchema>;
88
+ /**
89
+ * What the client sends to `POST /api/v1/community/posts`. The author
90
+ * is taken from the authenticated request; visibility area is resolved
91
+ * server-side from the user's primary area lineage (the client cannot
92
+ * spoof a different area).
93
+ */
94
+ export declare const createPostBodySchema: z.ZodObject<{
95
+ text: z.ZodString;
96
+ images: z.ZodOptional<z.ZodArray<z.ZodObject<{
97
+ url: z.ZodString;
98
+ thumbnailUrl: z.ZodOptional<z.ZodString>;
99
+ width: z.ZodNumber;
100
+ height: z.ZodNumber;
101
+ bytes: z.ZodNumber;
102
+ alt: z.ZodOptional<z.ZodString>;
103
+ }, z.core.$strip>>>;
104
+ videos: z.ZodOptional<z.ZodArray<z.ZodObject<{
105
+ url: z.ZodString;
106
+ thumbnailUrl: z.ZodString;
107
+ width: z.ZodNumber;
108
+ height: z.ZodNumber;
109
+ bytes: z.ZodNumber;
110
+ duration: z.ZodNumber;
111
+ }, z.core.$strip>>>;
112
+ visibilityLevel: z.ZodEnum<{
113
+ local: "local";
114
+ district: "district";
115
+ state: "state";
116
+ national: "national";
117
+ global: "global";
118
+ }>;
119
+ }, z.core.$strip>;
120
+ export type CreatePostBody = z.infer<typeof createPostBodySchema>;
121
+ /**
122
+ * What the client sends to `PATCH /api/v1/community/posts/:id`. Only
123
+ * the text body is editable — media additions / removals require a new
124
+ * post (matches Twitter / FB convention).
125
+ */
126
+ export declare const updatePostBodySchema: z.ZodObject<{
127
+ text: z.ZodString;
128
+ }, z.core.$strip>;
129
+ export type UpdatePostBody = z.infer<typeof updatePostBodySchema>;
130
+ //# sourceMappingURL=post.d.ts.map
@@ -0,0 +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;AAYxB;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB;;;;;iBAWnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAI1E;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuClC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;iBAM/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"}