founder-schema 0.18.0 → 0.20.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/README.md +110 -3
- package/dist/access/permissions.d.ts +3 -3
- package/dist/access/permissions.d.ts.map +1 -1
- package/dist/access/permissions.js.map +1 -1
- package/dist/core/common.d.ts +49 -28
- package/dist/core/common.d.ts.map +1 -1
- package/dist/core/common.js +65 -26
- package/dist/core/common.js.map +1 -1
- package/dist/core/deletion.d.ts +40 -0
- package/dist/core/deletion.d.ts.map +1 -0
- package/dist/core/deletion.js +39 -0
- package/dist/core/deletion.js.map +1 -0
- package/dist/core/limits.d.ts +25 -0
- package/dist/core/limits.d.ts.map +1 -1
- package/dist/core/limits.js +25 -0
- package/dist/core/limits.js.map +1 -1
- package/dist/core/validation.d.ts +13 -0
- package/dist/core/validation.d.ts.map +1 -1
- package/dist/core/validation.js +13 -0
- package/dist/core/validation.js.map +1 -1
- package/dist/domains/audit/audit.d.ts +36 -12
- package/dist/domains/audit/audit.d.ts.map +1 -1
- package/dist/domains/audit/audit.js +9 -10
- package/dist/domains/audit/audit.js.map +1 -1
- package/dist/domains/billing/billing.d.ts +29 -13
- package/dist/domains/billing/billing.d.ts.map +1 -1
- package/dist/domains/billing/billing.js +2 -3
- package/dist/domains/billing/billing.js.map +1 -1
- package/dist/domains/chat/chat.d.ts +19 -5
- package/dist/domains/chat/chat.d.ts.map +1 -1
- package/dist/domains/chat/chat.js +10 -10
- package/dist/domains/chat/chat.js.map +1 -1
- package/dist/domains/communities/communities.d.ts +95 -57
- package/dist/domains/communities/communities.d.ts.map +1 -1
- package/dist/domains/contributions/contributions.d.ts +28 -12
- package/dist/domains/contributions/contributions.d.ts.map +1 -1
- package/dist/domains/contributions/contributions.js +3 -0
- package/dist/domains/contributions/contributions.js.map +1 -1
- package/dist/domains/discover/discover.d.ts +2 -2
- package/dist/domains/feed/feed.d.ts +111 -63
- package/dist/domains/feed/feed.d.ts.map +1 -1
- package/dist/domains/feed/feed.js +3 -0
- package/dist/domains/feed/feed.js.map +1 -1
- package/dist/domains/location/areas.d.ts +338 -0
- package/dist/domains/location/areas.d.ts.map +1 -0
- package/dist/domains/location/areas.js +241 -0
- package/dist/domains/location/areas.js.map +1 -0
- package/dist/domains/location/india.d.ts +31 -123
- package/dist/domains/location/india.d.ts.map +1 -1
- package/dist/domains/location/india.js +98 -64
- package/dist/domains/location/india.js.map +1 -1
- package/dist/domains/media/media.d.ts +22 -0
- package/dist/domains/media/media.d.ts.map +1 -1
- package/dist/domains/media/media.js +20 -0
- package/dist/domains/media/media.js.map +1 -1
- package/dist/domains/members/members.d.ts +26 -9
- package/dist/domains/members/members.d.ts.map +1 -1
- package/dist/domains/members/members.js +9 -10
- package/dist/domains/members/members.js.map +1 -1
- package/dist/domains/membership/membership.d.ts +19 -0
- package/dist/domains/membership/membership.d.ts.map +1 -1
- package/dist/domains/membership/membership.js +10 -0
- package/dist/domains/membership/membership.js.map +1 -1
- package/dist/domains/moderation/moderation.d.ts +8 -2
- package/dist/domains/moderation/moderation.d.ts.map +1 -1
- package/dist/domains/moderation/moderation.js +3 -6
- package/dist/domains/moderation/moderation.js.map +1 -1
- package/dist/domains/notifications/notifications.d.ts +10 -6
- package/dist/domains/notifications/notifications.d.ts.map +1 -1
- package/dist/domains/onboarding/onboarding-answers.d.ts +9 -12
- package/dist/domains/onboarding/onboarding-answers.d.ts.map +1 -1
- package/dist/domains/onboarding/onboarding-answers.js +12 -19
- package/dist/domains/onboarding/onboarding-answers.js.map +1 -1
- package/dist/domains/onboarding/onboarding.d.ts +121 -98
- package/dist/domains/onboarding/onboarding.d.ts.map +1 -1
- package/dist/domains/onboarding/onboarding.js +30 -28
- package/dist/domains/onboarding/onboarding.js.map +1 -1
- package/dist/domains/people/person.d.ts +54 -0
- package/dist/domains/people/person.d.ts.map +1 -0
- package/dist/domains/people/person.js +73 -0
- package/dist/domains/people/person.js.map +1 -0
- package/dist/domains/products/products.d.ts +62 -33
- package/dist/domains/products/products.d.ts.map +1 -1
- package/dist/domains/products/products.js +3 -0
- package/dist/domains/products/products.js.map +1 -1
- package/dist/domains/profile/founder-profile.d.ts +93 -60
- package/dist/domains/profile/founder-profile.d.ts.map +1 -1
- package/dist/domains/profile/founder-profile.js +55 -25
- package/dist/domains/profile/founder-profile.js.map +1 -1
- package/dist/domains/reviews/reviews.d.ts +25 -15
- package/dist/domains/reviews/reviews.d.ts.map +1 -1
- package/dist/domains/support/support.d.ts +47 -10
- package/dist/domains/support/support.d.ts.map +1 -1
- package/dist/domains/support/support.js +4 -2
- package/dist/domains/support/support.js.map +1 -1
- package/dist/domains/team/team.d.ts +9 -3
- package/dist/domains/team/team.d.ts.map +1 -1
- package/dist/domains/team/team.js +3 -6
- package/dist/domains/team/team.js.map +1 -1
- package/dist/index.d.ts +13 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -11
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/account.d.ts +0 -40
- package/dist/account.d.ts.map +0 -1
- package/dist/account.js +0 -39
- package/dist/account.js.map +0 -1
- package/dist/chat.d.ts +0 -187
- package/dist/chat.d.ts.map +0 -1
- package/dist/chat.js +0 -189
- package/dist/chat.js.map +0 -1
- package/dist/common.d.ts +0 -304
- package/dist/common.d.ts.map +0 -1
- package/dist/common.js +0 -340
- package/dist/common.js.map +0 -1
- package/dist/discover.d.ts +0 -245
- package/dist/discover.d.ts.map +0 -1
- package/dist/discover.js +0 -68
- package/dist/discover.js.map +0 -1
- package/dist/errors.d.ts +0 -85
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -89
- package/dist/errors.js.map +0 -1
- package/dist/feed.d.ts +0 -1658
- package/dist/feed.d.ts.map +0 -1
- package/dist/feed.js +0 -623
- package/dist/feed.js.map +0 -1
- package/dist/founder-profile.d.ts +0 -387
- package/dist/founder-profile.d.ts.map +0 -1
- package/dist/founder-profile.js +0 -180
- package/dist/founder-profile.js.map +0 -1
- package/dist/limits.d.ts +0 -76
- package/dist/limits.d.ts.map +0 -1
- package/dist/limits.js +0 -84
- package/dist/limits.js.map +0 -1
- package/dist/onboarding.d.ts +0 -1018
- package/dist/onboarding.d.ts.map +0 -1
- package/dist/onboarding.js +0 -717
- package/dist/onboarding.js.map +0 -1
- package/dist/responses/common.d.ts +0 -167
- package/dist/responses/common.d.ts.map +0 -1
- package/dist/responses/common.js +0 -67
- package/dist/responses/common.js.map +0 -1
- package/dist/responses/index.d.ts +0 -7
- package/dist/responses/index.d.ts.map +0 -1
- package/dist/responses/index.js +0 -7
- package/dist/responses/index.js.map +0 -1
- package/dist/uploads.d.ts +0 -113
- package/dist/uploads.d.ts.map +0 -1
- package/dist/uploads.js +0 -106
- package/dist/uploads.js.map +0 -1
- package/dist/validation.d.ts +0 -136
- package/dist/validation.d.ts.map +0 -1
- package/dist/validation.js +0 -142
- package/dist/validation.js.map +0 -1
package/dist/founder-profile.js
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* founder-schema — The founder profile
|
|
3
|
-
*
|
|
4
|
-
* One member, one profile. The central auth account owns identity (email,
|
|
5
|
-
* verification, deletion); this owns everything Founder Circle shows.
|
|
6
|
-
*
|
|
7
|
-
* @module founder-schema/founder-profile
|
|
8
|
-
*/
|
|
9
|
-
import { z } from 'zod';
|
|
10
|
-
import { chosenUsernameSchema, GOAL_VALUES, goalSchema, httpUrlSchema, industrySchema, locationSchema, optionalTrimmedString, skillSchema, startupStageSchema, usernameSchema, } from './common.js';
|
|
11
|
-
import { ABOUT_MAX, DISPLAY_NAME_MAX, FOUNDED_YEAR_MIN, HEADLINE_MAX, SKILLS_MAX, TEAM_SIZE_MAX, TEAM_SIZE_MIN, VENTURE_NAME_MAX, VENTURE_TAGLINE_MAX, } from './limits.js';
|
|
12
|
-
import { VALIDATION_MESSAGE } from './validation.js';
|
|
13
|
-
// ─── Venture ─────────────────────────────────────────────────────────────────
|
|
14
|
-
/**
|
|
15
|
-
* ⚠ NUMBERS ARE NUMBERS, never coerced. This is a BODY, which arrives as JSON
|
|
16
|
-
* and already carries types. `z.coerce.number()` here accepted `teamSize: true`
|
|
17
|
-
* as 1 and `" "` as 0, and made the schema's input type `unknown`, so a form
|
|
18
|
-
* typed against it could put anything in the field. Coercion belongs to query
|
|
19
|
-
* strings, where everything is text; a form converts its text input before it
|
|
20
|
-
* builds the body.
|
|
21
|
-
*/
|
|
22
|
-
export const ventureSchema = z.object({
|
|
23
|
-
name: z.string().trim().min(1).max(VENTURE_NAME_MAX),
|
|
24
|
-
tagline: optionalTrimmedString(VENTURE_TAGLINE_MAX),
|
|
25
|
-
website: httpUrlSchema.optional(),
|
|
26
|
-
industry: industrySchema,
|
|
27
|
-
stage: startupStageSchema,
|
|
28
|
-
/** Team size including the founder. Optional: a solo pre-idea founder has none to report. */
|
|
29
|
-
teamSize: z.number().int().min(TEAM_SIZE_MIN).max(TEAM_SIZE_MAX).optional(),
|
|
30
|
-
/**
|
|
31
|
-
* Not in the future. The bound is read per parse, never captured once.
|
|
32
|
-
*
|
|
33
|
-
* `.max(new Date().getUTCFullYear())` looks equivalent and is not: it is
|
|
34
|
-
* evaluated when this module is imported, so a server process still up on
|
|
35
|
-
* 1 January rejects the new year until somebody restarts it. The backend's
|
|
36
|
-
* Mongoose model deliberately carries no upper bound for the same reason, a
|
|
37
|
-
* `max` there being frozen at schema construction. This is where the ceiling
|
|
38
|
-
* lives.
|
|
39
|
-
*/
|
|
40
|
-
foundedYear: z
|
|
41
|
-
.number()
|
|
42
|
-
.int()
|
|
43
|
-
.min(FOUNDED_YEAR_MIN)
|
|
44
|
-
.refine((year) => year <= new Date().getUTCFullYear(), {
|
|
45
|
-
error: VALIDATION_MESSAGE.foundedYearFuture,
|
|
46
|
-
})
|
|
47
|
-
.optional(),
|
|
48
|
-
});
|
|
49
|
-
// ─── Profile ─────────────────────────────────────────────────────────────────
|
|
50
|
-
/**
|
|
51
|
-
* The founder's off-platform links. ONE shape: onboarding's contact step picks
|
|
52
|
-
* its three from this, so a link one side knows can never be missing on the
|
|
53
|
-
* other. (It was written twice until 0.2.0, and the profile side lacked
|
|
54
|
-
* Instagram, which onboarding collected.)
|
|
55
|
-
*
|
|
56
|
-
* Defined without a default, because the read side wants one and the write
|
|
57
|
-
* side must not have one; each adds its own.
|
|
58
|
-
*/
|
|
59
|
-
export const founderLinksSchema = z.object({
|
|
60
|
-
linkedin: httpUrlSchema.optional(),
|
|
61
|
-
x: httpUrlSchema.optional(),
|
|
62
|
-
instagram: httpUrlSchema.optional(),
|
|
63
|
-
github: httpUrlSchema.optional(),
|
|
64
|
-
website: httpUrlSchema.optional(),
|
|
65
|
-
});
|
|
66
|
-
/**
|
|
67
|
-
* The profile as the owner sees it. A peer sees the redacted projection
|
|
68
|
-
* (`founderCardSchema`), which is built on the server and never by dropping
|
|
69
|
-
* fields on the client.
|
|
70
|
-
*/
|
|
71
|
-
export const founderProfileSchema = z.object({
|
|
72
|
-
id: z.string(),
|
|
73
|
-
userId: z.string(),
|
|
74
|
-
username: usernameSchema,
|
|
75
|
-
displayName: z.string().trim().min(1).max(DISPLAY_NAME_MAX),
|
|
76
|
-
headline: optionalTrimmedString(HEADLINE_MAX),
|
|
77
|
-
about: optionalTrimmedString(ABOUT_MAX),
|
|
78
|
-
/**
|
|
79
|
-
* Plain `z.url()`, NOT `httpUrlSchema`, and the difference is deliberate.
|
|
80
|
-
*
|
|
81
|
-
* No member can write this field: it appears in no write body, and
|
|
82
|
-
* `public-surface.test.ts` asserts that and will fail the day somebody adds it
|
|
83
|
-
* to a form. So the scheme restriction would be defending a field that takes
|
|
84
|
-
* no member input, while refusing hosts we legitimately serve avatars from,
|
|
85
|
-
* our own dev host among them. A read schema that rejects our own response is
|
|
86
|
-
* a self-inflicted outage.
|
|
87
|
-
*
|
|
88
|
-
* ⚠️ That argument holds only while nothing member-supplied reaches this
|
|
89
|
-
* field. Two sources write an avatar today and NEITHER is a member typing a
|
|
90
|
-
* URL: our own upload path, and the central-auth `user.created` /
|
|
91
|
-
* `user.updated` webhook, which carries the Google OAuth picture. If a
|
|
92
|
-
* "paste a link to your photo" control is ever added, this goes back to
|
|
93
|
-
* `httpUrlSchema` and the ruling behind it is void.
|
|
94
|
-
*/
|
|
95
|
-
avatarUrl: z.url().optional(),
|
|
96
|
-
location: locationSchema.optional(),
|
|
97
|
-
venture: ventureSchema.optional(),
|
|
98
|
-
skills: z.array(skillSchema).max(SKILLS_MAX).default([]),
|
|
99
|
-
goals: z.array(goalSchema).max(GOAL_VALUES.length).default([]),
|
|
100
|
-
links: founderLinksSchema.default({}),
|
|
101
|
-
/** Onboarding is finished and the member is visible in Discover. */
|
|
102
|
-
isOnboarded: z.boolean().default(false),
|
|
103
|
-
/** Member paused their own profile. Hidden from Discover, keeps their data. */
|
|
104
|
-
isActive: z.boolean().default(true),
|
|
105
|
-
createdAt: z.iso.datetime(),
|
|
106
|
-
updatedAt: z.iso.datetime(),
|
|
107
|
-
});
|
|
108
|
-
/**
|
|
109
|
-
* What one founder sees of another in Discover and on a profile page.
|
|
110
|
-
*
|
|
111
|
-
* Built server-side. Keep it a strict subset of `founderProfileSchema` — if a
|
|
112
|
-
* private field ever needs to show here, that is a product decision, not an
|
|
113
|
-
* accident of spreading the full document.
|
|
114
|
-
*/
|
|
115
|
-
export const founderCardSchema = founderProfileSchema.pick({
|
|
116
|
-
id: true,
|
|
117
|
-
username: true,
|
|
118
|
-
displayName: true,
|
|
119
|
-
headline: true,
|
|
120
|
-
avatarUrl: true,
|
|
121
|
-
location: true,
|
|
122
|
-
venture: true,
|
|
123
|
-
skills: true,
|
|
124
|
-
goals: true,
|
|
125
|
-
});
|
|
126
|
-
// ─── Write bodies ────────────────────────────────────────────────────────────
|
|
127
|
-
/**
|
|
128
|
-
* A text field the member is allowed to empty.
|
|
129
|
-
*
|
|
130
|
-
* Three states, and they are deliberately distinct:
|
|
131
|
-
* absent do not touch this field
|
|
132
|
-
* null clear it (the backend turns this into an `$unset`)
|
|
133
|
-
* "" REJECTED
|
|
134
|
-
*
|
|
135
|
-
* The empty string is refused on purpose. A form that forgets to convert a
|
|
136
|
-
* cleared input to `null` then fails loudly at the boundary, instead of being
|
|
137
|
-
* silently dropped and leaving the member staring at text they just deleted.
|
|
138
|
-
* `optionalTrimmedString` does the dropping, which is right for a create body
|
|
139
|
-
* and wrong for a patch.
|
|
140
|
-
*/
|
|
141
|
-
const clearableText = (maxLength) => z.string().trim().min(1, VALIDATION_MESSAGE.clearWithNull).max(maxLength).nullable().optional();
|
|
142
|
-
/**
|
|
143
|
-
* Patch body for the Me tab. Only the keys the member actually changed.
|
|
144
|
-
*
|
|
145
|
-
* ⚠️ Written as its own object ON PURPOSE. Do NOT rebuild it as
|
|
146
|
-
* `founderProfileSchema.pick({...}).partial()`: `.partial()` does not switch
|
|
147
|
-
* off `.default()`, so `skills`, `goals` and `links` would materialise as
|
|
148
|
-
* `[]`, `[]` and `{}` on every request, including an empty one. Under a `$set`
|
|
149
|
-
* that wipes a member's skills and every one of their links the moment they
|
|
150
|
-
* edit their display name. `tsc` cannot see it and the request looks correct in
|
|
151
|
-
* the network tab.
|
|
152
|
-
*
|
|
153
|
-
* The rule this comes from: defaults belong on the READ side. A write body
|
|
154
|
-
* states what the caller sent and nothing else.
|
|
155
|
-
*/
|
|
156
|
-
export const updateFounderProfileBodySchema = z.object({
|
|
157
|
-
displayName: z.string().trim().min(1).max(DISPLAY_NAME_MAX).optional(),
|
|
158
|
-
headline: clearableText(HEADLINE_MAX),
|
|
159
|
-
about: clearableText(ABOUT_MAX),
|
|
160
|
-
/** Carries the whole location; `locationSchema` has no default to fill a gap. */
|
|
161
|
-
location: locationSchema.optional(),
|
|
162
|
-
venture: ventureSchema.optional(),
|
|
163
|
-
skills: z.array(skillSchema).max(SKILLS_MAX).optional(),
|
|
164
|
-
goals: z.array(goalSchema).max(GOAL_VALUES.length).optional(),
|
|
165
|
-
/** Sent whole. To drop one link, send the object without that key. */
|
|
166
|
-
links: founderLinksSchema.optional(),
|
|
167
|
-
});
|
|
168
|
-
/**
|
|
169
|
-
* Username change. Separate from the profile patch because it needs a
|
|
170
|
-
* uniqueness check, and it refuses a reserved handle (`chosenUsernameSchema`).
|
|
171
|
-
*/
|
|
172
|
-
export const updateUsernameBodySchema = z.object({ username: chosenUsernameSchema });
|
|
173
|
-
/** Availability probe behind the username field. */
|
|
174
|
-
export const usernameAvailabilitySchema = z.object({
|
|
175
|
-
username: usernameSchema,
|
|
176
|
-
available: z.boolean(),
|
|
177
|
-
/** Present when unavailable: `taken` or `reserved`. */
|
|
178
|
-
reason: z.enum(['taken', 'reserved']).optional(),
|
|
179
|
-
});
|
|
180
|
-
//# sourceMappingURL=founder-profile.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"founder-profile.js","sourceRoot":"","sources":["../src/founder-profile.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema — The founder profile\n *\n * One member, one profile. The central auth account owns identity (email,\n * verification, deletion); this owns everything Founder Circle shows.\n *\n * @module founder-schema/founder-profile\n */\n\nimport { z } from 'zod';\nimport {\n chosenUsernameSchema,\n GOAL_VALUES,\n goalSchema,\n httpUrlSchema,\n industrySchema,\n locationSchema,\n optionalTrimmedString,\n skillSchema,\n startupStageSchema,\n usernameSchema,\n} from './common.js';\nimport {\n ABOUT_MAX,\n DISPLAY_NAME_MAX,\n FOUNDED_YEAR_MIN,\n HEADLINE_MAX,\n SKILLS_MAX,\n TEAM_SIZE_MAX,\n TEAM_SIZE_MIN,\n VENTURE_NAME_MAX,\n VENTURE_TAGLINE_MAX,\n} from './limits.js';\nimport { VALIDATION_MESSAGE } from './validation.js';\n\n// ─── Venture ─────────────────────────────────────────────────────────────────\n\n/**\n * ⚠ NUMBERS ARE NUMBERS, never coerced. This is a BODY, which arrives as JSON\n * and already carries types. `z.coerce.number()` here accepted `teamSize: true`\n * as 1 and `\" \"` as 0, and made the schema's input type `unknown`, so a form\n * typed against it could put anything in the field. Coercion belongs to query\n * strings, where everything is text; a form converts its text input before it\n * builds the body.\n */\nexport const ventureSchema = z.object({\n name: z.string().trim().min(1).max(VENTURE_NAME_MAX),\n tagline: optionalTrimmedString(VENTURE_TAGLINE_MAX),\n website: httpUrlSchema.optional(),\n industry: industrySchema,\n stage: startupStageSchema,\n /** Team size including the founder. Optional: a solo pre-idea founder has none to report. */\n teamSize: z.number().int().min(TEAM_SIZE_MIN).max(TEAM_SIZE_MAX).optional(),\n /**\n * Not in the future. The bound is read per parse, never captured once.\n *\n * `.max(new Date().getUTCFullYear())` looks equivalent and is not: it is\n * evaluated when this module is imported, so a server process still up on\n * 1 January rejects the new year until somebody restarts it. The backend's\n * Mongoose model deliberately carries no upper bound for the same reason, a\n * `max` there being frozen at schema construction. This is where the ceiling\n * lives.\n */\n foundedYear: z\n .number()\n .int()\n .min(FOUNDED_YEAR_MIN)\n .refine((year) => year <= new Date().getUTCFullYear(), {\n error: VALIDATION_MESSAGE.foundedYearFuture,\n })\n .optional(),\n});\nexport type Venture = z.infer<typeof ventureSchema>;\n\n// ─── Profile ─────────────────────────────────────────────────────────────────\n\n/**\n * The founder's off-platform links. ONE shape: onboarding's contact step picks\n * its three from this, so a link one side knows can never be missing on the\n * other. (It was written twice until 0.2.0, and the profile side lacked\n * Instagram, which onboarding collected.)\n *\n * Defined without a default, because the read side wants one and the write\n * side must not have one; each adds its own.\n */\nexport const founderLinksSchema = z.object({\n linkedin: httpUrlSchema.optional(),\n x: httpUrlSchema.optional(),\n instagram: httpUrlSchema.optional(),\n github: httpUrlSchema.optional(),\n website: httpUrlSchema.optional(),\n});\nexport type FounderLinks = z.infer<typeof founderLinksSchema>;\n\n/**\n * The profile as the owner sees it. A peer sees the redacted projection\n * (`founderCardSchema`), which is built on the server and never by dropping\n * fields on the client.\n */\nexport const founderProfileSchema = z.object({\n id: z.string(),\n userId: z.string(),\n username: usernameSchema,\n displayName: z.string().trim().min(1).max(DISPLAY_NAME_MAX),\n headline: optionalTrimmedString(HEADLINE_MAX),\n about: optionalTrimmedString(ABOUT_MAX),\n /**\n * Plain `z.url()`, NOT `httpUrlSchema`, and the difference is deliberate.\n *\n * No member can write this field: it appears in no write body, and\n * `public-surface.test.ts` asserts that and will fail the day somebody adds it\n * to a form. So the scheme restriction would be defending a field that takes\n * no member input, while refusing hosts we legitimately serve avatars from,\n * our own dev host among them. A read schema that rejects our own response is\n * a self-inflicted outage.\n *\n * ⚠️ That argument holds only while nothing member-supplied reaches this\n * field. Two sources write an avatar today and NEITHER is a member typing a\n * URL: our own upload path, and the central-auth `user.created` /\n * `user.updated` webhook, which carries the Google OAuth picture. If a\n * \"paste a link to your photo\" control is ever added, this goes back to\n * `httpUrlSchema` and the ruling behind it is void.\n */\n avatarUrl: z.url().optional(),\n location: locationSchema.optional(),\n venture: ventureSchema.optional(),\n skills: z.array(skillSchema).max(SKILLS_MAX).default([]),\n goals: z.array(goalSchema).max(GOAL_VALUES.length).default([]),\n links: founderLinksSchema.default({}),\n /** Onboarding is finished and the member is visible in Discover. */\n isOnboarded: z.boolean().default(false),\n /** Member paused their own profile. Hidden from Discover, keeps their data. */\n isActive: z.boolean().default(true),\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\nexport type FounderProfile = z.infer<typeof founderProfileSchema>;\n\n/**\n * What one founder sees of another in Discover and on a profile page.\n *\n * Built server-side. Keep it a strict subset of `founderProfileSchema` — if a\n * private field ever needs to show here, that is a product decision, not an\n * accident of spreading the full document.\n */\nexport const founderCardSchema = founderProfileSchema.pick({\n id: true,\n username: true,\n displayName: true,\n headline: true,\n avatarUrl: true,\n location: true,\n venture: true,\n skills: true,\n goals: true,\n});\nexport type FounderCard = z.infer<typeof founderCardSchema>;\n\n// ─── Write bodies ────────────────────────────────────────────────────────────\n\n/**\n * A text field the member is allowed to empty.\n *\n * Three states, and they are deliberately distinct:\n * absent do not touch this field\n * null clear it (the backend turns this into an `$unset`)\n * \"\" REJECTED\n *\n * The empty string is refused on purpose. A form that forgets to convert a\n * cleared input to `null` then fails loudly at the boundary, instead of being\n * silently dropped and leaving the member staring at text they just deleted.\n * `optionalTrimmedString` does the dropping, which is right for a create body\n * and wrong for a patch.\n */\nconst clearableText = (maxLength: number) =>\n z.string().trim().min(1, VALIDATION_MESSAGE.clearWithNull).max(maxLength).nullable().optional();\n\n/**\n * Patch body for the Me tab. Only the keys the member actually changed.\n *\n * ⚠️ Written as its own object ON PURPOSE. Do NOT rebuild it as\n * `founderProfileSchema.pick({...}).partial()`: `.partial()` does not switch\n * off `.default()`, so `skills`, `goals` and `links` would materialise as\n * `[]`, `[]` and `{}` on every request, including an empty one. Under a `$set`\n * that wipes a member's skills and every one of their links the moment they\n * edit their display name. `tsc` cannot see it and the request looks correct in\n * the network tab.\n *\n * The rule this comes from: defaults belong on the READ side. A write body\n * states what the caller sent and nothing else.\n */\nexport const updateFounderProfileBodySchema = z.object({\n displayName: z.string().trim().min(1).max(DISPLAY_NAME_MAX).optional(),\n headline: clearableText(HEADLINE_MAX),\n about: clearableText(ABOUT_MAX),\n /** Carries the whole location; `locationSchema` has no default to fill a gap. */\n location: locationSchema.optional(),\n venture: ventureSchema.optional(),\n skills: z.array(skillSchema).max(SKILLS_MAX).optional(),\n goals: z.array(goalSchema).max(GOAL_VALUES.length).optional(),\n /** Sent whole. To drop one link, send the object without that key. */\n links: founderLinksSchema.optional(),\n});\nexport type UpdateFounderProfileBody = z.infer<typeof updateFounderProfileBodySchema>;\n\n/**\n * Username change. Separate from the profile patch because it needs a\n * uniqueness check, and it refuses a reserved handle (`chosenUsernameSchema`).\n */\nexport const updateUsernameBodySchema = z.object({ username: chosenUsernameSchema });\nexport type UpdateUsernameBody = z.infer<typeof updateUsernameBodySchema>;\n\n/** Availability probe behind the username field. */\nexport const usernameAvailabilitySchema = z.object({\n username: usernameSchema,\n available: z.boolean(),\n /** Present when unavailable: `taken` or `reserved`. */\n reason: z.enum(['taken', 'reserved']).optional(),\n});\nexport type UsernameAvailability = z.infer<typeof usernameAvailabilitySchema>;\n"]}
|
package/dist/limits.d.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* founder-schema — Every length, size and count limit, by name
|
|
3
|
-
*
|
|
4
|
-
* ONE PLACE FOR EVERY NUMBER a client and the server must agree on. Before this,
|
|
5
|
-
* the limits lived inline (`.max(80)`, `.max(1000)`) where nothing else could
|
|
6
|
-
* read them, so the web client re-typed each one for its counters and the
|
|
7
|
-
* backend re-typed them as Mongoose `maxlength`. Three copies of one number is
|
|
8
|
-
* how the image alt text came to be 280 here and 500 in the backend.
|
|
9
|
-
*
|
|
10
|
-
* The rule from 0.2.0: a schema uses one of these constants, a consumer imports
|
|
11
|
-
* the same constant, and nobody writes the digits again.
|
|
12
|
-
*
|
|
13
|
-
* Imports nothing, so any module here can use it without a cycle. Limits that
|
|
14
|
-
* already had a name in their own module (POST_MAX_BODY_CHARS, POLL_*,
|
|
15
|
-
* USERNAME_*, INTERESTS_*, MIN_AGE_YEARS...) stay where they are and keep their
|
|
16
|
-
* names; this file holds the ones that had none.
|
|
17
|
-
*
|
|
18
|
-
* ⚠️ Lowering a limit is a breaking change for stored data: a value that was
|
|
19
|
-
* valid when written fails the next edit. Raise freely; lower deliberately.
|
|
20
|
-
*
|
|
21
|
-
* @module founder-schema/limits
|
|
22
|
-
*/
|
|
23
|
-
export declare const DISPLAY_NAME_MAX = 80;
|
|
24
|
-
export declare const HEADLINE_MAX = 120;
|
|
25
|
-
export declare const ABOUT_MAX = 1000;
|
|
26
|
-
/** Skills a member may list. Discover filters on them. */
|
|
27
|
-
export declare const SKILLS_MAX = 8;
|
|
28
|
-
/** Goals a member must pick at onboarding. The list itself caps the maximum. */
|
|
29
|
-
export declare const GOALS_MIN = 1;
|
|
30
|
-
export declare const CITY_MAX = 80;
|
|
31
|
-
export declare const STATE_MAX = 80;
|
|
32
|
-
export declare const COUNTRY_MAX = 80;
|
|
33
|
-
export declare const VENTURE_NAME_MAX = 120;
|
|
34
|
-
export declare const VENTURE_TAGLINE_MAX = 160;
|
|
35
|
-
/** Team size including the founder. */
|
|
36
|
-
export declare const TEAM_SIZE_MIN = 1;
|
|
37
|
-
export declare const TEAM_SIZE_MAX = 100000;
|
|
38
|
-
/** Earliest founding year accepted. The ceiling is "this year", read per parse. */
|
|
39
|
-
export declare const FOUNDED_YEAR_MIN = 1900;
|
|
40
|
-
/**
|
|
41
|
-
* Longest URL a member may TYPE. Applied by `httpUrlSchema` itself, so every
|
|
42
|
-
* member URL carries it: profile links, a venture website.
|
|
43
|
-
*
|
|
44
|
-
* ⚠ NOT applied to URLs the server reads from elsewhere (a link preview's
|
|
45
|
-
* page or image), which use `safeUrlSchema`: a 314-character CDN image URL is
|
|
46
|
-
* ordinary, and one of them would otherwise fail a whole feed page.
|
|
47
|
-
*/
|
|
48
|
-
export declare const LINK_URL_MAX = 300;
|
|
49
|
-
/** Author-supplied image description. The backend's stored copy uses this too. */
|
|
50
|
-
export declare const MEDIA_ALT_MAX = 280;
|
|
51
|
-
export declare const LINK_PREVIEW_TITLE_MAX = 200;
|
|
52
|
-
export declare const LINK_PREVIEW_DESCRIPTION_MAX = 500;
|
|
53
|
-
/** The free-text note on a report. */
|
|
54
|
-
export declare const REPORT_NOTE_MAX = 1000;
|
|
55
|
-
/**
|
|
56
|
-
* Largest file accepted for upload: 10 MB.
|
|
57
|
-
*
|
|
58
|
-
* Checked on BOTH sides and for different reasons. The server refuses a bigger
|
|
59
|
-
* object when it is attached. The client checks before uploading, because a
|
|
60
|
-
* presigned PUT caps the content type but not the size, so a member on a phone
|
|
61
|
-
* connection would otherwise watch a 40 MB upload finish and then fail.
|
|
62
|
-
*/
|
|
63
|
-
export declare const UPLOAD_MAX_BYTES: number;
|
|
64
|
-
/** Values one Discover multi-select filter may carry (`?skill=a&skill=b`). */
|
|
65
|
-
export declare const DISCOVER_FILTER_VALUES_MAX = 10;
|
|
66
|
-
/** Discover's free-text inputs: the name search, city and country. */
|
|
67
|
-
export declare const DISCOVER_TEXT_MAX = 80;
|
|
68
|
-
/** Page size bounds for every cursor-paged list. */
|
|
69
|
-
export declare const PAGE_SIZE_MAX = 50;
|
|
70
|
-
export declare const PAGE_SIZE_DEFAULT = 20;
|
|
71
|
-
/**
|
|
72
|
-
* Members one participants lookup may name. Bounded so the lookup cannot be
|
|
73
|
-
* used to page through the directory.
|
|
74
|
-
*/
|
|
75
|
-
export declare const CHAT_PARTICIPANTS_MAX = 100;
|
|
76
|
-
//# sourceMappingURL=limits.d.ts.map
|
package/dist/limits.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,eAAO,MAAM,SAAS,OAAO,CAAC;AAC9B,0DAA0D;AAC1D,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,gFAAgF;AAChF,eAAO,MAAM,SAAS,IAAI,CAAC;AAI3B,eAAO,MAAM,QAAQ,KAAK,CAAC;AAC3B,eAAO,MAAM,SAAS,KAAK,CAAC;AAC5B,eAAO,MAAM,WAAW,KAAK,CAAC;AAI9B,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,uCAAuC;AACvC,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,aAAa,SAAU,CAAC;AACrC,mFAAmF;AACnF,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAIrC;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,MAAM,CAAC;AAIhC,kFAAkF;AAClF,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAChD,sCAAsC;AACtC,eAAO,MAAM,eAAe,OAAO,CAAC;AAIpC;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,QAAmB,CAAC;AAIjD,8EAA8E;AAC9E,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAC7C,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,oDAAoD;AACpD,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAIpC;;;GAGG;AACH,eAAO,MAAM,qBAAqB,MAAM,CAAC"}
|
package/dist/limits.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* founder-schema — Every length, size and count limit, by name
|
|
3
|
-
*
|
|
4
|
-
* ONE PLACE FOR EVERY NUMBER a client and the server must agree on. Before this,
|
|
5
|
-
* the limits lived inline (`.max(80)`, `.max(1000)`) where nothing else could
|
|
6
|
-
* read them, so the web client re-typed each one for its counters and the
|
|
7
|
-
* backend re-typed them as Mongoose `maxlength`. Three copies of one number is
|
|
8
|
-
* how the image alt text came to be 280 here and 500 in the backend.
|
|
9
|
-
*
|
|
10
|
-
* The rule from 0.2.0: a schema uses one of these constants, a consumer imports
|
|
11
|
-
* the same constant, and nobody writes the digits again.
|
|
12
|
-
*
|
|
13
|
-
* Imports nothing, so any module here can use it without a cycle. Limits that
|
|
14
|
-
* already had a name in their own module (POST_MAX_BODY_CHARS, POLL_*,
|
|
15
|
-
* USERNAME_*, INTERESTS_*, MIN_AGE_YEARS...) stay where they are and keep their
|
|
16
|
-
* names; this file holds the ones that had none.
|
|
17
|
-
*
|
|
18
|
-
* ⚠️ Lowering a limit is a breaking change for stored data: a value that was
|
|
19
|
-
* valid when written fails the next edit. Raise freely; lower deliberately.
|
|
20
|
-
*
|
|
21
|
-
* @module founder-schema/limits
|
|
22
|
-
*/
|
|
23
|
-
// ─── Profile ─────────────────────────────────────────────────────────────────
|
|
24
|
-
export const DISPLAY_NAME_MAX = 80;
|
|
25
|
-
export const HEADLINE_MAX = 120;
|
|
26
|
-
export const ABOUT_MAX = 1000;
|
|
27
|
-
/** Skills a member may list. Discover filters on them. */
|
|
28
|
-
export const SKILLS_MAX = 8;
|
|
29
|
-
/** Goals a member must pick at onboarding. The list itself caps the maximum. */
|
|
30
|
-
export const GOALS_MIN = 1;
|
|
31
|
-
// ─── Location ────────────────────────────────────────────────────────────────
|
|
32
|
-
export const CITY_MAX = 80;
|
|
33
|
-
export const STATE_MAX = 80;
|
|
34
|
-
export const COUNTRY_MAX = 80;
|
|
35
|
-
// ─── Venture ─────────────────────────────────────────────────────────────────
|
|
36
|
-
export const VENTURE_NAME_MAX = 120;
|
|
37
|
-
export const VENTURE_TAGLINE_MAX = 160;
|
|
38
|
-
/** Team size including the founder. */
|
|
39
|
-
export const TEAM_SIZE_MIN = 1;
|
|
40
|
-
export const TEAM_SIZE_MAX = 100_000;
|
|
41
|
-
/** Earliest founding year accepted. The ceiling is "this year", read per parse. */
|
|
42
|
-
export const FOUNDED_YEAR_MIN = 1900;
|
|
43
|
-
// ─── Links ───────────────────────────────────────────────────────────────────
|
|
44
|
-
/**
|
|
45
|
-
* Longest URL a member may TYPE. Applied by `httpUrlSchema` itself, so every
|
|
46
|
-
* member URL carries it: profile links, a venture website.
|
|
47
|
-
*
|
|
48
|
-
* ⚠ NOT applied to URLs the server reads from elsewhere (a link preview's
|
|
49
|
-
* page or image), which use `safeUrlSchema`: a 314-character CDN image URL is
|
|
50
|
-
* ordinary, and one of them would otherwise fail a whole feed page.
|
|
51
|
-
*/
|
|
52
|
-
export const LINK_URL_MAX = 300;
|
|
53
|
-
// ─── Feed and moderation ─────────────────────────────────────────────────────
|
|
54
|
-
/** Author-supplied image description. The backend's stored copy uses this too. */
|
|
55
|
-
export const MEDIA_ALT_MAX = 280;
|
|
56
|
-
export const LINK_PREVIEW_TITLE_MAX = 200;
|
|
57
|
-
export const LINK_PREVIEW_DESCRIPTION_MAX = 500;
|
|
58
|
-
/** The free-text note on a report. */
|
|
59
|
-
export const REPORT_NOTE_MAX = 1000;
|
|
60
|
-
// ─── Uploads ─────────────────────────────────────────────────────────────────
|
|
61
|
-
/**
|
|
62
|
-
* Largest file accepted for upload: 10 MB.
|
|
63
|
-
*
|
|
64
|
-
* Checked on BOTH sides and for different reasons. The server refuses a bigger
|
|
65
|
-
* object when it is attached. The client checks before uploading, because a
|
|
66
|
-
* presigned PUT caps the content type but not the size, so a member on a phone
|
|
67
|
-
* connection would otherwise watch a 40 MB upload finish and then fail.
|
|
68
|
-
*/
|
|
69
|
-
export const UPLOAD_MAX_BYTES = 10 * 1024 * 1024;
|
|
70
|
-
// ─── Lists and search ────────────────────────────────────────────────────────
|
|
71
|
-
/** Values one Discover multi-select filter may carry (`?skill=a&skill=b`). */
|
|
72
|
-
export const DISCOVER_FILTER_VALUES_MAX = 10;
|
|
73
|
-
/** Discover's free-text inputs: the name search, city and country. */
|
|
74
|
-
export const DISCOVER_TEXT_MAX = 80;
|
|
75
|
-
/** Page size bounds for every cursor-paged list. */
|
|
76
|
-
export const PAGE_SIZE_MAX = 50;
|
|
77
|
-
export const PAGE_SIZE_DEFAULT = 20;
|
|
78
|
-
// ─── Chat ────────────────────────────────────────────────────────────────────
|
|
79
|
-
/**
|
|
80
|
-
* Members one participants lookup may name. Bounded so the lookup cannot be
|
|
81
|
-
* used to page through the directory.
|
|
82
|
-
*/
|
|
83
|
-
export const CHAT_PARTICIPANTS_MAX = 100;
|
|
84
|
-
//# sourceMappingURL=limits.js.map
|
package/dist/limits.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAChC,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC;AAC9B,0DAA0D;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,gFAAgF;AAChF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC;AAE3B,gFAAgF;AAEhF,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAC3B,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC;AAC5B,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAE9B,gFAAgF;AAEhF,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AACvC,uCAAuC;AACvC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC;AACrC,mFAAmF;AACnF,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAErC,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAEhC,gFAAgF;AAEhF,kFAAkF;AAClF,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AACjC,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAC1C,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAChD,sCAAsC;AACtC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAEpC,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEjD,gFAAgF;AAEhF,8EAA8E;AAC9E,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAC7C,sEAAsE;AACtE,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,oDAAoD;AACpD,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAChC,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAEpC,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC","sourcesContent":["/**\n * founder-schema — Every length, size and count limit, by name\n *\n * ONE PLACE FOR EVERY NUMBER a client and the server must agree on. Before this,\n * the limits lived inline (`.max(80)`, `.max(1000)`) where nothing else could\n * read them, so the web client re-typed each one for its counters and the\n * backend re-typed them as Mongoose `maxlength`. Three copies of one number is\n * how the image alt text came to be 280 here and 500 in the backend.\n *\n * The rule from 0.2.0: a schema uses one of these constants, a consumer imports\n * the same constant, and nobody writes the digits again.\n *\n * Imports nothing, so any module here can use it without a cycle. Limits that\n * already had a name in their own module (POST_MAX_BODY_CHARS, POLL_*,\n * USERNAME_*, INTERESTS_*, MIN_AGE_YEARS...) stay where they are and keep their\n * names; this file holds the ones that had none.\n *\n * ⚠️ Lowering a limit is a breaking change for stored data: a value that was\n * valid when written fails the next edit. Raise freely; lower deliberately.\n *\n * @module founder-schema/limits\n */\n\n// ─── Profile ─────────────────────────────────────────────────────────────────\n\nexport const DISPLAY_NAME_MAX = 80;\nexport const HEADLINE_MAX = 120;\nexport const ABOUT_MAX = 1000;\n/** Skills a member may list. Discover filters on them. */\nexport const SKILLS_MAX = 8;\n/** Goals a member must pick at onboarding. The list itself caps the maximum. */\nexport const GOALS_MIN = 1;\n\n// ─── Location ────────────────────────────────────────────────────────────────\n\nexport const CITY_MAX = 80;\nexport const STATE_MAX = 80;\nexport const COUNTRY_MAX = 80;\n\n// ─── Venture ─────────────────────────────────────────────────────────────────\n\nexport const VENTURE_NAME_MAX = 120;\nexport const VENTURE_TAGLINE_MAX = 160;\n/** Team size including the founder. */\nexport const TEAM_SIZE_MIN = 1;\nexport const TEAM_SIZE_MAX = 100_000;\n/** Earliest founding year accepted. The ceiling is \"this year\", read per parse. */\nexport const FOUNDED_YEAR_MIN = 1900;\n\n// ─── Links ───────────────────────────────────────────────────────────────────\n\n/**\n * Longest URL a member may TYPE. Applied by `httpUrlSchema` itself, so every\n * member URL carries it: profile links, a venture website.\n *\n * ⚠ NOT applied to URLs the server reads from elsewhere (a link preview's\n * page or image), which use `safeUrlSchema`: a 314-character CDN image URL is\n * ordinary, and one of them would otherwise fail a whole feed page.\n */\nexport const LINK_URL_MAX = 300;\n\n// ─── Feed and moderation ─────────────────────────────────────────────────────\n\n/** Author-supplied image description. The backend's stored copy uses this too. */\nexport const MEDIA_ALT_MAX = 280;\nexport const LINK_PREVIEW_TITLE_MAX = 200;\nexport const LINK_PREVIEW_DESCRIPTION_MAX = 500;\n/** The free-text note on a report. */\nexport const REPORT_NOTE_MAX = 1000;\n\n// ─── Uploads ─────────────────────────────────────────────────────────────────\n\n/**\n * Largest file accepted for upload: 10 MB.\n *\n * Checked on BOTH sides and for different reasons. The server refuses a bigger\n * object when it is attached. The client checks before uploading, because a\n * presigned PUT caps the content type but not the size, so a member on a phone\n * connection would otherwise watch a 40 MB upload finish and then fail.\n */\nexport const UPLOAD_MAX_BYTES = 10 * 1024 * 1024;\n\n// ─── Lists and search ────────────────────────────────────────────────────────\n\n/** Values one Discover multi-select filter may carry (`?skill=a&skill=b`). */\nexport const DISCOVER_FILTER_VALUES_MAX = 10;\n/** Discover's free-text inputs: the name search, city and country. */\nexport const DISCOVER_TEXT_MAX = 80;\n/** Page size bounds for every cursor-paged list. */\nexport const PAGE_SIZE_MAX = 50;\nexport const PAGE_SIZE_DEFAULT = 20;\n\n// ─── Chat ────────────────────────────────────────────────────────────────────\n\n/**\n * Members one participants lookup may name. Bounded so the lookup cannot be\n * used to page through the directory.\n */\nexport const CHAT_PARTICIPANTS_MAX = 100;\n"]}
|