founder-schema 0.12.0 → 0.13.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 (40) hide show
  1. package/README.md +20 -0
  2. package/dist/core/errors.d.ts +5 -1
  3. package/dist/core/errors.d.ts.map +1 -1
  4. package/dist/core/errors.js +7 -0
  5. package/dist/core/errors.js.map +1 -1
  6. package/dist/core/responses.d.ts +4 -0
  7. package/dist/core/responses.d.ts.map +1 -1
  8. package/dist/domains/billing/billing.d.ts +1 -0
  9. package/dist/domains/billing/billing.d.ts.map +1 -1
  10. package/dist/domains/billing/billing.js +11 -1
  11. package/dist/domains/billing/billing.js.map +1 -1
  12. package/dist/domains/communities/communities.d.ts +2 -0
  13. package/dist/domains/communities/communities.d.ts.map +1 -1
  14. package/dist/domains/communities/communities.js +7 -0
  15. package/dist/domains/communities/communities.js.map +1 -1
  16. package/dist/domains/contributions/contributions.d.ts +2 -2
  17. package/dist/domains/contributions/contributions.d.ts.map +1 -1
  18. package/dist/domains/contributions/contributions.js +3 -2
  19. package/dist/domains/contributions/contributions.js.map +1 -1
  20. package/dist/domains/membership/membership.d.ts +1 -0
  21. package/dist/domains/membership/membership.d.ts.map +1 -1
  22. package/dist/domains/membership/membership.js +6 -0
  23. package/dist/domains/membership/membership.js.map +1 -1
  24. package/dist/domains/onboarding/onboarding.d.ts +0 -10
  25. package/dist/domains/onboarding/onboarding.d.ts.map +1 -1
  26. package/dist/domains/onboarding/onboarding.js +9 -3
  27. package/dist/domains/onboarding/onboarding.js.map +1 -1
  28. package/dist/domains/profile/founder-profile.d.ts +9 -3
  29. package/dist/domains/profile/founder-profile.d.ts.map +1 -1
  30. package/dist/domains/profile/founder-profile.js +6 -3
  31. package/dist/domains/profile/founder-profile.js.map +1 -1
  32. package/dist/domains/support/support.d.ts +16 -1
  33. package/dist/domains/support/support.d.ts.map +1 -1
  34. package/dist/domains/support/support.js +5 -0
  35. package/dist/domains/support/support.js.map +1 -1
  36. package/dist/index.d.ts +1 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -1
  39. package/dist/index.js.map +1 -1
  40. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding.js","sourceRoot":"","sources":["../../../src/domains/onboarding/onboarding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema — Onboarding: steps, enums, and the two shapes of the answers\n *\n * ONE LIST DEFINES THE FLOW, AND IT IS DERIVED. Each step's fields are a pick\n * of the finish body (`ONBOARDING_STEP_SCHEMAS`), and `FOUNDER_ONBOARDING_STEPS`\n * is built FROM those picks: its `fields`, and even whether a step may be\n * skipped, come from the schema rather than from a second hand-written list.\n * GymMonk arrived at one list after keeping two in sync by hand, where a step\n * could exist with no title or, worse, no validation gate at all; until 0.2.0\n * this file still wrote the field lists twice.\n *\n * TWO SHAPES, ONE SET OF RULES. A half-filled form legitimately holds `null`\n * for a choice nobody has made yet; the finalize body only ever sees completed\n * answers. So the rules are written once and expressed over both shapes:\n * `onboardingFormSchema` for work in progress and `completeOnboardingBodySchema`\n * for the end. Letting those two drift is how a wizard says a step is optional\n * and then answers 422 at Finish.\n *\n * NO COPY IN HERE. Step titles and help lines are translation KEYS\n * (`titleKey`, `helpKey`), Jansathi's rule for every config string: an English\n * sentence in a shared package is a sentence every other language has to match\n * by wording. A topic category is named by its `key`, which the client words\n * (0.6.0 dropped its `labelKey`: the web, English-only since 2026-10-06, read\n * nothing from it).\n *\n * @module founder-schema/domains/onboarding\n */\n\nimport { z } from 'zod';\nimport {\n displayNameSchema,\n GENDER_VALUES,\n GOAL_VALUES,\n genderSchema,\n goalSchema,\n INDUSTRY_VALUES,\n industrySchema,\n locationSchema,\n objectIdSchema,\n optionalTrimmedString,\n phoneSchema,\n SKILL_VALUES,\n STARTUP_STAGE_VALUES,\n skillSchema,\n startupStageSchema,\n} from '../../core/common.js';\nimport {\n ABOUT_MAX,\n CITY_MAX,\n COUNTRY_MAX,\n DISPLAY_NAME_MAX,\n GOALS_MIN,\n HEADLINE_MAX,\n LINK_URL_MAX,\n SKILLS_MAX,\n STATE_MAX,\n TEAM_SIZE_MAX,\n VENTURE_NAME_MAX,\n} from '../../core/limits.js';\nimport { VALIDATION_MESSAGE } from '../../core/validation.js';\nimport { founderLinksSchema, ventureSchema } from '../profile/founder-profile.js';\n\n// ─── Age ─────────────────────────────────────────────────────────────────────\n\n/**\n * 18, ruled by the user 2026-09-21. Under-18 would pull in parental-consent\n * duties under the DPDP Act, which is a different and larger problem than a\n * validation rule.\n *\n * ⚠️ The SERVER refuses at finalize. This schema exists so the member sees a\n * useful message; it is not the gate.\n */\nexport const MIN_AGE_YEARS = 18;\n/** A sanity ceiling, not a product rule. Catches a mistyped year. */\nexport const MAX_AGE_YEARS = 120;\n\n/**\n * Whole years completed, by the calendar.\n *\n * ⚠️ NOT `elapsedMs / (365.25 * day)`, which is what the sibling product uses.\n * That approximation reads 17.9986 at the start of somebody's eighteenth\n * birthday and only crosses 18 about halfway through the day, so it refuses\n * them for the half of their birthday they are most likely to be signing up on.\n * Measured: it disagrees with the calendar on all 400 of the next 400 days.\n * An age gate is exactly the place an approximation is not good enough.\n */\nexport function ageInYears(isoDate: string, now: Date = new Date()): number {\n // ⚠️ A STRING, `YYYY-MM-DD`, not a `Date`. This is a wire contract, so it\n // takes the wire type. The backend is the obvious caller and the backend\n // holds a `Date`, so it must format first; passing the Date straight in used\n // to fail with `isoDate.split is not a function`, which says nothing useful.\n // Naming the fix costs one line and saves the next person the detour.\n if (typeof isoDate !== 'string') {\n throw new TypeError(\n 'ageInYears expects a YYYY-MM-DD string, not a Date. Format it first, e.g. date.toISOString().slice(0, 10).',\n );\n }\n const [y, m, d] = isoDate.split('-').map(Number) as [number, number, number];\n let age = now.getUTCFullYear() - y;\n const monthNow = now.getUTCMonth() + 1;\n if (monthNow < m || (monthNow === m && now.getUTCDate() < d)) age -= 1;\n return age;\n}\n\n/** A calendar date with no time component, `YYYY-MM-DD`. */\nexport const isoDateSchema = z\n .string()\n .trim()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, VALIDATION_MESSAGE.dateInvalid);\nexport type IsoDate = z.infer<typeof isoDateSchema>;\n\n/** True only for a date that exists. Rejects 2026-02-30 and 2026-13-01. */\nfunction isRealDate(iso: string): boolean {\n const [y, m, d] = iso.split('-').map(Number) as [number, number, number];\n if (m < 1 || m > 12 || d < 1) return false;\n const asDate = new Date(Date.UTC(y, m - 1, d));\n return (\n asDate.getUTCFullYear() === y && asDate.getUTCMonth() === m - 1 && asDate.getUTCDate() === d\n );\n}\n\n/**\n * Date of birth, with the age gate applied per parse.\n *\n * ⚠️ THE CLIENT IS NOT THE GATE. This schema exists so the member sees a useful\n * message, and the server must refuse the same dates at finalize regardless.\n * The sibling dating product validates the identical rule on its client and\n * still shipped a defect where an under-age date of birth produced a live,\n * discoverable profile, because the client was the only thing checking.\n */\nexport const dateOfBirthSchema = isoDateSchema\n .refine(isRealDate, { error: VALIDATION_MESSAGE.dobInvalid })\n .refine((v) => ageInYears(v) >= MIN_AGE_YEARS, { error: VALIDATION_MESSAGE.dobUnderAge })\n .refine((v) => ageInYears(v) <= MAX_AGE_YEARS, { error: VALIDATION_MESSAGE.dobTooOld });\nexport type DateOfBirth = z.infer<typeof dateOfBirthSchema>;\n\n// ─── Business ────────────────────────────────────────────────────────────────\n\nexport const BUSINESS_TYPE_VALUES = ['startup', 'sme', 'enterprise'] as const;\nexport const businessTypeSchema = z.enum(BUSINESS_TYPE_VALUES);\nexport type BusinessType = z.infer<typeof businessTypeSchema>;\n\n// ─── Topics: the shared vocabulary ───────────────────────────────────────────────────────────────\n\n/**\n * ONE vocabulary, used TWICE: a member picks these as their `interests`, and a\n * post carries them as its `topics`. That is what makes relevance an index\n * lookup rather than a guess, and it is why this list is not called \"interests\"\n * - naming it for one of its two jobs would have invited a second list for the\n * other, which is the mistake this package has already made once with goals.\n * (User's ruling via hary, 2026-09-21.)\n *\n * Deliberately DISTINCT from two neighbours that will otherwise collect the\n * same words:\n *\n * industry what your company does\n * skills what you can do\n * interests what you want to read about\n *\n * If the copy does not keep them apart, members fill all three identically and\n * every one of them stops telling us anything.\n *\n * A closed list, consistent with industry, skill and stage, for the reason\n * already written beside those: free text means two people typing \"growth\" and\n * \"Growth Marketing\" never match, and matching is the entire point. The cost is\n * that adding an interest needs a publish.\n *\n * Tuned down from the dating product's 246, which is mostly dating material.\n * Values reuse its exact strings wherever one existed, so its Hindi\n * translations can be lifted across.\n *\n * ⚠️ Stored per member. Append only; removing a value orphans data.\n */\nexport const TOPIC_VALUES = [\n // Career growth\n 'mentoring',\n 'leadership',\n 'networking',\n 'public_speaking',\n 'teaching',\n 'hiring_talent',\n 'personal_branding',\n 'career_transition',\n 'remote_work',\n // Innovation and tech\n 'ai_ml',\n 'blockchain',\n 'crypto_web3',\n 'robotics',\n 'data_science',\n 'cybersecurity',\n 'game_dev',\n 'ux_design',\n 'app_development',\n 'open_source',\n 'electronics',\n 'space_exploration',\n 'green_tech',\n 'deeptech',\n 'no_code',\n // Business\n 'entrepreneurship',\n 'investing',\n 'stock_trading',\n 'personal_finance',\n 'fundraising',\n 'marketing',\n 'sales',\n 'consulting',\n 'ecommerce',\n 'retail',\n 'real_estate',\n 'supply_chain',\n 'product_management',\n 'growth',\n 'b2b_saas',\n 'd2c',\n // Personal development\n 'meditation',\n 'journaling',\n 'self_improvement',\n 'productivity',\n 'reading',\n 'online_courses',\n 'philosophy',\n 'psychology',\n 'therapy',\n 'sleep_optimization',\n 'gym',\n 'yoga',\n // Creative\n 'photography',\n 'writing',\n 'graphic_design',\n 'filmmaking',\n 'digital_art',\n 'content_creation',\n 'blogging',\n 'vlogging',\n 'podcasts',\n 'animation',\n 'music_production',\n // Impact and community\n 'volunteering',\n 'ngo_work',\n 'environmental',\n 'women_empowerment',\n 'community_service',\n 'social_enterprise',\n 'education_access',\n] as const;\nexport const topicSchema = z.enum(TOPIC_VALUES);\nexport type Topic = z.infer<typeof topicSchema>;\n\n/**\n * The grouping the picker renders.\n *\n * ⚠️ `TOPIC_VALUES` above is the single source of truth and this is typed\n * against it, so a typo here is a compile error rather than a chip that renders\n * and can never be selected. The dating product keeps a categorised list and a\n * flat list side by side and they have already drifted apart by two values;\n * a test in this package asserts these two agree exactly, in both directions.\n */\nexport const TOPIC_CATEGORY_KEYS = [\n 'career',\n 'tech',\n 'business',\n 'growth',\n 'creative',\n 'impact',\n] as const;\nexport type TopicCategoryKey = (typeof TOPIC_CATEGORY_KEYS)[number];\n\n/**\n * One group of the picker: its `key` (the client words it) and its topics.\n * Breaking in 0.6.0: no `labelKey`.\n */\nexport interface TopicCategory {\n key: TopicCategoryKey;\n values: readonly Topic[];\n}\n\nconst topicCategory = (key: TopicCategoryKey, values: readonly Topic[]): TopicCategory => ({\n key,\n values,\n});\n\nexport const TOPIC_CATEGORIES: readonly TopicCategory[] = [\n topicCategory('career', [\n 'mentoring',\n 'leadership',\n 'networking',\n 'public_speaking',\n 'teaching',\n 'hiring_talent',\n 'personal_branding',\n 'career_transition',\n 'remote_work',\n ]),\n topicCategory('tech', [\n 'ai_ml',\n 'blockchain',\n 'crypto_web3',\n 'robotics',\n 'data_science',\n 'cybersecurity',\n 'game_dev',\n 'ux_design',\n 'app_development',\n 'open_source',\n 'electronics',\n 'space_exploration',\n 'green_tech',\n 'deeptech',\n 'no_code',\n ]),\n topicCategory('business', [\n 'entrepreneurship',\n 'investing',\n 'stock_trading',\n 'personal_finance',\n 'fundraising',\n 'marketing',\n 'sales',\n 'consulting',\n 'ecommerce',\n 'retail',\n 'real_estate',\n 'supply_chain',\n 'product_management',\n 'growth',\n 'b2b_saas',\n 'd2c',\n ]),\n topicCategory('growth', [\n 'meditation',\n 'journaling',\n 'self_improvement',\n 'productivity',\n 'reading',\n 'online_courses',\n 'philosophy',\n 'psychology',\n 'therapy',\n 'sleep_optimization',\n 'gym',\n 'yoga',\n ]),\n topicCategory('creative', [\n 'photography',\n 'writing',\n 'graphic_design',\n 'filmmaking',\n 'digital_art',\n 'content_creation',\n 'blogging',\n 'vlogging',\n 'podcasts',\n 'animation',\n 'music_production',\n ]),\n topicCategory('impact', [\n 'volunteering',\n 'ngo_work',\n 'environmental',\n 'women_empowerment',\n 'community_service',\n 'social_enterprise',\n 'education_access',\n ]),\n];\n\n/**\n * How many a member must pick. A minimum exists because these drive feed\n * relevance and zero of them means no relevance at all.\n *\n * ⚠️ If 3 turns out to be hard to reach against this list, that is a signal\n * about the LIST, not about the minimum. The sibling product enforces no\n * minimum at all, and its own field config says \"pick up to 10\" while every\n * screen and schema enforces 20.\n */\nexport const INTERESTS_MIN = 3;\nexport const INTERESTS_MAX = 10;\n\n// ─── The step keys ───────────────────────────────────────────────────────────\n\n/**\n * The step keys, in order, as a literal union, so a consumer can key a table by\n * step and have TypeScript insist on every one. Before 0.2.0 `key` was a plain\n * string and the web client kept its own copy of this list to get the same\n * check; a test there held the two together. Now there is one list.\n */\nexport const ONBOARDING_STEP_KEYS = [\n 'identity',\n 'contact',\n 'location',\n 'goals',\n 'interests',\n 'business',\n 'guidelines',\n] as const;\nexport type OnboardingStepKey = (typeof ONBOARDING_STEP_KEYS)[number];\n\n// ─── Guidelines ──────────────────────────────────────────────────────────────\n\n/**\n * The community guidelines a member agrees to at the last step, by version.\n *\n * The finish body accepts THIS version and no other: an old tab still showing\n * last month's text cannot record agreement to text it never displayed, and\n * `'whatever'` is not a version. Until 0.2.0 any non-empty string passed, and\n * the web client held this constant on its own.\n *\n * ⚠ Changing the guidelines text means bumping this, in the same publish.\n * Every member who agreed to an earlier version keeps that version on their\n * profile; that record is the point.\n */\nexport const GUIDELINES_VERSION = '2026-10-03' as const;\nexport const guidelinesVersionSchema = z.literal(GUIDELINES_VERSION, {\n error: VALIDATION_MESSAGE.guidelinesOutdated,\n});\n\n// ─── Contact ─────────────────────────────────────────────────────────────────\n\n/**\n * The links the contact step collects, picked from the profile's own links so\n * the two cannot disagree on what a link is. The phone is `phoneSchema`: ten\n * digits, stored raw with no country code, on the account rather than here.\n */\nexport const contactLinksSchema = founderLinksSchema.pick({\n linkedin: true,\n x: true,\n instagram: true,\n});\nexport type ContactLinks = z.infer<typeof contactLinksSchema>;\n\n/** A team size has at most this many digits: `TEAM_SIZE_MAX` written out. */\nexport const TEAM_SIZE_DIGITS_MAX = String(TEAM_SIZE_MAX).length;\n\n// ─── The form, mid-flight: the draft each step saves ──────────────────────────\n\n/**\n * The answers so far, keyed by the finish body's own field names: what each\n * step SAVES (`PATCH /onboarding`, merged per field), what `GET` hands back\n * to resume, and so the only keys a draft may hold\n * (`ONBOARDING_DRAFT_KEYS`).\n *\n * RAW, on purpose: a draft is what the member TYPED, not what Finish will send.\n * A half-typed link is ordinary text, a team size is digits as typed, and every\n * choice is `null` until made (\"not answered\" is not \"answered with nothing\").\n * Nothing here is required; whether a member may FINISH is\n * `completeOnboardingBodySchema`'s decision, and the client builds that body\n * from these answers.\n *\n * Screens may hold a different shape on top of this one (the web draws first\n * and last name as two fields and joins them into `displayName`). Derive that\n * type from `OnboardingForm` rather than writing it out, so a field added here\n * reaches every screen.\n *\n * A stored draft is UNTRUSTED when it comes back: an older client, or another\n * one, wrote it, and the server stores values opaquely. Read it with\n * `readOnboardingDraft`, never by casting.\n */\nexport const onboardingFormSchema = z.object({\n displayName: z.string().max(DISPLAY_NAME_MAX),\n gender: genderSchema.nullable(),\n /** `YYYY-MM-DD` once complete; whatever has been typed until then. */\n dateOfBirth: z.string(),\n headline: z.string().max(HEADLINE_MAX),\n about: z.string().max(ABOUT_MAX),\n /**\n * The completed upload's id (`media`, purpose `avatar`). Allowed in the form,\n * and NEVER restored by `readOnboardingDraft`: an upload not attached within\n * `MEDIA_UNATTACHED_TTL_HOURS` is deleted, so an id from an older draft would\n * fail at Finish, on the last screen, about a photo picked days ago. Clients\n * hold it for the visit and do not save it.\n */\n avatarMediaId: objectIdSchema.nullable(),\n skills: z.array(skillSchema).max(SKILLS_MAX),\n\n /** As typed; the finish body takes `phoneSchema`'s ten digits. */\n phone: z.string(),\n /** As typed; the finish body takes full `https://` URLs. */\n links: z.object({\n linkedin: z.string().max(LINK_URL_MAX),\n x: z.string().max(LINK_URL_MAX),\n instagram: z.string().max(LINK_URL_MAX),\n }),\n\n /** `null` until the member opens the location step, and when they skip it. */\n location: z\n .object({\n city: z.string().max(CITY_MAX),\n state: z.string().max(STATE_MAX),\n country: z.string().max(COUNTRY_MAX),\n })\n .nullable(),\n\n goals: z.array(goalSchema).max(GOAL_VALUES.length),\n interests: z.array(topicSchema).max(INTERESTS_MAX),\n\n /**\n * Always present; empty until started. Onboarding does not ask for a\n * tagline (the profile does, later), so the draft has none.\n */\n venture: z.object({\n name: z.string().max(VENTURE_NAME_MAX),\n website: z.string().max(LINK_URL_MAX),\n industry: industrySchema.nullable(),\n stage: startupStageSchema.nullable(),\n /** Digits as typed, at most `TEAM_SIZE_DIGITS_MAX`; the body sends a number. */\n teamSize: z.string().max(TEAM_SIZE_DIGITS_MAX),\n }),\n businessType: businessTypeSchema.nullable(),\n\n /** The guidelines text the member agreed to, or `null`. */\n guidelinesVersion: z.string().nullable(),\n});\nexport type OnboardingForm = z.infer<typeof onboardingFormSchema>;\n\n// ─── Reading a stored draft back ─────────────────────────────────────────────\n\n/** Longest date of birth worth keeping from a draft: `YYYY-MM-DD`. */\nconst DATE_INPUT_MAX = 10;\n\n/** Longest phone number worth keeping from a draft, as typed with spaces. */\nconst PHONE_INPUT_MAX = 20;\n\n/** Text, cut to its limit; anything that is not text is \"not answered\". */\nconst draftText = (max: number) =>\n z\n .string()\n .catch('')\n .transform((v) => v.slice(0, max));\n\n/** One of a vocabulary, or `null` (\"not answered\"). */\nconst draftChoice = <T extends readonly [string, ...string[]]>(values: T) =>\n z.enum(values).nullable().catch(null);\n\n/**\n * Items of a vocabulary, deduplicated and capped. Unknown items (a value since\n * retired, or junk) are dropped one by one, so the rest of the answer survives.\n */\nconst draftList = <T extends readonly [string, ...string[]]>(values: T, max: number) =>\n z\n .array(z.unknown())\n .catch([])\n .transform((items) => {\n const allowed = new Set<string>(values);\n const kept = items.filter((v): v is T[number] => typeof v === 'string' && allowed.has(v));\n return [...new Set(kept)].slice(0, max);\n });\n\n/** An object of the given fields, or `null` when the draft holds none. */\nconst draftObject = <S extends z.ZodRawShape>(shape: S) =>\n z\n .record(z.string(), z.unknown())\n .nullable()\n .catch(null)\n .pipe(z.union([z.null(), z.object(shape)]));\n\nconst draftReaderSchema = z.object({\n displayName: draftText(DISPLAY_NAME_MAX),\n gender: draftChoice(GENDER_VALUES),\n dateOfBirth: draftText(DATE_INPUT_MAX),\n headline: draftText(HEADLINE_MAX),\n about: draftText(ABOUT_MAX),\n avatarMediaId: z\n .unknown()\n .optional()\n .transform(() => null),\n skills: draftList(SKILL_VALUES, SKILLS_MAX),\n phone: draftText(PHONE_INPUT_MAX),\n links: draftObject({\n linkedin: draftText(LINK_URL_MAX),\n x: draftText(LINK_URL_MAX),\n instagram: draftText(LINK_URL_MAX),\n }).transform((links) => links ?? { linkedin: '', x: '', instagram: '' }),\n location: draftObject({\n city: draftText(CITY_MAX),\n state: draftText(STATE_MAX),\n country: draftText(COUNTRY_MAX),\n }),\n goals: draftList(GOAL_VALUES, GOAL_VALUES.length),\n interests: draftList(TOPIC_VALUES, INTERESTS_MAX),\n venture: draftObject({\n name: draftText(VENTURE_NAME_MAX),\n website: draftText(LINK_URL_MAX),\n industry: draftChoice(INDUSTRY_VALUES),\n stage: draftChoice(STARTUP_STAGE_VALUES),\n teamSize: z\n .string()\n .catch('')\n .transform((v) => v.replace(/\\D/g, '').slice(0, TEAM_SIZE_DIGITS_MAX)),\n }).transform((venture) => venture ?? { ...EMPTY_ONBOARDING_VENTURE }),\n businessType: draftChoice(BUSINESS_TYPE_VALUES),\n /** Agreement to an OLDER text is not agreement to this one. */\n guidelinesVersion: z\n .unknown()\n .optional()\n .transform((v) => (v === GUIDELINES_VERSION ? GUIDELINES_VERSION : null)),\n});\n\n/** The business step before anything is chosen. */\nexport const EMPTY_ONBOARDING_VENTURE: OnboardingForm['venture'] = {\n name: '',\n website: '',\n industry: null,\n stage: null,\n teamSize: '',\n};\n\n/**\n * A stored draft as an `OnboardingForm`, FIELD BY FIELD.\n *\n * Every field is checked against its own vocabulary and cut to its own limit;\n * one that does not fit becomes \"not answered\" (`''`, `null`, `[]`) and the\n * rest of the draft survives. Never coerced into a different answer: a value\n * outside a vocabulary is dropped, not mapped to the nearest one. A photo\n * is never restored (see `avatarMediaId`), and agreement only counts for the\n * CURRENT guidelines.\n *\n * It fills in no answer the member did not give: a blank country stays blank.\n * Whatever a screen shows by default is that screen's choice.\n */\nexport function readOnboardingDraft(draft: unknown): OnboardingForm {\n const source = draft && typeof draft === 'object' && !Array.isArray(draft) ? draft : {};\n return draftReaderSchema.parse(source);\n}\n\n// ─── The finalize body ───────────────────────────────────────────────────────\n\n/**\n * What the client sends to finish. Completed answers only.\n *\n * ⚠️ EVERY OPTIONAL FIELD HERE MUST BE ABSENT WHEN UNANSWERED, never a default\n * standing in for one. The sibling gym product sent `bloodGroup ?? 'O+'`, so\n * every member who skipped the question was recorded as O-positive: a real\n * answer, indistinguishable from one somebody gave, sitting on a screen staff\n * would read in an emergency. Absent has to stay absent.\n *\n * ⚠️ AND THIS IS NOT THE GATE EITHER. The server re-checks the age and refuses\n * at finalize. `isOnboarded` may be set here and nowhere else: four of the\n * profile's partial indexes are gated on it, so a half-built profile carrying\n * it true appears in Discover half-built.\n *\n * Location, venture and links are the profile's own shapes, not copies: the\n * copies are how the profile model came to lack Instagram.\n */\nexport const completeOnboardingBodySchema = z.object({\n // Plain bounds, no custom message: `too_small` with minimum 1 already says\n // \"required\", and the client words it in the member's language.\n displayName: displayNameSchema,\n /**\n * ⚠️ NO `username` HERE, and its absence is deliberate.\n *\n * It used to be required, and that was a defect: no onboarding step collects\n * one, the design draws no screen for one, and it was not even on the\n * in-progress form, so a finalize could never have succeeded. Found by\n * checking every finalize-required field against the step list; a test now\n * asserts that relationship in both directions.\n *\n * The handle is DERIVED SERVER-SIDE at finalize and edited later from the Me\n * tab, which is what the product describes. That also makes the collision\n * case kinder: a server deriving a handle can suffix it and move on, whereas\n * a member who picked one six steps ago can only be told, at the end, that\n * step one failed.\n */\n gender: genderSchema,\n dateOfBirth: dateOfBirthSchema,\n headline: optionalTrimmedString(HEADLINE_MAX),\n about: optionalTrimmedString(ABOUT_MAX),\n /**\n * A completed avatar upload (`media`, purpose `avatar`). The server attaches\n * it inside the same transaction that creates the profile, so a refused\n * Finish leaves the upload unattached (and swept), never half-used.\n */\n avatarMediaId: objectIdSchema.optional(),\n\n phone: phoneSchema,\n links: contactLinksSchema.optional(),\n\n /** Absent when the member skipped the step or refused the permission. */\n location: locationSchema.optional(),\n\n goals: z.array(goalSchema).min(GOALS_MIN).max(GOAL_VALUES.length),\n interests: z.array(topicSchema).min(INTERESTS_MIN).max(INTERESTS_MAX),\n skills: z.array(skillSchema).max(SKILLS_MAX).optional(),\n\n /**\n * Absent when the member skipped the business step. The profile's venture\n * without `foundedYear`, which onboarding does not ask; the Me tab does.\n */\n venture: ventureSchema.omit({ foundedYear: true }).optional(),\n businessType: businessTypeSchema.optional(),\n\n /**\n * The version of the guidelines this member read: `GUIDELINES_VERSION`,\n * exactly.\n *\n * A version and not a boolean, and the server stamps the time. A boolean says\n * somebody agreed; a version and a timestamp say WHAT they agreed to and\n * WHEN, which is the only form worth anything the day the text changes or a\n * moderation decision is disputed.\n */\n guidelinesVersion: guidelinesVersionSchema,\n});\nexport type CompleteOnboardingBody = z.infer<typeof completeOnboardingBodySchema>;\n/** What a form may hand to the finish body before parsing. */\nexport type CompleteOnboardingBodyInput = z.input<typeof completeOnboardingBodySchema>;\n\n// ─── The steps ───────────────────────────────────────────────────────────────\n\n/**\n * Each step's slice of the finish body, picked FROM it, so a client validating\n * \"may I leave this step\" and the server validating the finish apply the very\n * same rules. A copy would drift, and the drift shows up as a wizard that lets\n * a step pass and a finish that refuses it, on the last screen.\n *\n * THIS IS THE ONE PLACE A STEP'S FIELDS ARE WRITTEN. `FOUNDER_ONBOARDING_STEPS`\n * below reads them from here. A test asserts that every finish field belongs to\n * exactly one step.\n *\n * These validate the FINISH shape (skipped = absent), not the in-progress form:\n * a client maps its form state to the slice first. The server does not run them\n * on a draft save, because a half-answered step must be storable.\n */\nexport const ONBOARDING_STEP_SCHEMAS = {\n identity: completeOnboardingBodySchema.pick({\n displayName: true,\n gender: true,\n dateOfBirth: true,\n headline: true,\n about: true,\n avatarMediaId: true,\n // Here because ruling D8 folded the design's orphan \"title, achievements,\n // skills\" screen into step one. It was on no step until 0.2.0, which made\n // it the one finish field no step owned.\n skills: true,\n }),\n contact: completeOnboardingBodySchema.pick({ phone: true, links: true }),\n location: completeOnboardingBodySchema.pick({ location: true }),\n goals: completeOnboardingBodySchema.pick({ goals: true }),\n interests: completeOnboardingBodySchema.pick({ interests: true }),\n business: completeOnboardingBodySchema.pick({ venture: true, businessType: true }),\n guidelines: completeOnboardingBodySchema.pick({ guidelinesVersion: true }),\n} as const satisfies Record<OnboardingStepKey, z.ZodObject>;\n\n/** One step's slice, parsed: `OnboardingStepBody<'contact'>` is `{ phone, links? }`. */\nexport type OnboardingStepBody<K extends OnboardingStepKey> = z.infer<\n (typeof ONBOARDING_STEP_SCHEMAS)[K]\n>;\n\n/** A finish-body field name. */\nexport type OnboardingField = keyof CompleteOnboardingBody;\n\n/**\n * One step of the wizard, as a client renders it.\n *\n * `fields` is what gates leaving this step: a field that appears in no step is\n * unreachable twice over, because Continue will not surface its error and the\n * final submit's jump-to-the-bad-step finds no step to jump to and leaves the\n * last screen dead.\n */\nexport interface OnboardingStepConfig {\n /** Stable identifier. Safe for analytics and for a resume cursor, unlike an index. */\n key: OnboardingStepKey;\n /** Translation keys. The words live in the client's message files. */\n titleKey: `onboarding.steps.${OnboardingStepKey}.title`;\n helpKey: `onboarding.steps.${OnboardingStepKey}.help`;\n /** The step's slice of the finish body, in schema order. */\n fields: readonly OnboardingField[];\n /**\n * False when the whole step may be passed without answering anything.\n * DERIVED: a step is optional exactly when its slice accepts an empty\n * object, so \"skippable\" can never disagree with what the finish accepts.\n */\n required: boolean;\n}\n\nexport const FOUNDER_ONBOARDING_STEPS: readonly OnboardingStepConfig[] = ONBOARDING_STEP_KEYS.map(\n (key): OnboardingStepConfig => {\n const slice = ONBOARDING_STEP_SCHEMAS[key];\n return {\n key,\n titleKey: `onboarding.steps.${key}.title`,\n helpKey: `onboarding.steps.${key}.help`,\n fields: Object.keys(slice.shape) as OnboardingField[],\n required: !slice.safeParse({}).success,\n };\n },\n);\n\nexport const ONBOARDING_TOTAL_STEPS = FOUNDER_ONBOARDING_STEPS.length;\n\n/** Fields gating each step, in step order. Read from the same picks. */\nexport const ONBOARDING_STEP_FIELDS: readonly (readonly OnboardingField[])[] =\n FOUNDER_ONBOARDING_STEPS.map((s) => s.fields);\n\n/** What finishing answers: the new profile's id and the handle derived for it. */\nexport const completeOnboardingResponseSchema = z.object({\n id: z.string(),\n username: z.string(),\n});\nexport type CompleteOnboardingResponse = z.infer<typeof completeOnboardingResponseSchema>;\n\n// ─── The resume cursor ───────────────────────────────────────────────────────\n\n/**\n * The keys a draft may hold: exactly the in-progress form's fields.\n *\n * ⚠ The server writes each key as a dot path (`draft.<key>`). Unchecked, a key\n * holding a dot writes somewhere nested the form never asked for, and the\n * collection fills with whatever a client invents. Until 0.2.0 the backend\n * kept its own copy of this list and DROPPED unknown keys without a word; now a\n * draft carrying one is refused, with the key in the issue's path.\n */\nexport const onboardingDraftKeySchema = onboardingFormSchema.keyof();\nexport const ONBOARDING_DRAFT_KEYS = onboardingDraftKeySchema.options;\nexport type OnboardingDraftKey = z.infer<typeof onboardingDraftKeySchema>;\n\n/**\n * Where the member got to, kept in its own collection, separate from the\n * profile.\n *\n * `step` is a flat index into `FOUNDER_ONBOARDING_STEPS`, not a `(step, sub)`\n * pair: one number is what lets a member start on the web and resume elsewhere,\n * provided both ends agree on the encoding.\n *\n * The draft's KEYS come from the form; its VALUES are opaque on purpose. A\n * half-answered step must be storable even though it would fail the finish,\n * and everything in it is re-validated strictly at finalize.\n *\n * `partialRecord`, not `record`: in Zod 4 an enum-keyed `z.record` demands\n * every key, and a draft holds whichever steps the member has reached.\n */\nexport const onboardingDraftSchema = z.partialRecord(onboardingDraftKeySchema, z.unknown());\nexport type OnboardingDraft = z.infer<typeof onboardingDraftSchema>;\n\nexport const onboardingProgressSchema = z.object({\n step: z.number().int().min(0).max(ONBOARDING_TOTAL_STEPS),\n draft: onboardingDraftSchema.optional(),\n});\nexport type OnboardingProgress = z.infer<typeof onboardingProgressSchema>;\n\n/**\n * `PATCH` body: any subset of the cursor, merged server-side. No defaults.\n * `step` may equal `ONBOARDING_TOTAL_STEPS`: \"past the last step\", which the\n * client sends on its way to finish.\n */\nexport const onboardingProgressUpdateSchema = z.object({\n step: z.number().int().min(0).max(ONBOARDING_TOTAL_STEPS).optional(),\n draft: onboardingDraftSchema.optional(),\n});\nexport type OnboardingProgressUpdate = z.infer<typeof onboardingProgressUpdateSchema>;\n\n/**\n * What the client reads on return, from `GET` and from every `PATCH`.\n *\n * ⚠️ `onboarded` is the gate and it comes from the profile, not from the\n * cursor: a finished member on a new device must be recognised even when the\n * cursor row is gone, and a cursor that failed to load must never make an\n * unfinished member look finished.\n */\nexport const onboardingStatusSchema = z.object({\n onboarded: z.boolean(),\n step: z.number().int().min(0).max(ONBOARDING_TOTAL_STEPS),\n draft: onboardingDraftSchema.optional(),\n});\nexport type OnboardingStatus = z.infer<typeof onboardingStatusSchema>;\n"]}
1
+ {"version":3,"file":"onboarding.js","sourceRoot":"","sources":["../../../src/domains/onboarding/onboarding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema — Onboarding: steps, enums, and the two shapes of the answers\n *\n * ONE LIST DEFINES THE FLOW, AND IT IS DERIVED. Each step's fields are a pick\n * of the finish body (`ONBOARDING_STEP_SCHEMAS`), and `FOUNDER_ONBOARDING_STEPS`\n * is built FROM those picks: its `fields`, and even whether a step may be\n * skipped, come from the schema rather than from a second hand-written list.\n * GymMonk arrived at one list after keeping two in sync by hand, where a step\n * could exist with no title or, worse, no validation gate at all; until 0.2.0\n * this file still wrote the field lists twice.\n *\n * TWO SHAPES, ONE SET OF RULES. A half-filled form legitimately holds `null`\n * for a choice nobody has made yet; the finalize body only ever sees completed\n * answers. So the rules are written once and expressed over both shapes:\n * `onboardingFormSchema` for work in progress and `completeOnboardingBodySchema`\n * for the end. Letting those two drift is how a wizard says a step is optional\n * and then answers 422 at Finish.\n *\n * NO COPY IN HERE. Step titles and help lines are translation KEYS\n * (`titleKey`, `helpKey`), Jansathi's rule for every config string: an English\n * sentence in a shared package is a sentence every other language has to match\n * by wording. A topic category is named by its `key`, which the client words\n * (0.6.0 dropped its `labelKey`: the web, English-only since 2026-10-06, read\n * nothing from it).\n *\n * @module founder-schema/domains/onboarding\n */\n\nimport { z } from 'zod';\nimport {\n displayNameSchema,\n GENDER_VALUES,\n GOAL_VALUES,\n genderSchema,\n goalSchema,\n INDUSTRY_VALUES,\n industrySchema,\n locationSchema,\n objectIdSchema,\n optionalTrimmedString,\n phoneSchema,\n SKILL_VALUES,\n STARTUP_STAGE_VALUES,\n skillSchema,\n startupStageSchema,\n} from '../../core/common.js';\nimport {\n ABOUT_MAX,\n CITY_MAX,\n COUNTRY_MAX,\n DISPLAY_NAME_MAX,\n GOALS_MIN,\n HEADLINE_MAX,\n LINK_URL_MAX,\n SKILLS_MAX,\n STATE_MAX,\n TEAM_SIZE_MAX,\n VENTURE_NAME_MAX,\n} from '../../core/limits.js';\nimport { VALIDATION_MESSAGE } from '../../core/validation.js';\nimport { founderLinksSchema, ventureSchema } from '../profile/founder-profile.js';\n\n// ─── Age ─────────────────────────────────────────────────────────────────────\n\n/**\n * 18, ruled by the user 2026-09-21. Under-18 would pull in parental-consent\n * duties under the DPDP Act, which is a different and larger problem than a\n * validation rule.\n *\n * ⚠️ The SERVER refuses at finalize. This schema exists so the member sees a\n * useful message; it is not the gate.\n */\nexport const MIN_AGE_YEARS = 18;\n/** A sanity ceiling, not a product rule. Catches a mistyped year. */\nexport const MAX_AGE_YEARS = 120;\n\n/**\n * Whole years completed, by the calendar.\n *\n * ⚠️ NOT `elapsedMs / (365.25 * day)`, which is what the sibling product uses.\n * That approximation reads 17.9986 at the start of somebody's eighteenth\n * birthday and only crosses 18 about halfway through the day, so it refuses\n * them for the half of their birthday they are most likely to be signing up on.\n * Measured: it disagrees with the calendar on all 400 of the next 400 days.\n * An age gate is exactly the place an approximation is not good enough.\n */\n/** India Standard Time, UTC+05:30, with no daylight saving. */\nconst INDIA_OFFSET_MS = (5 * 60 + 30) * 60 * 1000;\n\nexport function ageInYears(isoDate: string, now: Date = new Date()): number {\n // ⚠️ A STRING, `YYYY-MM-DD`, not a `Date`. This is a wire contract, so it\n // takes the wire type. The backend is the obvious caller and the backend\n // holds a `Date`, so it must format first; passing the Date straight in used\n // to fail with `isoDate.split is not a function`, which says nothing useful.\n // Naming the fix costs one line and saves the next person the detour.\n if (typeof isoDate !== 'string') {\n throw new TypeError(\n 'ageInYears expects a YYYY-MM-DD string, not a Date. Format it first, e.g. date.toISOString().slice(0, 10).',\n );\n }\n const [y, m, d] = isoDate.split('-').map(Number) as [number, number, number];\n // The date TODAY IS IN INDIA (0.13.0), where the members are: a birthday\n // begins at midnight there, not five and a half hours later at UTC's\n // midnight. India keeps one offset all year.\n const today = new Date(now.getTime() + INDIA_OFFSET_MS);\n let age = today.getUTCFullYear() - y;\n const monthNow = today.getUTCMonth() + 1;\n if (monthNow < m || (monthNow === m && today.getUTCDate() < d)) age -= 1;\n return age;\n}\n\n/** A calendar date with no time component, `YYYY-MM-DD`. */\nexport const isoDateSchema = z\n .string()\n .trim()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, VALIDATION_MESSAGE.dateInvalid);\nexport type IsoDate = z.infer<typeof isoDateSchema>;\n\n/** True only for a date that exists. Rejects 2026-02-30 and 2026-13-01. */\nfunction isRealDate(iso: string): boolean {\n const [y, m, d] = iso.split('-').map(Number) as [number, number, number];\n if (m < 1 || m > 12 || d < 1) return false;\n const asDate = new Date(Date.UTC(y, m - 1, d));\n return (\n asDate.getUTCFullYear() === y && asDate.getUTCMonth() === m - 1 && asDate.getUTCDate() === d\n );\n}\n\n/**\n * Date of birth, with the age gate applied per parse.\n *\n * ⚠️ THE CLIENT IS NOT THE GATE. This schema exists so the member sees a useful\n * message, and the server must refuse the same dates at finalize regardless.\n * The sibling dating product validates the identical rule on its client and\n * still shipped a defect where an under-age date of birth produced a live,\n * discoverable profile, because the client was the only thing checking.\n */\nexport const dateOfBirthSchema = isoDateSchema\n .refine(isRealDate, { error: VALIDATION_MESSAGE.dobInvalid })\n .refine((v) => ageInYears(v) >= MIN_AGE_YEARS, { error: VALIDATION_MESSAGE.dobUnderAge })\n .refine((v) => ageInYears(v) <= MAX_AGE_YEARS, { error: VALIDATION_MESSAGE.dobTooOld });\nexport type DateOfBirth = z.infer<typeof dateOfBirthSchema>;\n\n// ─── Business ────────────────────────────────────────────────────────────────\n\nexport const BUSINESS_TYPE_VALUES = ['startup', 'sme', 'enterprise'] as const;\nexport const businessTypeSchema = z.enum(BUSINESS_TYPE_VALUES);\nexport type BusinessType = z.infer<typeof businessTypeSchema>;\n\n// ─── Topics: the shared vocabulary ───────────────────────────────────────────────────────────────\n\n/**\n * ONE vocabulary, used TWICE: a member picks these as their `interests`, and a\n * post carries them as its `topics`. That is what makes relevance an index\n * lookup rather than a guess, and it is why this list is not called \"interests\"\n * - naming it for one of its two jobs would have invited a second list for the\n * other, which is the mistake this package has already made once with goals.\n * (User's ruling via hary, 2026-09-21.)\n *\n * Deliberately DISTINCT from two neighbours that will otherwise collect the\n * same words:\n *\n * industry what your company does\n * skills what you can do\n * interests what you want to read about\n *\n * If the copy does not keep them apart, members fill all three identically and\n * every one of them stops telling us anything.\n *\n * A closed list, consistent with industry, skill and stage, for the reason\n * already written beside those: free text means two people typing \"growth\" and\n * \"Growth Marketing\" never match, and matching is the entire point. The cost is\n * that adding an interest needs a publish.\n *\n * Tuned down from the dating product's 246, which is mostly dating material.\n * Values reuse its exact strings wherever one existed, so its Hindi\n * translations can be lifted across.\n *\n * ⚠️ Stored per member. Append only; removing a value orphans data.\n */\nexport const TOPIC_VALUES = [\n // Career growth\n 'mentoring',\n 'leadership',\n 'networking',\n 'public_speaking',\n 'teaching',\n 'hiring_talent',\n 'personal_branding',\n 'career_transition',\n 'remote_work',\n // Innovation and tech\n 'ai_ml',\n 'blockchain',\n 'crypto_web3',\n 'robotics',\n 'data_science',\n 'cybersecurity',\n 'game_dev',\n 'ux_design',\n 'app_development',\n 'open_source',\n 'electronics',\n 'space_exploration',\n 'green_tech',\n 'deeptech',\n 'no_code',\n // Business\n 'entrepreneurship',\n 'investing',\n 'stock_trading',\n 'personal_finance',\n 'fundraising',\n 'marketing',\n 'sales',\n 'consulting',\n 'ecommerce',\n 'retail',\n 'real_estate',\n 'supply_chain',\n 'product_management',\n 'growth',\n 'b2b_saas',\n 'd2c',\n // Personal development\n 'meditation',\n 'journaling',\n 'self_improvement',\n 'productivity',\n 'reading',\n 'online_courses',\n 'philosophy',\n 'psychology',\n 'therapy',\n 'sleep_optimization',\n 'gym',\n 'yoga',\n // Creative\n 'photography',\n 'writing',\n 'graphic_design',\n 'filmmaking',\n 'digital_art',\n 'content_creation',\n 'blogging',\n 'vlogging',\n 'podcasts',\n 'animation',\n 'music_production',\n // Impact and community\n 'volunteering',\n 'ngo_work',\n 'environmental',\n 'women_empowerment',\n 'community_service',\n 'social_enterprise',\n 'education_access',\n] as const;\nexport const topicSchema = z.enum(TOPIC_VALUES);\nexport type Topic = z.infer<typeof topicSchema>;\n\n/**\n * The grouping the picker renders.\n *\n * ⚠️ `TOPIC_VALUES` above is the single source of truth and this is typed\n * against it, so a typo here is a compile error rather than a chip that renders\n * and can never be selected. The dating product keeps a categorised list and a\n * flat list side by side and they have already drifted apart by two values;\n * a test in this package asserts these two agree exactly, in both directions.\n */\nexport const TOPIC_CATEGORY_KEYS = [\n 'career',\n 'tech',\n 'business',\n 'growth',\n 'creative',\n 'impact',\n] as const;\nexport type TopicCategoryKey = (typeof TOPIC_CATEGORY_KEYS)[number];\n\n/**\n * One group of the picker: its `key` (the client words it) and its topics.\n * Breaking in 0.6.0: no `labelKey`.\n */\nexport interface TopicCategory {\n key: TopicCategoryKey;\n values: readonly Topic[];\n}\n\nconst topicCategory = (key: TopicCategoryKey, values: readonly Topic[]): TopicCategory => ({\n key,\n values,\n});\n\nexport const TOPIC_CATEGORIES: readonly TopicCategory[] = [\n topicCategory('career', [\n 'mentoring',\n 'leadership',\n 'networking',\n 'public_speaking',\n 'teaching',\n 'hiring_talent',\n 'personal_branding',\n 'career_transition',\n 'remote_work',\n ]),\n topicCategory('tech', [\n 'ai_ml',\n 'blockchain',\n 'crypto_web3',\n 'robotics',\n 'data_science',\n 'cybersecurity',\n 'game_dev',\n 'ux_design',\n 'app_development',\n 'open_source',\n 'electronics',\n 'space_exploration',\n 'green_tech',\n 'deeptech',\n 'no_code',\n ]),\n topicCategory('business', [\n 'entrepreneurship',\n 'investing',\n 'stock_trading',\n 'personal_finance',\n 'fundraising',\n 'marketing',\n 'sales',\n 'consulting',\n 'ecommerce',\n 'retail',\n 'real_estate',\n 'supply_chain',\n 'product_management',\n 'growth',\n 'b2b_saas',\n 'd2c',\n ]),\n topicCategory('growth', [\n 'meditation',\n 'journaling',\n 'self_improvement',\n 'productivity',\n 'reading',\n 'online_courses',\n 'philosophy',\n 'psychology',\n 'therapy',\n 'sleep_optimization',\n 'gym',\n 'yoga',\n ]),\n topicCategory('creative', [\n 'photography',\n 'writing',\n 'graphic_design',\n 'filmmaking',\n 'digital_art',\n 'content_creation',\n 'blogging',\n 'vlogging',\n 'podcasts',\n 'animation',\n 'music_production',\n ]),\n topicCategory('impact', [\n 'volunteering',\n 'ngo_work',\n 'environmental',\n 'women_empowerment',\n 'community_service',\n 'social_enterprise',\n 'education_access',\n ]),\n];\n\n/**\n * How many a member must pick. A minimum exists because these drive feed\n * relevance and zero of them means no relevance at all.\n *\n * ⚠️ If 3 turns out to be hard to reach against this list, that is a signal\n * about the LIST, not about the minimum. The sibling product enforces no\n * minimum at all, and its own field config says \"pick up to 10\" while every\n * screen and schema enforces 20.\n */\nexport const INTERESTS_MIN = 3;\nexport const INTERESTS_MAX = 10;\n\n// ─── The step keys ───────────────────────────────────────────────────────────\n\n/**\n * The step keys, in order, as a literal union, so a consumer can key a table by\n * step and have TypeScript insist on every one. Before 0.2.0 `key` was a plain\n * string and the web client kept its own copy of this list to get the same\n * check; a test there held the two together. Now there is one list.\n */\nexport const ONBOARDING_STEP_KEYS = [\n 'identity',\n 'contact',\n 'location',\n 'goals',\n 'interests',\n 'business',\n 'guidelines',\n] as const;\nexport type OnboardingStepKey = (typeof ONBOARDING_STEP_KEYS)[number];\n\n// ─── Guidelines ──────────────────────────────────────────────────────────────\n\n/**\n * The community guidelines a member agrees to at the last step, by version.\n *\n * The finish body accepts THIS version and no other: an old tab still showing\n * last month's text cannot record agreement to text it never displayed, and\n * `'whatever'` is not a version. Until 0.2.0 any non-empty string passed, and\n * the web client held this constant on its own.\n *\n * ⚠ Changing the guidelines text means bumping this, in the same publish.\n * Every member who agreed to an earlier version keeps that version on their\n * profile; that record is the point.\n */\nexport const GUIDELINES_VERSION = '2026-10-03' as const;\nexport const guidelinesVersionSchema = z.literal(GUIDELINES_VERSION, {\n error: VALIDATION_MESSAGE.guidelinesOutdated,\n});\n\n// ─── Contact ─────────────────────────────────────────────────────────────────\n\n/**\n * The links the contact step collects, picked from the profile's own links so\n * the two cannot disagree on what a link is. The phone is `phoneSchema`: ten\n * digits, stored raw with no country code, on the account rather than here.\n */\nexport const contactLinksSchema = founderLinksSchema.pick({\n linkedin: true,\n x: true,\n instagram: true,\n});\nexport type ContactLinks = z.infer<typeof contactLinksSchema>;\n\n/** A team size has at most this many digits: `TEAM_SIZE_MAX` written out. */\nexport const TEAM_SIZE_DIGITS_MAX = String(TEAM_SIZE_MAX).length;\n\n// ─── The form, mid-flight: the draft each step saves ──────────────────────────\n\n/**\n * The answers so far, keyed by the finish body's own field names: what each\n * step SAVES (`PATCH /onboarding`, merged per field), what `GET` hands back\n * to resume, and so the only keys a draft may hold\n * (`ONBOARDING_DRAFT_KEYS`).\n *\n * RAW, on purpose: a draft is what the member TYPED, not what Finish will send.\n * A half-typed link is ordinary text, a team size is digits as typed, and every\n * choice is `null` until made (\"not answered\" is not \"answered with nothing\").\n * Nothing here is required; whether a member may FINISH is\n * `completeOnboardingBodySchema`'s decision, and the client builds that body\n * from these answers.\n *\n * Screens may hold a different shape on top of this one (the web draws first\n * and last name as two fields and joins them into `displayName`). Derive that\n * type from `OnboardingForm` rather than writing it out, so a field added here\n * reaches every screen.\n *\n * A stored draft is UNTRUSTED when it comes back: an older client, or another\n * one, wrote it, and the server stores values opaquely. Read it with\n * `readOnboardingDraft`, never by casting.\n */\nexport const onboardingFormSchema = z.object({\n displayName: z.string().max(DISPLAY_NAME_MAX),\n gender: genderSchema.nullable(),\n /** `YYYY-MM-DD` once complete; whatever has been typed until then. */\n dateOfBirth: z.string(),\n headline: z.string().max(HEADLINE_MAX),\n about: z.string().max(ABOUT_MAX),\n /**\n * The completed upload's id (`media`, purpose `avatar`). Allowed in the form,\n * and NEVER restored by `readOnboardingDraft`: an upload not attached within\n * `MEDIA_UNATTACHED_TTL_HOURS` is deleted, so an id from an older draft would\n * fail at Finish, on the last screen, about a photo picked days ago. Clients\n * hold it for the visit and do not save it.\n */\n avatarMediaId: objectIdSchema.nullable(),\n skills: z.array(skillSchema).max(SKILLS_MAX),\n\n /** As typed; the finish body takes `phoneSchema`'s ten digits. */\n phone: z.string(),\n /** As typed; the finish body takes full `https://` URLs. */\n links: z.object({\n linkedin: z.string().max(LINK_URL_MAX),\n x: z.string().max(LINK_URL_MAX),\n instagram: z.string().max(LINK_URL_MAX),\n }),\n\n /** `null` until the member opens the location step, and when they skip it. */\n location: z\n .object({\n city: z.string().max(CITY_MAX),\n state: z.string().max(STATE_MAX),\n country: z.string().max(COUNTRY_MAX),\n })\n .nullable(),\n\n goals: z.array(goalSchema).max(GOAL_VALUES.length),\n interests: z.array(topicSchema).max(INTERESTS_MAX),\n\n /**\n * Always present; empty until started. Onboarding does not ask for a\n * tagline (the profile does, later), so the draft has none.\n */\n venture: z.object({\n name: z.string().max(VENTURE_NAME_MAX),\n website: z.string().max(LINK_URL_MAX),\n industry: industrySchema.nullable(),\n stage: startupStageSchema.nullable(),\n /** Digits as typed, at most `TEAM_SIZE_DIGITS_MAX`; the body sends a number. */\n teamSize: z.string().max(TEAM_SIZE_DIGITS_MAX),\n }),\n businessType: businessTypeSchema.nullable(),\n\n /** The guidelines text the member agreed to, or `null`. */\n guidelinesVersion: z.string().nullable(),\n});\nexport type OnboardingForm = z.infer<typeof onboardingFormSchema>;\n\n// ─── Reading a stored draft back ─────────────────────────────────────────────\n\n/** Longest date of birth worth keeping from a draft: `YYYY-MM-DD`. */\nconst DATE_INPUT_MAX = 10;\n\n/** Longest phone number worth keeping from a draft, as typed with spaces. */\nconst PHONE_INPUT_MAX = 20;\n\n/** Text, cut to its limit; anything that is not text is \"not answered\". */\nconst draftText = (max: number) =>\n z\n .string()\n .catch('')\n .transform((v) => v.slice(0, max));\n\n/** One of a vocabulary, or `null` (\"not answered\"). */\nconst draftChoice = <T extends readonly [string, ...string[]]>(values: T) =>\n z.enum(values).nullable().catch(null);\n\n/**\n * Items of a vocabulary, deduplicated and capped. Unknown items (a value since\n * retired, or junk) are dropped one by one, so the rest of the answer survives.\n */\nconst draftList = <T extends readonly [string, ...string[]]>(values: T, max: number) =>\n z\n .array(z.unknown())\n .catch([])\n .transform((items) => {\n const allowed = new Set<string>(values);\n const kept = items.filter((v): v is T[number] => typeof v === 'string' && allowed.has(v));\n return [...new Set(kept)].slice(0, max);\n });\n\n/** An object of the given fields, or `null` when the draft holds none. */\nconst draftObject = <S extends z.ZodRawShape>(shape: S) =>\n z\n .record(z.string(), z.unknown())\n .nullable()\n .catch(null)\n .pipe(z.union([z.null(), z.object(shape)]));\n\nconst draftReaderSchema = z.object({\n displayName: draftText(DISPLAY_NAME_MAX),\n gender: draftChoice(GENDER_VALUES),\n dateOfBirth: draftText(DATE_INPUT_MAX),\n headline: draftText(HEADLINE_MAX),\n about: draftText(ABOUT_MAX),\n avatarMediaId: z\n .unknown()\n .optional()\n .transform(() => null),\n skills: draftList(SKILL_VALUES, SKILLS_MAX),\n phone: draftText(PHONE_INPUT_MAX),\n links: draftObject({\n linkedin: draftText(LINK_URL_MAX),\n x: draftText(LINK_URL_MAX),\n instagram: draftText(LINK_URL_MAX),\n }).transform((links) => links ?? { linkedin: '', x: '', instagram: '' }),\n location: draftObject({\n city: draftText(CITY_MAX),\n state: draftText(STATE_MAX),\n country: draftText(COUNTRY_MAX),\n }),\n goals: draftList(GOAL_VALUES, GOAL_VALUES.length),\n interests: draftList(TOPIC_VALUES, INTERESTS_MAX),\n venture: draftObject({\n name: draftText(VENTURE_NAME_MAX),\n website: draftText(LINK_URL_MAX),\n industry: draftChoice(INDUSTRY_VALUES),\n stage: draftChoice(STARTUP_STAGE_VALUES),\n teamSize: z\n .string()\n .catch('')\n .transform((v) => v.replace(/\\D/g, '').slice(0, TEAM_SIZE_DIGITS_MAX)),\n }).transform((venture) => venture ?? { ...EMPTY_ONBOARDING_VENTURE }),\n businessType: draftChoice(BUSINESS_TYPE_VALUES),\n /** Agreement to an OLDER text is not agreement to this one. */\n guidelinesVersion: z\n .unknown()\n .optional()\n .transform((v) => (v === GUIDELINES_VERSION ? GUIDELINES_VERSION : null)),\n});\n\n/** The business step before anything is chosen. */\nexport const EMPTY_ONBOARDING_VENTURE: OnboardingForm['venture'] = {\n name: '',\n website: '',\n industry: null,\n stage: null,\n teamSize: '',\n};\n\n/**\n * A stored draft as an `OnboardingForm`, FIELD BY FIELD.\n *\n * Every field is checked against its own vocabulary and cut to its own limit;\n * one that does not fit becomes \"not answered\" (`''`, `null`, `[]`) and the\n * rest of the draft survives. Never coerced into a different answer: a value\n * outside a vocabulary is dropped, not mapped to the nearest one. A photo\n * is never restored (see `avatarMediaId`), and agreement only counts for the\n * CURRENT guidelines.\n *\n * It fills in no answer the member did not give: a blank country stays blank.\n * Whatever a screen shows by default is that screen's choice.\n */\nexport function readOnboardingDraft(draft: unknown): OnboardingForm {\n const source = draft && typeof draft === 'object' && !Array.isArray(draft) ? draft : {};\n return draftReaderSchema.parse(source);\n}\n\n// ─── The finalize body ───────────────────────────────────────────────────────\n\n/**\n * What the client sends to finish. Completed answers only.\n *\n * ⚠️ EVERY OPTIONAL FIELD HERE MUST BE ABSENT WHEN UNANSWERED, never a default\n * standing in for one. The sibling gym product sent `bloodGroup ?? 'O+'`, so\n * every member who skipped the question was recorded as O-positive: a real\n * answer, indistinguishable from one somebody gave, sitting on a screen staff\n * would read in an emergency. Absent has to stay absent.\n *\n * ⚠️ AND THIS IS NOT THE GATE EITHER. The server re-checks the age and refuses\n * at finalize. `isOnboarded` may be set here and nowhere else: four of the\n * profile's partial indexes are gated on it, so a half-built profile carrying\n * it true appears in Discover half-built.\n *\n * Location, venture and links are the profile's own shapes, not copies: the\n * copies are how the profile model came to lack Instagram.\n */\nexport const completeOnboardingBodySchema = z.object({\n // Plain bounds, no custom message: `too_small` with minimum 1 already says\n // \"required\", and the client words it in the member's language.\n displayName: displayNameSchema,\n /**\n * ⚠️ NO `username` HERE, and its absence is deliberate.\n *\n * It used to be required, and that was a defect: no onboarding step collects\n * one, the design draws no screen for one, and it was not even on the\n * in-progress form, so a finalize could never have succeeded. Found by\n * checking every finalize-required field against the step list; a test now\n * asserts that relationship in both directions.\n *\n * The handle is DERIVED SERVER-SIDE at finalize and edited later from the Me\n * tab, which is what the product describes. That also makes the collision\n * case kinder: a server deriving a handle can suffix it and move on, whereas\n * a member who picked one six steps ago can only be told, at the end, that\n * step one failed.\n */\n gender: genderSchema,\n dateOfBirth: dateOfBirthSchema,\n headline: optionalTrimmedString(HEADLINE_MAX),\n about: optionalTrimmedString(ABOUT_MAX),\n /**\n * A completed avatar upload (`media`, purpose `avatar`). The server attaches\n * it inside the same transaction that creates the profile, so a refused\n * Finish leaves the upload unattached (and swept), never half-used.\n */\n avatarMediaId: objectIdSchema.optional(),\n\n phone: phoneSchema,\n links: contactLinksSchema.optional(),\n\n /** Absent when the member skipped the step or refused the permission. */\n location: locationSchema.optional(),\n\n goals: z.array(goalSchema).min(GOALS_MIN).max(GOAL_VALUES.length),\n interests: z.array(topicSchema).min(INTERESTS_MIN).max(INTERESTS_MAX),\n skills: z.array(skillSchema).max(SKILLS_MAX).optional(),\n\n /**\n * Absent when the member skipped the business step. The profile's venture\n * without `foundedYear`, which onboarding does not ask; the Me tab does.\n */\n venture: ventureSchema.omit({ foundedYear: true }).optional(),\n businessType: businessTypeSchema.optional(),\n\n /**\n * The version of the guidelines this member read: `GUIDELINES_VERSION`,\n * exactly.\n *\n * A version and not a boolean, and the server stamps the time. A boolean says\n * somebody agreed; a version and a timestamp say WHAT they agreed to and\n * WHEN, which is the only form worth anything the day the text changes or a\n * moderation decision is disputed.\n */\n guidelinesVersion: guidelinesVersionSchema,\n});\nexport type CompleteOnboardingBody = z.infer<typeof completeOnboardingBodySchema>;\n/** What a form may hand to the finish body before parsing. */\nexport type CompleteOnboardingBodyInput = z.input<typeof completeOnboardingBodySchema>;\n\n// ─── The steps ───────────────────────────────────────────────────────────────\n\n/**\n * Each step's slice of the finish body, picked FROM it, so a client validating\n * \"may I leave this step\" and the server validating the finish apply the very\n * same rules. A copy would drift, and the drift shows up as a wizard that lets\n * a step pass and a finish that refuses it, on the last screen.\n *\n * THIS IS THE ONE PLACE A STEP'S FIELDS ARE WRITTEN. `FOUNDER_ONBOARDING_STEPS`\n * below reads them from here. A test asserts that every finish field belongs to\n * exactly one step.\n *\n * These validate the FINISH shape (skipped = absent), not the in-progress form:\n * a client maps its form state to the slice first. The server does not run them\n * on a draft save, because a half-answered step must be storable.\n */\nexport const ONBOARDING_STEP_SCHEMAS = {\n identity: completeOnboardingBodySchema.pick({\n displayName: true,\n gender: true,\n dateOfBirth: true,\n headline: true,\n about: true,\n avatarMediaId: true,\n // Here because ruling D8 folded the design's orphan \"title, achievements,\n // skills\" screen into step one. It was on no step until 0.2.0, which made\n // it the one finish field no step owned.\n skills: true,\n }),\n contact: completeOnboardingBodySchema.pick({ phone: true, links: true }),\n location: completeOnboardingBodySchema.pick({ location: true }),\n goals: completeOnboardingBodySchema.pick({ goals: true }),\n interests: completeOnboardingBodySchema.pick({ interests: true }),\n business: completeOnboardingBodySchema.pick({ venture: true, businessType: true }),\n guidelines: completeOnboardingBodySchema.pick({ guidelinesVersion: true }),\n} as const satisfies Record<OnboardingStepKey, z.ZodObject>;\n\n/** One step's slice, parsed: `OnboardingStepBody<'contact'>` is `{ phone, links? }`. */\nexport type OnboardingStepBody<K extends OnboardingStepKey> = z.infer<\n (typeof ONBOARDING_STEP_SCHEMAS)[K]\n>;\n\n/** A finish-body field name. */\nexport type OnboardingField = keyof CompleteOnboardingBody;\n\n/**\n * One step of the wizard, as a client renders it.\n *\n * `fields` is what gates leaving this step: a field that appears in no step is\n * unreachable twice over, because Continue will not surface its error and the\n * final submit's jump-to-the-bad-step finds no step to jump to and leaves the\n * last screen dead.\n */\nexport interface OnboardingStepConfig {\n /** Stable identifier. Safe for analytics and for a resume cursor, unlike an index. */\n key: OnboardingStepKey;\n /** Translation keys. The words live in the client's message files. */\n titleKey: `onboarding.steps.${OnboardingStepKey}.title`;\n helpKey: `onboarding.steps.${OnboardingStepKey}.help`;\n /** The step's slice of the finish body, in schema order. */\n fields: readonly OnboardingField[];\n /**\n * False when the whole step may be passed without answering anything.\n * DERIVED: a step is optional exactly when its slice accepts an empty\n * object, so \"skippable\" can never disagree with what the finish accepts.\n */\n required: boolean;\n}\n\nexport const FOUNDER_ONBOARDING_STEPS: readonly OnboardingStepConfig[] = ONBOARDING_STEP_KEYS.map(\n (key): OnboardingStepConfig => {\n const slice = ONBOARDING_STEP_SCHEMAS[key];\n return {\n key,\n titleKey: `onboarding.steps.${key}.title`,\n helpKey: `onboarding.steps.${key}.help`,\n fields: Object.keys(slice.shape) as OnboardingField[],\n required: !slice.safeParse({}).success,\n };\n },\n);\n\nexport const ONBOARDING_TOTAL_STEPS = FOUNDER_ONBOARDING_STEPS.length;\n\n/** Fields gating each step, in step order. Read from the same picks. */\nexport const ONBOARDING_STEP_FIELDS: readonly (readonly OnboardingField[])[] =\n FOUNDER_ONBOARDING_STEPS.map((s) => s.fields);\n\n/** What finishing answers: the new profile's id and the handle derived for it. */\nexport const completeOnboardingResponseSchema = z.object({\n id: z.string(),\n username: z.string(),\n});\nexport type CompleteOnboardingResponse = z.infer<typeof completeOnboardingResponseSchema>;\n\n// ─── The resume cursor ───────────────────────────────────────────────────────\n\n/**\n * The keys a draft may hold: exactly the in-progress form's fields.\n *\n * ⚠ The server writes each key as a dot path (`draft.<key>`). Unchecked, a key\n * holding a dot writes somewhere nested the form never asked for, and the\n * collection fills with whatever a client invents. Until 0.2.0 the backend\n * kept its own copy of this list and DROPPED unknown keys without a word; now a\n * draft carrying one is refused, with the key in the issue's path.\n */\nexport const onboardingDraftKeySchema = onboardingFormSchema.keyof();\nexport const ONBOARDING_DRAFT_KEYS = onboardingDraftKeySchema.options;\nexport type OnboardingDraftKey = z.infer<typeof onboardingDraftKeySchema>;\n\n/**\n * Where the member got to, kept in its own collection, separate from the\n * profile.\n *\n * `step` is a flat index into `FOUNDER_ONBOARDING_STEPS`, not a `(step, sub)`\n * pair: one number is what lets a member start on the web and resume elsewhere,\n * provided both ends agree on the encoding.\n *\n * The draft's KEYS come from the form; its VALUES are opaque on purpose. A\n * half-answered step must be storable even though it would fail the finish,\n * and everything in it is re-validated strictly at finalize.\n *\n * `partialRecord`, not `record`: in Zod 4 an enum-keyed `z.record` demands\n * every key, and a draft holds whichever steps the member has reached.\n */\nexport const onboardingDraftSchema = z.partialRecord(onboardingDraftKeySchema, z.unknown());\nexport type OnboardingDraft = z.infer<typeof onboardingDraftSchema>;\n\nexport const onboardingProgressSchema = z.object({\n step: z.number().int().min(0).max(ONBOARDING_TOTAL_STEPS),\n draft: onboardingDraftSchema.optional(),\n});\nexport type OnboardingProgress = z.infer<typeof onboardingProgressSchema>;\n\n/**\n * `PATCH` body: any subset of the cursor, merged server-side. No defaults.\n * `step` may equal `ONBOARDING_TOTAL_STEPS`: \"past the last step\", which the\n * client sends on its way to finish.\n */\nexport const onboardingProgressUpdateSchema = z.object({\n step: z.number().int().min(0).max(ONBOARDING_TOTAL_STEPS).optional(),\n draft: onboardingDraftSchema.optional(),\n});\nexport type OnboardingProgressUpdate = z.infer<typeof onboardingProgressUpdateSchema>;\n\n/**\n * What the client reads on return, from `GET` and from every `PATCH`.\n *\n * ⚠️ `onboarded` is the gate and it comes from the profile, not from the\n * cursor: a finished member on a new device must be recognised even when the\n * cursor row is gone, and a cursor that failed to load must never make an\n * unfinished member look finished.\n */\nexport const onboardingStatusSchema = z.object({\n onboarded: z.boolean(),\n step: z.number().int().min(0).max(ONBOARDING_TOTAL_STEPS),\n draft: onboardingDraftSchema.optional(),\n});\nexport type OnboardingStatus = z.infer<typeof onboardingStatusSchema>;\n"]}
@@ -356,9 +356,10 @@ export type PublicBirthday = z.infer<typeof publicBirthdaySchema>;
356
356
  * client renders what arrives. Built field by field on the server
357
357
  * (`toMemberPublic`), never by dropping fields from a fuller document.
358
358
  *
359
- * `viewer.canMessage` is the server's answer to "may I start a chat with
360
- * them": who may message whom will follow membership and plans, so no client
361
- * works it out.
359
+ * `viewer.canMessage` is the server's answer to "offer Message": the tap
360
+ * opens a conversation, or (0.13.0) the sheet that makes one possible (the
361
+ * membership for a viewer, the plans for a member without one). Who may
362
+ * message whom follows membership and plans, so no client works it out.
362
363
  */
363
364
  export declare const memberProfileSchema: z.ZodObject<{
364
365
  id: z.ZodString;
@@ -590,6 +591,11 @@ export declare const updateUsernameBodySchema: z.ZodObject<{
590
591
  username: z.ZodString;
591
592
  }, z.core.$strip>;
592
593
  export type UpdateUsernameBody = z.infer<typeof updateUsernameBodySchema>;
594
+ /** `GET /api/v1/profiles/username-available?username=` (0.13.0): the handle asked about. */
595
+ export declare const usernameAvailabilityQuerySchema: z.ZodObject<{
596
+ username: z.ZodString;
597
+ }, z.core.$strip>;
598
+ export type UsernameAvailabilityQuery = z.infer<typeof usernameAvailabilityQuerySchema>;
593
599
  /** Availability probe behind the username field. */
594
600
  export declare const usernameAvailabilitySchema: z.ZodObject<{
595
601
  username: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"founder-profile.d.ts","sourceRoot":"","sources":["../../../src/domains/profile/founder-profile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"founder-profile.d.ts","sourceRoot":"","sources":["../../../src/domains/profile/founder-profile.ts"],"names":[],"mappings":"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"}
@@ -218,9 +218,10 @@ export const publicBirthdaySchema = z.object({
218
218
  * client renders what arrives. Built field by field on the server
219
219
  * (`toMemberPublic`), never by dropping fields from a fuller document.
220
220
  *
221
- * `viewer.canMessage` is the server's answer to "may I start a chat with
222
- * them": who may message whom will follow membership and plans, so no client
223
- * works it out.
221
+ * `viewer.canMessage` is the server's answer to "offer Message": the tap
222
+ * opens a conversation, or (0.13.0) the sheet that makes one possible (the
223
+ * membership for a viewer, the plans for a member without one). Who may
224
+ * message whom follows membership and plans, so no client works it out.
224
225
  */
225
226
  export const memberProfileSchema = founderProfileSchema
226
227
  .pick({
@@ -305,6 +306,8 @@ export const updateFounderProfileBodySchema = z.object({
305
306
  * uniqueness check, and it refuses a reserved handle (`chosenUsernameSchema`).
306
307
  */
307
308
  export const updateUsernameBodySchema = z.object({ username: chosenUsernameSchema });
309
+ /** `GET /api/v1/profiles/username-available?username=` (0.13.0): the handle asked about. */
310
+ export const usernameAvailabilityQuerySchema = z.object({ username: usernameSchema });
308
311
  /** Availability probe behind the username field. */
309
312
  export const usernameAvailabilitySchema = z.object({
310
313
  username: usernameSchema,
@@ -1 +1 @@
1
- {"version":3,"file":"founder-profile.js","sourceRoot":"","sources":["../../../src/domains/profile/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/domains/profile\n */\n\nimport { z } from 'zod';\nimport {\n chosenUsernameSchema,\n displayNameSchema,\n GOAL_VALUES,\n genderSchema,\n goalSchema,\n httpUrlSchema,\n industrySchema,\n locationSchema,\n objectIdSchema,\n optionalTrimmedString,\n phoneSchema,\n skillSchema,\n startupStageSchema,\n usernameSchema,\n} from '../../core/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 '../../core/limits.js';\nimport { VALIDATION_MESSAGE } from '../../core/validation.js';\nimport { mediaImageSchema } from '../media/media.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// ─── A member as other surfaces name them ────────────────────────────────────\n\n/**\n * A member as a byline renders them: on a post (`feedAuthorSchema` is this), a\n * product's team, a review, a notification, the top-helpers list.\n *\n * Every field is LIVE, joined against the profile at read time rather than\n * frozen onto the post or review at write time. So a renamed handle, a new\n * photo or an edited headline updates everywhere, the link always targets the\n * current username, and nothing personal survives in other people's rows once\n * an account is deleted.\n */\nexport const memberBylineSchema = z.object({\n userId: z.string(),\n username: usernameSchema,\n displayName: z.string(),\n /** Server-generated or from the login provider, never member-typed, so a\n * plain URL check. Same reasoning as `avatarUrl` on the profile. */\n avatarUrl: z.url().optional(),\n /** The member's one-line headline, live-joined. */\n headline: z.string().optional(),\n});\nexport type MemberByline = z.infer<typeof memberBylineSchema>;\n\n/**\n * What a member has given the community, on their profile and card.\n *\n * `score` is points earned from OTHER members' recognition only: a product's\n * team marking your feedback helpful, confirming you tested their product,\n * and members finding your review helpful (writing one earns nothing by\n * itself). Nothing a member\n * does to their own product counts, so the score cannot be bought by having a\n * popular one. `helpedCount` is how many different founders recognised that\n * help (\"Helped 12 founders\"). See `domains/contributions`.\n */\nexport const contributionSummarySchema = z.object({\n score: z.number().int().nonnegative(),\n helpedCount: z.number().int().nonnegative(),\n});\nexport type ContributionSummary = z.infer<typeof contributionSummarySchema>;\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 * WHICH picture: the member's uploaded photo at its small size (192, see\n * `MEDIA_SIZES.avatar`), else their sign-in provider's picture, else absent.\n * Every surface that shows this member resolves it the same way.\n */\n avatarUrl: z.url().optional(),\n /**\n * The uploaded photo itself, every size, when the member has one. Absent\n * means `avatarUrl` (if any) is the sign-in provider's picture, so a client\n * offers \"Remove photo\" only when this is present. Not on `founderCardSchema`:\n * a card needs one small picture, not the set.\n */\n avatar: mediaImageSchema.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 /**\n * Their contribution to other founders. Server-computed, never written by a\n * member. REQUIRED, no default: a read-side default would let a server that\n * forgot the field pass as a real zero.\n */\n contribution: contributionSummarySchema,\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 /**\n * The MEMBER's id (0.6.0): what a team invitation, a chat and every byline\n * key on. `id` is the profile's own id, which nothing takes as input.\n */\n userId: 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 contribution: true,\n});\nexport type FounderCard = z.infer<typeof founderCardSchema>;\n\n// ─── What a member chooses to show (0.11.0) ──────────────────────────────────\n\n/**\n * The four personal details a member MAY show on their profile page (the\n * user's ruling, 2026-10-11). Each is PRIVATE until its owner turns it on;\n * everything else on a profile is public as before. Changed only through\n * `PATCH /profiles/me/personal`.\n */\nexport const CONTACT_VISIBILITY_FIELDS = ['email', 'phone', 'gender', 'birthday'] as const;\nexport type ContactVisibilityField = (typeof CONTACT_VISIBILITY_FIELDS)[number];\n\n/** Which of the four the member shows. Every key present on a read: false is private. */\nexport const contactVisibilitySchema = z.object({\n email: z.boolean(),\n phone: z.boolean(),\n gender: z.boolean(),\n birthday: z.boolean(),\n});\nexport type ContactVisibility = z.infer<typeof contactVisibilitySchema>;\n\n/**\n * A birthday as OTHERS see it: day and month, NEVER the year (the user's\n * ruling). The year would give away the age and, with the name, the full date\n * of birth that identity checks ask for. The year is never on the wire.\n */\nexport const publicBirthdaySchema = z.object({\n day: z.number().int().min(1).max(31),\n month: z.number().int().min(1).max(12),\n});\nexport type PublicBirthday = z.infer<typeof publicBirthdaySchema>;\n\n/**\n * `GET /api/v1/founders/by-username/:username` (0.11.0): one member's profile\n * page, as a signed-in member (or the member themself) sees it.\n *\n * The card's fields, what only a page has room for (about, links, member\n * since), and `shown`: the personal details this member has CHOSEN to show,\n * and nothing else. Email and phone go to members only, never to an account\n * without membership (the coming viewer tier); the server decides, and a\n * client renders what arrives. Built field by field on the server\n * (`toMemberPublic`), never by dropping fields from a fuller document.\n *\n * `viewer.canMessage` is the server's answer to \"may I start a chat with\n * them\": who may message whom will follow membership and plans, so no client\n * works it out.\n */\nexport const memberProfileSchema = founderProfileSchema\n .pick({\n id: true,\n userId: true,\n username: true,\n displayName: true,\n headline: true,\n about: true,\n avatarUrl: true,\n location: true,\n venture: true,\n skills: true,\n goals: true,\n links: true,\n contribution: true,\n createdAt: true,\n })\n .extend({\n shown: z.object({\n email: z.string().optional(),\n phone: z.string().optional(),\n gender: genderSchema.optional(),\n birthday: publicBirthdaySchema.optional(),\n }),\n viewer: z.object({ isSelf: z.boolean(), canMessage: z.boolean() }),\n });\nexport type MemberProfile = z.infer<typeof memberProfileSchema>;\n\n/** The member page's address: `/discover/<username>`. */\nexport const memberHandleParamsSchema = z.object({ username: usernameSchema });\nexport type MemberHandleParams = z.infer<typeof memberHandleParamsSchema>;\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: displayNameSchema.optional(),\n headline: clearableText(HEADLINE_MAX),\n about: clearableText(ABOUT_MAX),\n /**\n * Carries the whole location; `locationSchema` has no default to fill a gap.\n * `null` removes it (0.10.0): a member may stop showing their city on\n * Discover, and nothing else would take it off once given.\n */\n location: locationSchema.nullable().optional(),\n /**\n * The whole venture, or `null` to remove it (0.10.0), its business type\n * with it: a member whose venture closed is no longer building it.\n */\n venture: ventureSchema.nullable().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\n// ─── The member's own personal details ──────────────────────────────────────\n\n/**\n * `GET /api/v1/profiles/me/personal` (0.10.0): what ONLY the member sees of\n * themselves, the \"Personal details\" card of the Me tab's Profile.\n *\n * ⚠ OWNER ONLY, and kept OFF `founderProfileSchema` on purpose. Email, phone,\n * gender and date of birth are personal data: they appear on no card, no\n * search, no team list, no byline and no audit detail. The profile is read on\n * every page by the app shell; these do not travel with it, they are asked\n * for only where they are shown.\n *\n * Read shapes are plain where the stored value may predate today's rule (a\n * phone seeded from the sign-in provider in another format): a read schema\n * that rejects our own stored value is a self-inflicted outage. The write\n * body holds the rules.\n */\nexport const myPersonalDetailsSchema = z.object({\n /** The profile's display name: the card's first row. */\n displayName: z.string(),\n /** The sign-in account's. Changed there (Account settings), never here. */\n email: z.string().optional(),\n /** Ten digits as stored on the account mirror; display adds the `+91`. */\n phone: z.string().optional(),\n gender: genderSchema.optional(),\n /**\n * `YYYY-MM-DD`. READ ONLY: it is the 18+ check's input, given once at\n * onboarding. A date of birth that could be edited later would be an age\n * gate anyone could walk around.\n */\n dateOfBirth: z.string().optional(),\n /** Which of email, phone, gender and birthday the member shows on their page (0.11.0). */\n visibility: contactVisibilitySchema,\n});\nexport type MyPersonalDetails = z.infer<typeof myPersonalDetailsSchema>;\n\n/**\n * `PATCH /api/v1/profiles/me/personal` (0.10.0): name, phone and gender. Only\n * the keys the member changed; answers with `myPersonalDetailsSchema`.\n *\n * ONE RULE PER FIELD: the very schemas onboarding finishes with (the display\n * name, the ten-digit phone, the gender enum with prefer-not-to-say), so a\n * value one accepts the other can never refuse.\n *\n * ⚠ NO `.default()` and no `.partial()` of a read shape (see\n * `updateFounderProfileBodySchema`): absent means unchanged, and a default\n * would overwrite what is stored. No `dateOfBirth`: read only, above. No\n * `email`: the sign-in account owns it.\n *\n * Name and phone are PRODUCT-OWNED on Founder Circle's account mirror: the\n * sign-in service seeds them once and never overwrites them, so this edits\n * Founder Circle's copy and never calls the sign-in service.\n */\nexport const updateMyPersonalDetailsBodySchema = z.object({\n displayName: displayNameSchema.optional(),\n phone: phoneSchema.optional(),\n gender: genderSchema.optional(),\n /**\n * The city, or `null` to remove it (0.11.0): it moved to the Personal\n * Details card, so its editor saves it here, with the rest, in one\n * transaction. `PATCH /profiles/me` still takes it too.\n */\n location: locationSchema.nullable().optional(),\n /** Only the switches that changed (0.11.0). */\n visibility: contactVisibilitySchema.partial().optional(),\n});\nexport type UpdateMyPersonalDetailsBody = z.infer<typeof updateMyPersonalDetailsBodySchema>;\n\n// ─── The member's own photo ──────────────────────────────────────────────────\n\n/**\n * `PUT /api/v1/profiles/me/avatar`: use a completed upload (purpose `avatar`)\n * as the member's photo. Answers with the updated `founderProfileSchema`.\n *\n * The previous photo is deleted from storage, not merely unlinked, so its old\n * address stops working. `DELETE /api/v1/profiles/me/avatar` removes the photo\n * the same way and the member falls back to their sign-in provider's picture.\n */\nexport const setAvatarBodySchema = z.object({ mediaId: objectIdSchema });\nexport type SetAvatarBody = z.infer<typeof setAvatarBodySchema>;\n"]}
1
+ {"version":3,"file":"founder-profile.js","sourceRoot":"","sources":["../../../src/domains/profile/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/domains/profile\n */\n\nimport { z } from 'zod';\nimport {\n chosenUsernameSchema,\n displayNameSchema,\n GOAL_VALUES,\n genderSchema,\n goalSchema,\n httpUrlSchema,\n industrySchema,\n locationSchema,\n objectIdSchema,\n optionalTrimmedString,\n phoneSchema,\n skillSchema,\n startupStageSchema,\n usernameSchema,\n} from '../../core/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 '../../core/limits.js';\nimport { VALIDATION_MESSAGE } from '../../core/validation.js';\nimport { mediaImageSchema } from '../media/media.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// ─── A member as other surfaces name them ────────────────────────────────────\n\n/**\n * A member as a byline renders them: on a post (`feedAuthorSchema` is this), a\n * product's team, a review, a notification, the top-helpers list.\n *\n * Every field is LIVE, joined against the profile at read time rather than\n * frozen onto the post or review at write time. So a renamed handle, a new\n * photo or an edited headline updates everywhere, the link always targets the\n * current username, and nothing personal survives in other people's rows once\n * an account is deleted.\n */\nexport const memberBylineSchema = z.object({\n userId: z.string(),\n username: usernameSchema,\n displayName: z.string(),\n /** Server-generated or from the login provider, never member-typed, so a\n * plain URL check. Same reasoning as `avatarUrl` on the profile. */\n avatarUrl: z.url().optional(),\n /** The member's one-line headline, live-joined. */\n headline: z.string().optional(),\n});\nexport type MemberByline = z.infer<typeof memberBylineSchema>;\n\n/**\n * What a member has given the community, on their profile and card.\n *\n * `score` is points earned from OTHER members' recognition only: a product's\n * team marking your feedback helpful, confirming you tested their product,\n * and members finding your review helpful (writing one earns nothing by\n * itself). Nothing a member\n * does to their own product counts, so the score cannot be bought by having a\n * popular one. `helpedCount` is how many different founders recognised that\n * help (\"Helped 12 founders\"). See `domains/contributions`.\n */\nexport const contributionSummarySchema = z.object({\n score: z.number().int().nonnegative(),\n helpedCount: z.number().int().nonnegative(),\n});\nexport type ContributionSummary = z.infer<typeof contributionSummarySchema>;\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 * WHICH picture: the member's uploaded photo at its small size (192, see\n * `MEDIA_SIZES.avatar`), else their sign-in provider's picture, else absent.\n * Every surface that shows this member resolves it the same way.\n */\n avatarUrl: z.url().optional(),\n /**\n * The uploaded photo itself, every size, when the member has one. Absent\n * means `avatarUrl` (if any) is the sign-in provider's picture, so a client\n * offers \"Remove photo\" only when this is present. Not on `founderCardSchema`:\n * a card needs one small picture, not the set.\n */\n avatar: mediaImageSchema.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 /**\n * Their contribution to other founders. Server-computed, never written by a\n * member. REQUIRED, no default: a read-side default would let a server that\n * forgot the field pass as a real zero.\n */\n contribution: contributionSummarySchema,\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 /**\n * The MEMBER's id (0.6.0): what a team invitation, a chat and every byline\n * key on. `id` is the profile's own id, which nothing takes as input.\n */\n userId: 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 contribution: true,\n});\nexport type FounderCard = z.infer<typeof founderCardSchema>;\n\n// ─── What a member chooses to show (0.11.0) ──────────────────────────────────\n\n/**\n * The four personal details a member MAY show on their profile page (the\n * user's ruling, 2026-10-11). Each is PRIVATE until its owner turns it on;\n * everything else on a profile is public as before. Changed only through\n * `PATCH /profiles/me/personal`.\n */\nexport const CONTACT_VISIBILITY_FIELDS = ['email', 'phone', 'gender', 'birthday'] as const;\nexport type ContactVisibilityField = (typeof CONTACT_VISIBILITY_FIELDS)[number];\n\n/** Which of the four the member shows. Every key present on a read: false is private. */\nexport const contactVisibilitySchema = z.object({\n email: z.boolean(),\n phone: z.boolean(),\n gender: z.boolean(),\n birthday: z.boolean(),\n});\nexport type ContactVisibility = z.infer<typeof contactVisibilitySchema>;\n\n/**\n * A birthday as OTHERS see it: day and month, NEVER the year (the user's\n * ruling). The year would give away the age and, with the name, the full date\n * of birth that identity checks ask for. The year is never on the wire.\n */\nexport const publicBirthdaySchema = z.object({\n day: z.number().int().min(1).max(31),\n month: z.number().int().min(1).max(12),\n});\nexport type PublicBirthday = z.infer<typeof publicBirthdaySchema>;\n\n/**\n * `GET /api/v1/founders/by-username/:username` (0.11.0): one member's profile\n * page, as a signed-in member (or the member themself) sees it.\n *\n * The card's fields, what only a page has room for (about, links, member\n * since), and `shown`: the personal details this member has CHOSEN to show,\n * and nothing else. Email and phone go to members only, never to an account\n * without membership (the coming viewer tier); the server decides, and a\n * client renders what arrives. Built field by field on the server\n * (`toMemberPublic`), never by dropping fields from a fuller document.\n *\n * `viewer.canMessage` is the server's answer to \"offer Message\": the tap\n * opens a conversation, or (0.13.0) the sheet that makes one possible (the\n * membership for a viewer, the plans for a member without one). Who may\n * message whom follows membership and plans, so no client works it out.\n */\nexport const memberProfileSchema = founderProfileSchema\n .pick({\n id: true,\n userId: true,\n username: true,\n displayName: true,\n headline: true,\n about: true,\n avatarUrl: true,\n location: true,\n venture: true,\n skills: true,\n goals: true,\n links: true,\n contribution: true,\n createdAt: true,\n })\n .extend({\n shown: z.object({\n email: z.string().optional(),\n phone: z.string().optional(),\n gender: genderSchema.optional(),\n birthday: publicBirthdaySchema.optional(),\n }),\n viewer: z.object({ isSelf: z.boolean(), canMessage: z.boolean() }),\n });\nexport type MemberProfile = z.infer<typeof memberProfileSchema>;\n\n/** The member page's address: `/discover/<username>`. */\nexport const memberHandleParamsSchema = z.object({ username: usernameSchema });\nexport type MemberHandleParams = z.infer<typeof memberHandleParamsSchema>;\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: displayNameSchema.optional(),\n headline: clearableText(HEADLINE_MAX),\n about: clearableText(ABOUT_MAX),\n /**\n * Carries the whole location; `locationSchema` has no default to fill a gap.\n * `null` removes it (0.10.0): a member may stop showing their city on\n * Discover, and nothing else would take it off once given.\n */\n location: locationSchema.nullable().optional(),\n /**\n * The whole venture, or `null` to remove it (0.10.0), its business type\n * with it: a member whose venture closed is no longer building it.\n */\n venture: ventureSchema.nullable().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/** `GET /api/v1/profiles/username-available?username=` (0.13.0): the handle asked about. */\nexport const usernameAvailabilityQuerySchema = z.object({ username: usernameSchema });\nexport type UsernameAvailabilityQuery = z.infer<typeof usernameAvailabilityQuerySchema>;\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\n// ─── The member's own personal details ──────────────────────────────────────\n\n/**\n * `GET /api/v1/profiles/me/personal` (0.10.0): what ONLY the member sees of\n * themselves, the \"Personal details\" card of the Me tab's Profile.\n *\n * ⚠ OWNER ONLY, and kept OFF `founderProfileSchema` on purpose. Email, phone,\n * gender and date of birth are personal data: they appear on no card, no\n * search, no team list, no byline and no audit detail. The profile is read on\n * every page by the app shell; these do not travel with it, they are asked\n * for only where they are shown.\n *\n * Read shapes are plain where the stored value may predate today's rule (a\n * phone seeded from the sign-in provider in another format): a read schema\n * that rejects our own stored value is a self-inflicted outage. The write\n * body holds the rules.\n */\nexport const myPersonalDetailsSchema = z.object({\n /** The profile's display name: the card's first row. */\n displayName: z.string(),\n /** The sign-in account's. Changed there (Account settings), never here. */\n email: z.string().optional(),\n /** Ten digits as stored on the account mirror; display adds the `+91`. */\n phone: z.string().optional(),\n gender: genderSchema.optional(),\n /**\n * `YYYY-MM-DD`. READ ONLY: it is the 18+ check's input, given once at\n * onboarding. A date of birth that could be edited later would be an age\n * gate anyone could walk around.\n */\n dateOfBirth: z.string().optional(),\n /** Which of email, phone, gender and birthday the member shows on their page (0.11.0). */\n visibility: contactVisibilitySchema,\n});\nexport type MyPersonalDetails = z.infer<typeof myPersonalDetailsSchema>;\n\n/**\n * `PATCH /api/v1/profiles/me/personal` (0.10.0): name, phone and gender. Only\n * the keys the member changed; answers with `myPersonalDetailsSchema`.\n *\n * ONE RULE PER FIELD: the very schemas onboarding finishes with (the display\n * name, the ten-digit phone, the gender enum with prefer-not-to-say), so a\n * value one accepts the other can never refuse.\n *\n * ⚠ NO `.default()` and no `.partial()` of a read shape (see\n * `updateFounderProfileBodySchema`): absent means unchanged, and a default\n * would overwrite what is stored. No `dateOfBirth`: read only, above. No\n * `email`: the sign-in account owns it.\n *\n * Name and phone are PRODUCT-OWNED on Founder Circle's account mirror: the\n * sign-in service seeds them once and never overwrites them, so this edits\n * Founder Circle's copy and never calls the sign-in service.\n */\nexport const updateMyPersonalDetailsBodySchema = z.object({\n displayName: displayNameSchema.optional(),\n phone: phoneSchema.optional(),\n gender: genderSchema.optional(),\n /**\n * The city, or `null` to remove it (0.11.0): it moved to the Personal\n * Details card, so its editor saves it here, with the rest, in one\n * transaction. `PATCH /profiles/me` still takes it too.\n */\n location: locationSchema.nullable().optional(),\n /** Only the switches that changed (0.11.0). */\n visibility: contactVisibilitySchema.partial().optional(),\n});\nexport type UpdateMyPersonalDetailsBody = z.infer<typeof updateMyPersonalDetailsBodySchema>;\n\n// ─── The member's own photo ──────────────────────────────────────────────────\n\n/**\n * `PUT /api/v1/profiles/me/avatar`: use a completed upload (purpose `avatar`)\n * as the member's photo. Answers with the updated `founderProfileSchema`.\n *\n * The previous photo is deleted from storage, not merely unlinked, so its old\n * address stops working. `DELETE /api/v1/profiles/me/avatar` removes the photo\n * the same way and the member falls back to their sign-in provider's picture.\n */\nexport const setAvatarBodySchema = z.object({ mediaId: objectIdSchema });\nexport type SetAvatarBody = z.infer<typeof setAvatarBodySchema>;\n"]}
@@ -33,11 +33,14 @@
33
33
  */
34
34
  import { z } from 'zod';
35
35
  /** What the problem is about: routes it, and lets the team see patterns. Append only. */
36
- export declare const TICKET_CATEGORY_VALUES: readonly ["account", "profile", "feed", "chat", "safety", "bug", "other"];
36
+ export declare const TICKET_CATEGORY_VALUES: readonly ["account", "profile", "feed", "chat", "safety", "bug", "other", "billing", "products", "communities"];
37
37
  export declare const ticketCategorySchema: z.ZodEnum<{
38
38
  chat: "chat";
39
39
  feed: "feed";
40
40
  other: "other";
41
+ communities: "communities";
42
+ products: "products";
43
+ billing: "billing";
41
44
  account: "account";
42
45
  profile: "profile";
43
46
  safety: "safety";
@@ -88,6 +91,9 @@ export declare const ticketSummarySchema: z.ZodObject<{
88
91
  chat: "chat";
89
92
  feed: "feed";
90
93
  other: "other";
94
+ communities: "communities";
95
+ products: "products";
96
+ billing: "billing";
91
97
  account: "account";
92
98
  profile: "profile";
93
99
  safety: "safety";
@@ -124,6 +130,9 @@ export declare const ticketPageSchema: z.ZodObject<{
124
130
  chat: "chat";
125
131
  feed: "feed";
126
132
  other: "other";
133
+ communities: "communities";
134
+ products: "products";
135
+ billing: "billing";
127
136
  account: "account";
128
137
  profile: "profile";
129
138
  safety: "safety";
@@ -162,6 +171,9 @@ export declare const ticketDetailSchema: z.ZodObject<{
162
171
  chat: "chat";
163
172
  feed: "feed";
164
173
  other: "other";
174
+ communities: "communities";
175
+ products: "products";
176
+ billing: "billing";
165
177
  account: "account";
166
178
  profile: "profile";
167
179
  safety: "safety";
@@ -244,6 +256,9 @@ export declare const createTicketBodySchema: z.ZodObject<{
244
256
  chat: "chat";
245
257
  feed: "feed";
246
258
  other: "other";
259
+ communities: "communities";
260
+ products: "products";
261
+ billing: "billing";
247
262
  account: "account";
248
263
  profile: "profile";
249
264
  safety: "safety";
@@ -1 +1 @@
1
- {"version":3,"file":"support.d.ts","sourceRoot":"","sources":["../../../src/domains/support/support.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"support.d.ts","sourceRoot":"","sources":["../../../src/domains/support/support.ts"],"names":[],"mappings":"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"}
@@ -44,6 +44,11 @@ export const TICKET_CATEGORY_VALUES = [
44
44
  'safety',
45
45
  'bug',
46
46
  'other',
47
+ // 0.13.0: payments and refunds (a refund is asked for through Help and
48
+ // support), products, and communities.
49
+ 'billing',
50
+ 'products',
51
+ 'communities',
47
52
  ];
48
53
  export const ticketCategorySchema = z.enum(TICKET_CATEGORY_VALUES);
49
54
  export const TICKET_STATUS_VALUES = ['open', 'waiting', 'resolved'];
@@ -1 +1 @@
1
- {"version":3,"file":"support.js","sourceRoot":"","sources":["../../../src/domains/support/support.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema: support\n *\n * A member asks for help; a support agent answers. One conversation per\n * problem, a ticket, with its messages in order.\n *\n * POST /api/v1/support/tickets { subject, category, body }\n * GET /api/v1/support/tickets ?scope&status&assignee&limit&cursor\n * GET /api/v1/support/tickets/:ticketId\n * POST /api/v1/support/tickets/:ticketId/messages { body } reply\n * POST /api/v1/support/tickets/:ticketId/claim an agent takes it\n * POST /api/v1/support/tickets/:ticketId/resolve closed as solved\n * POST /api/v1/support/tickets/:ticketId/reopen the member reopens\n *\n * GET /api/v1/support/saved-replies\n * POST /api/v1/support/saved-replies { title, body }\n * PUT /api/v1/support/saved-replies/:replyId { title, body }\n * DELETE /api/v1/support/saved-replies/:replyId\n *\n * THE STATES\n * open waiting on support: new, or the member wrote last\n * waiting waiting on the member: an agent wrote last\n * resolved closed; the member can reopen it, and writing reopens it\n *\n * `scope=mine` is the tickets the asker raised, whatever role they act as;\n * `scope=queue` is every ticket the active role may read (all of them for a\n * support agent or manager, only their own for a member). An agent replying to\n * an unclaimed ticket claims it.\n *\n * Every message is free text from a person: untrusted, shown as text.\n *\n * @module founder-schema/domains/support\n */\n\nimport { z } from 'zod';\nimport {\n emptyStringToUndefined,\n objectIdSchema,\n paginationQuerySchema,\n} from '../../core/common.js';\nimport {\n SAVED_REPLY_BODY_MAX,\n SAVED_REPLY_TITLE_MAX,\n TICKET_MESSAGE_MAX,\n TICKET_SUBJECT_MAX,\n TICKET_SUBJECT_MIN,\n} from '../../core/limits.js';\nimport { paginatedSchema } from '../../core/responses.js';\n\n/** What the problem is about: routes it, and lets the team see patterns. Append only. */\nexport const TICKET_CATEGORY_VALUES = [\n 'account',\n 'profile',\n 'feed',\n 'chat',\n 'safety',\n 'bug',\n 'other',\n] as const;\nexport const ticketCategorySchema = z.enum(TICKET_CATEGORY_VALUES);\nexport type TicketCategory = z.infer<typeof ticketCategorySchema>;\n\nexport const TICKET_STATUS_VALUES = ['open', 'waiting', 'resolved'] as const;\nexport const ticketStatusSchema = z.enum(TICKET_STATUS_VALUES);\nexport type TicketStatus = z.infer<typeof ticketStatusSchema>;\n\nexport const TICKET_SCOPE_VALUES = ['mine', 'queue'] as const;\nexport const ticketScopeSchema = z.enum(TICKET_SCOPE_VALUES);\nexport type TicketScope = z.infer<typeof ticketScopeSchema>;\n\n/** The queue's assignee filter: mine, nobody's, or anyone's. */\nexport const TICKET_ASSIGNEE_FILTER_VALUES = ['me', 'unassigned', 'any'] as const;\nexport const ticketAssigneeFilterSchema = z.enum(TICKET_ASSIGNEE_FILTER_VALUES);\nexport type TicketAssigneeFilter = z.infer<typeof ticketAssigneeFilterSchema>;\n\nconst person = z.object({ id: objectIdSchema, displayName: z.string() });\n\n/** One message. `from` says which side wrote it; the agent's name is shown to the member. */\nexport const ticketMessageSchema = z.object({\n id: objectIdSchema,\n from: z.enum(['member', 'agent']),\n author: person,\n body: z.string(),\n at: z.iso.datetime(),\n});\nexport type TicketMessage = z.infer<typeof ticketMessageSchema>;\n\n/** A ticket in a list. */\nexport const ticketSummarySchema = z.object({\n id: objectIdSchema,\n subject: z.string(),\n category: ticketCategorySchema,\n status: ticketStatusSchema,\n member: person.extend({ avatarUrl: z.url().nullable() }),\n assignee: person.nullable(),\n messageCount: z.number().int().min(1),\n createdAt: z.iso.datetime(),\n lastMessageAt: z.iso.datetime(),\n /** Who wrote last, so a list can say \"Support replied\" or \"Waiting on support\". */\n lastFrom: z.enum(['member', 'agent']),\n});\nexport type TicketSummary = z.infer<typeof ticketSummarySchema>;\n\nexport const ticketPageSchema = paginatedSchema(ticketSummarySchema);\nexport type TicketPage = z.infer<typeof ticketPageSchema>;\n\n/** A ticket with its whole conversation and what the asker may do with it. */\nexport const ticketDetailSchema = ticketSummarySchema.extend({\n messages: z.array(ticketMessageSchema).min(1),\n resolvedAt: z.iso.datetime().nullable(),\n viewer: z.object({\n canReply: z.boolean(),\n canClaim: z.boolean(),\n canResolve: z.boolean(),\n canReopen: z.boolean(),\n /** Replying as the agent side (the reply is shown as Support's). */\n asAgent: z.boolean(),\n }),\n});\nexport type TicketDetail = z.infer<typeof ticketDetailSchema>;\n\n/** `:ticketId` in the paths above. */\nexport const ticketParamsSchema = z.object({ ticketId: objectIdSchema });\nexport type TicketParams = z.infer<typeof ticketParamsSchema>;\n\n/** `GET /support/tickets`. Mine by default; status and assignee narrow it. */\nexport const ticketListQuerySchema = paginationQuerySchema.extend({\n scope: z.preprocess(emptyStringToUndefined, ticketScopeSchema.default('mine')),\n status: z.preprocess(emptyStringToUndefined, ticketStatusSchema.optional()),\n assignee: z.preprocess(emptyStringToUndefined, ticketAssigneeFilterSchema.default('any')),\n});\nexport type TicketListQuery = z.infer<typeof ticketListQuerySchema>;\nexport type TicketListQueryInput = z.input<typeof ticketListQuerySchema>;\n\nconst messageBody = z.string().trim().min(1).max(TICKET_MESSAGE_MAX);\n\n/** `POST /support/tickets`: what went wrong, in the member's words. */\nexport const createTicketBodySchema = z.object({\n subject: z.string().trim().min(TICKET_SUBJECT_MIN).max(TICKET_SUBJECT_MAX),\n category: ticketCategorySchema,\n body: messageBody,\n});\nexport type CreateTicketBody = z.infer<typeof createTicketBodySchema>;\n\n/** `POST /support/tickets/:ticketId/messages`. */\nexport const replyTicketBodySchema = z.object({ body: messageBody });\nexport type ReplyTicketBody = z.infer<typeof replyTicketBodySchema>;\n\n// ─── Saved replies ───────────────────────────────────────────────────────────\n\n/** An answer the support team reuses. Inserted into a reply, then edited, never sent as is. */\nexport const savedReplySchema = z.object({\n id: objectIdSchema,\n title: z.string(),\n body: z.string(),\n author: person,\n updatedAt: z.iso.datetime(),\n viewer: z.object({ canEdit: z.boolean(), canDelete: z.boolean() }),\n});\nexport type SavedReply = z.infer<typeof savedReplySchema>;\n\n/** Every saved reply, by title. Bounded by `SAVED_REPLIES_MAX`, so not paged. */\nexport const savedReplyListSchema = z.object({ items: z.array(savedReplySchema) });\nexport type SavedReplyList = z.infer<typeof savedReplyListSchema>;\n\n/** `:replyId` in the paths above. */\nexport const savedReplyParamsSchema = z.object({ replyId: objectIdSchema });\nexport type SavedReplyParams = z.infer<typeof savedReplyParamsSchema>;\n\n/** `POST` and `PUT /support/saved-replies`. */\nexport const savedReplyBodySchema = z.object({\n title: z.string().trim().min(1).max(SAVED_REPLY_TITLE_MAX),\n body: z.string().trim().min(1).max(SAVED_REPLY_BODY_MAX),\n});\nexport type SavedReplyBody = z.infer<typeof savedReplyBodySchema>;\n"]}
1
+ {"version":3,"file":"support.js","sourceRoot":"","sources":["../../../src/domains/support/support.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema: support\n *\n * A member asks for help; a support agent answers. One conversation per\n * problem, a ticket, with its messages in order.\n *\n * POST /api/v1/support/tickets { subject, category, body }\n * GET /api/v1/support/tickets ?scope&status&assignee&limit&cursor\n * GET /api/v1/support/tickets/:ticketId\n * POST /api/v1/support/tickets/:ticketId/messages { body } reply\n * POST /api/v1/support/tickets/:ticketId/claim an agent takes it\n * POST /api/v1/support/tickets/:ticketId/resolve closed as solved\n * POST /api/v1/support/tickets/:ticketId/reopen the member reopens\n *\n * GET /api/v1/support/saved-replies\n * POST /api/v1/support/saved-replies { title, body }\n * PUT /api/v1/support/saved-replies/:replyId { title, body }\n * DELETE /api/v1/support/saved-replies/:replyId\n *\n * THE STATES\n * open waiting on support: new, or the member wrote last\n * waiting waiting on the member: an agent wrote last\n * resolved closed; the member can reopen it, and writing reopens it\n *\n * `scope=mine` is the tickets the asker raised, whatever role they act as;\n * `scope=queue` is every ticket the active role may read (all of them for a\n * support agent or manager, only their own for a member). An agent replying to\n * an unclaimed ticket claims it.\n *\n * Every message is free text from a person: untrusted, shown as text.\n *\n * @module founder-schema/domains/support\n */\n\nimport { z } from 'zod';\nimport {\n emptyStringToUndefined,\n objectIdSchema,\n paginationQuerySchema,\n} from '../../core/common.js';\nimport {\n SAVED_REPLY_BODY_MAX,\n SAVED_REPLY_TITLE_MAX,\n TICKET_MESSAGE_MAX,\n TICKET_SUBJECT_MAX,\n TICKET_SUBJECT_MIN,\n} from '../../core/limits.js';\nimport { paginatedSchema } from '../../core/responses.js';\n\n/** What the problem is about: routes it, and lets the team see patterns. Append only. */\nexport const TICKET_CATEGORY_VALUES = [\n 'account',\n 'profile',\n 'feed',\n 'chat',\n 'safety',\n 'bug',\n 'other',\n // 0.13.0: payments and refunds (a refund is asked for through Help and\n // support), products, and communities.\n 'billing',\n 'products',\n 'communities',\n] as const;\nexport const ticketCategorySchema = z.enum(TICKET_CATEGORY_VALUES);\nexport type TicketCategory = z.infer<typeof ticketCategorySchema>;\n\nexport const TICKET_STATUS_VALUES = ['open', 'waiting', 'resolved'] as const;\nexport const ticketStatusSchema = z.enum(TICKET_STATUS_VALUES);\nexport type TicketStatus = z.infer<typeof ticketStatusSchema>;\n\nexport const TICKET_SCOPE_VALUES = ['mine', 'queue'] as const;\nexport const ticketScopeSchema = z.enum(TICKET_SCOPE_VALUES);\nexport type TicketScope = z.infer<typeof ticketScopeSchema>;\n\n/** The queue's assignee filter: mine, nobody's, or anyone's. */\nexport const TICKET_ASSIGNEE_FILTER_VALUES = ['me', 'unassigned', 'any'] as const;\nexport const ticketAssigneeFilterSchema = z.enum(TICKET_ASSIGNEE_FILTER_VALUES);\nexport type TicketAssigneeFilter = z.infer<typeof ticketAssigneeFilterSchema>;\n\nconst person = z.object({ id: objectIdSchema, displayName: z.string() });\n\n/** One message. `from` says which side wrote it; the agent's name is shown to the member. */\nexport const ticketMessageSchema = z.object({\n id: objectIdSchema,\n from: z.enum(['member', 'agent']),\n author: person,\n body: z.string(),\n at: z.iso.datetime(),\n});\nexport type TicketMessage = z.infer<typeof ticketMessageSchema>;\n\n/** A ticket in a list. */\nexport const ticketSummarySchema = z.object({\n id: objectIdSchema,\n subject: z.string(),\n category: ticketCategorySchema,\n status: ticketStatusSchema,\n member: person.extend({ avatarUrl: z.url().nullable() }),\n assignee: person.nullable(),\n messageCount: z.number().int().min(1),\n createdAt: z.iso.datetime(),\n lastMessageAt: z.iso.datetime(),\n /** Who wrote last, so a list can say \"Support replied\" or \"Waiting on support\". */\n lastFrom: z.enum(['member', 'agent']),\n});\nexport type TicketSummary = z.infer<typeof ticketSummarySchema>;\n\nexport const ticketPageSchema = paginatedSchema(ticketSummarySchema);\nexport type TicketPage = z.infer<typeof ticketPageSchema>;\n\n/** A ticket with its whole conversation and what the asker may do with it. */\nexport const ticketDetailSchema = ticketSummarySchema.extend({\n messages: z.array(ticketMessageSchema).min(1),\n resolvedAt: z.iso.datetime().nullable(),\n viewer: z.object({\n canReply: z.boolean(),\n canClaim: z.boolean(),\n canResolve: z.boolean(),\n canReopen: z.boolean(),\n /** Replying as the agent side (the reply is shown as Support's). */\n asAgent: z.boolean(),\n }),\n});\nexport type TicketDetail = z.infer<typeof ticketDetailSchema>;\n\n/** `:ticketId` in the paths above. */\nexport const ticketParamsSchema = z.object({ ticketId: objectIdSchema });\nexport type TicketParams = z.infer<typeof ticketParamsSchema>;\n\n/** `GET /support/tickets`. Mine by default; status and assignee narrow it. */\nexport const ticketListQuerySchema = paginationQuerySchema.extend({\n scope: z.preprocess(emptyStringToUndefined, ticketScopeSchema.default('mine')),\n status: z.preprocess(emptyStringToUndefined, ticketStatusSchema.optional()),\n assignee: z.preprocess(emptyStringToUndefined, ticketAssigneeFilterSchema.default('any')),\n});\nexport type TicketListQuery = z.infer<typeof ticketListQuerySchema>;\nexport type TicketListQueryInput = z.input<typeof ticketListQuerySchema>;\n\nconst messageBody = z.string().trim().min(1).max(TICKET_MESSAGE_MAX);\n\n/** `POST /support/tickets`: what went wrong, in the member's words. */\nexport const createTicketBodySchema = z.object({\n subject: z.string().trim().min(TICKET_SUBJECT_MIN).max(TICKET_SUBJECT_MAX),\n category: ticketCategorySchema,\n body: messageBody,\n});\nexport type CreateTicketBody = z.infer<typeof createTicketBodySchema>;\n\n/** `POST /support/tickets/:ticketId/messages`. */\nexport const replyTicketBodySchema = z.object({ body: messageBody });\nexport type ReplyTicketBody = z.infer<typeof replyTicketBodySchema>;\n\n// ─── Saved replies ───────────────────────────────────────────────────────────\n\n/** An answer the support team reuses. Inserted into a reply, then edited, never sent as is. */\nexport const savedReplySchema = z.object({\n id: objectIdSchema,\n title: z.string(),\n body: z.string(),\n author: person,\n updatedAt: z.iso.datetime(),\n viewer: z.object({ canEdit: z.boolean(), canDelete: z.boolean() }),\n});\nexport type SavedReply = z.infer<typeof savedReplySchema>;\n\n/** Every saved reply, by title. Bounded by `SAVED_REPLIES_MAX`, so not paged. */\nexport const savedReplyListSchema = z.object({ items: z.array(savedReplySchema) });\nexport type SavedReplyList = z.infer<typeof savedReplyListSchema>;\n\n/** `:replyId` in the paths above. */\nexport const savedReplyParamsSchema = z.object({ replyId: objectIdSchema });\nexport type SavedReplyParams = z.infer<typeof savedReplyParamsSchema>;\n\n/** `POST` and `PUT /support/saved-replies`. */\nexport const savedReplyBodySchema = z.object({\n title: z.string().trim().min(1).max(SAVED_REPLY_TITLE_MAX),\n body: z.string().trim().min(1).max(SAVED_REPLY_BODY_MAX),\n});\nexport type SavedReplyBody = z.infer<typeof savedReplyBodySchema>;\n"]}