founder-schema 0.19.0 → 0.21.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 (142) hide show
  1. package/README.md +46 -0
  2. package/dist/access/permissions.d.ts +3 -3
  3. package/dist/access/permissions.d.ts.map +1 -1
  4. package/dist/access/permissions.js.map +1 -1
  5. package/dist/core/common.d.ts +42 -15
  6. package/dist/core/common.d.ts.map +1 -1
  7. package/dist/core/common.js +58 -15
  8. package/dist/core/common.js.map +1 -1
  9. package/dist/core/deletion.d.ts +40 -0
  10. package/dist/core/deletion.d.ts.map +1 -0
  11. package/dist/core/deletion.js +39 -0
  12. package/dist/core/deletion.js.map +1 -0
  13. package/dist/domains/audit/audit.d.ts +36 -12
  14. package/dist/domains/audit/audit.d.ts.map +1 -1
  15. package/dist/domains/audit/audit.js +9 -10
  16. package/dist/domains/audit/audit.js.map +1 -1
  17. package/dist/domains/billing/billing.d.ts +29 -13
  18. package/dist/domains/billing/billing.d.ts.map +1 -1
  19. package/dist/domains/billing/billing.js +2 -3
  20. package/dist/domains/billing/billing.js.map +1 -1
  21. package/dist/domains/chat/chat.d.ts +19 -5
  22. package/dist/domains/chat/chat.d.ts.map +1 -1
  23. package/dist/domains/chat/chat.js +10 -10
  24. package/dist/domains/chat/chat.js.map +1 -1
  25. package/dist/domains/communities/communities.d.ts +95 -57
  26. package/dist/domains/communities/communities.d.ts.map +1 -1
  27. package/dist/domains/contributions/contributions.d.ts +28 -12
  28. package/dist/domains/contributions/contributions.d.ts.map +1 -1
  29. package/dist/domains/contributions/contributions.js +3 -0
  30. package/dist/domains/contributions/contributions.js.map +1 -1
  31. package/dist/domains/discover/discover.d.ts +2 -2
  32. package/dist/domains/feed/feed.d.ts +111 -63
  33. package/dist/domains/feed/feed.d.ts.map +1 -1
  34. package/dist/domains/feed/feed.js +3 -0
  35. package/dist/domains/feed/feed.js.map +1 -1
  36. package/dist/domains/location/areas.d.ts +7 -0
  37. package/dist/domains/location/areas.d.ts.map +1 -1
  38. package/dist/domains/location/areas.js +3 -0
  39. package/dist/domains/location/areas.js.map +1 -1
  40. package/dist/domains/media/media.d.ts +22 -0
  41. package/dist/domains/media/media.d.ts.map +1 -1
  42. package/dist/domains/media/media.js +20 -0
  43. package/dist/domains/media/media.js.map +1 -1
  44. package/dist/domains/members/members.d.ts +27 -9
  45. package/dist/domains/members/members.d.ts.map +1 -1
  46. package/dist/domains/members/members.js +9 -10
  47. package/dist/domains/members/members.js.map +1 -1
  48. package/dist/domains/membership/membership.d.ts +42 -1
  49. package/dist/domains/membership/membership.d.ts.map +1 -1
  50. package/dist/domains/membership/membership.js +42 -1
  51. package/dist/domains/membership/membership.js.map +1 -1
  52. package/dist/domains/moderation/moderation.d.ts +8 -2
  53. package/dist/domains/moderation/moderation.d.ts.map +1 -1
  54. package/dist/domains/moderation/moderation.js +3 -6
  55. package/dist/domains/moderation/moderation.js.map +1 -1
  56. package/dist/domains/notifications/notifications.d.ts +10 -6
  57. package/dist/domains/notifications/notifications.d.ts.map +1 -1
  58. package/dist/domains/onboarding/onboarding-answers.js +1 -1
  59. package/dist/domains/onboarding/onboarding-answers.js.map +1 -1
  60. package/dist/domains/onboarding/onboarding.d.ts +11 -10
  61. package/dist/domains/onboarding/onboarding.d.ts.map +1 -1
  62. package/dist/domains/onboarding/onboarding.js +16 -9
  63. package/dist/domains/onboarding/onboarding.js.map +1 -1
  64. package/dist/domains/people/person.d.ts +54 -0
  65. package/dist/domains/people/person.d.ts.map +1 -0
  66. package/dist/domains/people/person.js +73 -0
  67. package/dist/domains/people/person.js.map +1 -0
  68. package/dist/domains/products/products.d.ts +62 -33
  69. package/dist/domains/products/products.d.ts.map +1 -1
  70. package/dist/domains/products/products.js +3 -0
  71. package/dist/domains/products/products.js.map +1 -1
  72. package/dist/domains/profile/founder-profile.d.ts +36 -19
  73. package/dist/domains/profile/founder-profile.d.ts.map +1 -1
  74. package/dist/domains/profile/founder-profile.js +43 -21
  75. package/dist/domains/profile/founder-profile.js.map +1 -1
  76. package/dist/domains/reviews/reviews.d.ts +25 -15
  77. package/dist/domains/reviews/reviews.d.ts.map +1 -1
  78. package/dist/domains/support/support.d.ts +47 -10
  79. package/dist/domains/support/support.d.ts.map +1 -1
  80. package/dist/domains/support/support.js +4 -2
  81. package/dist/domains/support/support.js.map +1 -1
  82. package/dist/domains/team/team.d.ts +9 -3
  83. package/dist/domains/team/team.d.ts.map +1 -1
  84. package/dist/domains/team/team.js +3 -6
  85. package/dist/domains/team/team.js.map +1 -1
  86. package/dist/index.d.ts +11 -9
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +13 -9
  89. package/dist/index.js.map +1 -1
  90. package/package.json +3 -2
  91. package/dist/account.d.ts +0 -40
  92. package/dist/account.d.ts.map +0 -1
  93. package/dist/account.js +0 -39
  94. package/dist/account.js.map +0 -1
  95. package/dist/chat.d.ts +0 -187
  96. package/dist/chat.d.ts.map +0 -1
  97. package/dist/chat.js +0 -189
  98. package/dist/chat.js.map +0 -1
  99. package/dist/common.d.ts +0 -304
  100. package/dist/common.d.ts.map +0 -1
  101. package/dist/common.js +0 -340
  102. package/dist/common.js.map +0 -1
  103. package/dist/discover.d.ts +0 -245
  104. package/dist/discover.d.ts.map +0 -1
  105. package/dist/discover.js +0 -68
  106. package/dist/discover.js.map +0 -1
  107. package/dist/errors.d.ts +0 -85
  108. package/dist/errors.d.ts.map +0 -1
  109. package/dist/errors.js +0 -89
  110. package/dist/errors.js.map +0 -1
  111. package/dist/feed.d.ts +0 -1658
  112. package/dist/feed.d.ts.map +0 -1
  113. package/dist/feed.js +0 -623
  114. package/dist/feed.js.map +0 -1
  115. package/dist/founder-profile.d.ts +0 -387
  116. package/dist/founder-profile.d.ts.map +0 -1
  117. package/dist/founder-profile.js +0 -180
  118. package/dist/founder-profile.js.map +0 -1
  119. package/dist/limits.d.ts +0 -76
  120. package/dist/limits.d.ts.map +0 -1
  121. package/dist/limits.js +0 -84
  122. package/dist/limits.js.map +0 -1
  123. package/dist/onboarding.d.ts +0 -1018
  124. package/dist/onboarding.d.ts.map +0 -1
  125. package/dist/onboarding.js +0 -717
  126. package/dist/onboarding.js.map +0 -1
  127. package/dist/responses/common.d.ts +0 -167
  128. package/dist/responses/common.d.ts.map +0 -1
  129. package/dist/responses/common.js +0 -67
  130. package/dist/responses/common.js.map +0 -1
  131. package/dist/responses/index.d.ts +0 -7
  132. package/dist/responses/index.d.ts.map +0 -1
  133. package/dist/responses/index.js +0 -7
  134. package/dist/responses/index.js.map +0 -1
  135. package/dist/uploads.d.ts +0 -113
  136. package/dist/uploads.d.ts.map +0 -1
  137. package/dist/uploads.js +0 -106
  138. package/dist/uploads.js.map +0 -1
  139. package/dist/validation.d.ts +0 -136
  140. package/dist/validation.d.ts.map +0 -1
  141. package/dist/validation.js +0 -142
  142. package/dist/validation.js.map +0 -1
@@ -121,7 +121,7 @@ export function completeOnboardingBodyFrom(form) {
121
121
  links[k] = url;
122
122
  }
123
123
  const body = {
124
- displayName: tidyFullName(form.displayName),
124
+ fullName: tidyFullName(form.fullName),
125
125
  gender: form.gender ?? undefined,
126
126
  dateOfBirth: form.dateOfBirth.trim(),
127
127
  phone: normalizePhone(form.phone),
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding-answers.js","sourceRoot":"","sources":["../../../src/domains/onboarding/onboarding-answers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema — From a member's onboarding answers to what is sent (0.17.0)\n *\n * The answers are an `OnboardingForm` (the in-progress shape: raw text, `null`\n * for a choice not made). Two things are built from them, and until 0.17.0\n * each client built them by hand, so a second client (the app) would have had\n * to copy every rule below and keep it in step:\n *\n * the draft a step SAVES exactly the fields that step owns, as typed\n * (`onboardingDraftForStep`)\n * the body FINISH sends completed answers only, cleaned, every\n * unanswered optional field ABSENT\n * (`completeOnboardingBodyFrom`)\n *\n * Neither validates: `ONBOARDING_STEP_SCHEMAS` and `completeOnboardingBodySchema`\n * do, on what these build. A half-filled form builds a half-filled body on\n * purpose, so the schema refuses it with the reason under each field instead\n * of a builder hiding the gap.\n *\n * @module founder-schema/domains/onboarding/onboarding-answers\n */\n\nimport {\n type Industry,\n normalizeLinkUrl,\n normalizePhone,\n type StartupStage,\n tidyFullName,\n} from '../../core/common.js';\nimport { FOUNDED_YEAR_MIN } from '../../core/limits.js';\nimport { type Place, pickOfPlace } from '../location/areas.js';\nimport {\n type CompleteOnboardingBodyInput,\n FOUNDER_ONBOARDING_STEPS,\n GUIDELINES_VERSION,\n ONBOARDING_STEP_KEYS,\n type OnboardingForm,\n type OnboardingStepKey,\n readOnboardingDraft,\n teamSizeDigits,\n} from './onboarding.js';\n\ntype DeepPartial<T> = T extends readonly (infer Item)[]\n ? DeepPartial<Item>[]\n : T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\n/**\n * A founding year as typed, kept to digits, as many as a year has (0.18.0,\n * moved from the web's Me editor beside `teamSizeDigits`).\n */\nexport const foundedYearDigits = (raw: string): string =>\n raw.replace(/\\D/g, '').slice(0, String(FOUNDED_YEAR_MIN).length);\n\n/**\n * A venture body from what was typed (0.18.0): ONE builder for onboarding's\n * business step and Me's business editor, which each built it by hand and\n * cleaned the team size two ways. Text trimmed, the website made a link\n * (`normalizeLinkUrl`), digits kept (`teamSizeDigits`, `foundedYearDigits`);\n * an empty optional answer is ABSENT. A missing name, industry or stage is\n * left missing, so `ventureSchema` refuses it under its field.\n */\nexport function ventureBodyFrom(v: {\n name: string;\n website: string;\n industry: Industry | null;\n stage: StartupStage | null;\n teamSize: string;\n tagline?: string;\n foundedYear?: string;\n}): {\n name: string;\n industry: Industry | undefined;\n stage: StartupStage | undefined;\n tagline?: string;\n website?: string;\n teamSize?: number;\n foundedYear?: number;\n} {\n const tagline = v.tagline?.trim();\n const website = normalizeLinkUrl(v.website);\n const teamSize = teamSizeDigits(v.teamSize);\n const foundedYear = foundedYearDigits(v.foundedYear ?? '');\n return {\n name: v.name.trim(),\n industry: v.industry ?? undefined,\n stage: v.stage ?? undefined,\n ...(tagline ? { tagline } : {}),\n ...(website ? { website } : {}),\n ...(teamSize ? { teamSize: Number(teamSize) } : {}),\n ...(foundedYear ? { foundedYear: Number(foundedYear) } : {}),\n };\n}\n\n/**\n * What `completeOnboardingBodyFrom` builds: the finish body's INPUT, any part\n * of it possibly still missing. Not a valid body until\n * `completeOnboardingBodySchema` says so.\n */\nexport type CompleteOnboardingBodyCandidate = DeepPartial<CompleteOnboardingBodyInput>;\n\n/** Answers with nothing filled in: what a new member starts from. */\nexport function emptyOnboardingForm(): OnboardingForm {\n return readOnboardingDraft({});\n}\n\n/**\n * True when the member has started describing a business: any of the\n * venture's own answers. Then it is sent, and the schema asks for its name,\n * industry and stage.\n *\n * The business type and the registration do not start it: they DESCRIBE a\n * business. Picked without one, each is sent anyway and refused on its own\n * field (`ventureRequired`: add the business, or clear this), never dropped\n * without a word (hary's ruling).\n */\nexport function ventureStarted(form: Pick<OnboardingForm, 'venture'>): boolean {\n const v = form.venture;\n return Boolean(v.name.trim() || v.website.trim() || v.industry || v.stage || v.teamSize.trim());\n}\n\n/**\n * True when a place has been given (0.19.0). The drawer hands back only a\n * whole place (state, district, and a locality or the whole district), so\n * there is no half answer: a place is there or it is not.\n */\nexport function locationStarted(place: Place | null): boolean {\n return place !== null;\n}\n\n/**\n * The draft one step saves: exactly the fields that step owns\n * (`FOUNDER_ONBOARDING_STEPS[].fields`, the same picks its validation uses),\n * as typed. Only the step's own fields, so a save can never overwrite another\n * step's answers (the server merges per field); raw, so a member who comes back\n * sees what they typed. The photo step's field is its upload id, which the\n * server holds rather than drafts.\n */\nexport function onboardingDraftForStep(\n form: OnboardingForm,\n key: OnboardingStepKey,\n): Partial<OnboardingForm> {\n const step = FOUNDER_ONBOARDING_STEPS[ONBOARDING_STEP_KEYS.indexOf(key)];\n const draft: Partial<OnboardingForm> = {};\n for (const field of step?.fields ?? []) copyField(draft, form, field);\n return draft;\n}\n\n/** One field across, typed by its key (0.18.0: the draft is the FORM's shape, never `unknown`). */\nfunction copyField<K extends keyof OnboardingForm>(\n to: Partial<OnboardingForm>,\n from: OnboardingForm,\n key: K,\n): void {\n to[key] = from[key];\n}\n\n/**\n * What Finish sends, and what every step is CHECKED as (each step's slice\n * reads its own fields from it).\n *\n * ⚠ ABSENT, NEVER A DEFAULT. The sibling gym product sent `bloodGroup ?? 'O+'`\n * and recorded everyone who skipped the question as O-positive. An optional\n * answer not given is left out; nothing is filled with a plausible value.\n *\n * Cleaned the way the schema reads it: the name tidied (`tidyFullName`), the\n * phone to ten digits (`normalizePhone`), links given their scheme\n * (`normalizeLinkUrl`), the place as its area ids (`pickOfPlace`, 0.19.0:\n * the server names it), the team size a number. A half-answered part is\n * SENT, not hidden: a business without its stage reaches the schema and is\n * refused there, under the field.\n */\nexport function completeOnboardingBodyFrom(form: OnboardingForm): CompleteOnboardingBodyCandidate {\n const headline = form.headline.trim();\n const about = form.about.trim();\n\n const links: Partial<Record<keyof OnboardingForm['links'], string>> = {};\n for (const k of Object.keys(form.links) as (keyof OnboardingForm['links'])[]) {\n const url = normalizeLinkUrl(form.links[k]);\n if (url) links[k] = url;\n }\n\n const body: CompleteOnboardingBodyCandidate = {\n displayName: tidyFullName(form.displayName),\n gender: form.gender ?? undefined,\n dateOfBirth: form.dateOfBirth.trim(),\n phone: normalizePhone(form.phone),\n goals: form.goals,\n interests: form.interests,\n // Only agreement to the CURRENT text is sent; anything else is absent, so\n // the schema refuses it as not agreed. Consent to an older text is not\n // consent to this one.\n guidelinesVersion:\n form.guidelinesVersion === GUIDELINES_VERSION ? GUIDELINES_VERSION : undefined,\n };\n if (headline) body.headline = headline;\n if (about) body.about = about;\n if (form.avatarMediaId) body.avatarMediaId = form.avatarMediaId;\n if (form.skills.length) body.skills = form.skills;\n if (Object.keys(links).length) body.links = links;\n\n if (form.location) body.location = pickOfPlace(form.location);\n\n if (ventureStarted(form)) body.venture = ventureBodyFrom(form.venture);\n // Sent whenever given: with a business they describe it, without one the\n // schema refuses each on its own field rather than anything vanishing.\n if (form.businessType) body.businessType = form.businessType;\n if (form.legalStructure) body.legalStructure = form.legalStructure;\n\n return body;\n}\n"]}
1
+ {"version":3,"file":"onboarding-answers.js","sourceRoot":"","sources":["../../../src/domains/onboarding/onboarding-answers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema — From a member's onboarding answers to what is sent (0.17.0)\n *\n * The answers are an `OnboardingForm` (the in-progress shape: raw text, `null`\n * for a choice not made). Two things are built from them, and until 0.17.0\n * each client built them by hand, so a second client (the app) would have had\n * to copy every rule below and keep it in step:\n *\n * the draft a step SAVES exactly the fields that step owns, as typed\n * (`onboardingDraftForStep`)\n * the body FINISH sends completed answers only, cleaned, every\n * unanswered optional field ABSENT\n * (`completeOnboardingBodyFrom`)\n *\n * Neither validates: `ONBOARDING_STEP_SCHEMAS` and `completeOnboardingBodySchema`\n * do, on what these build. A half-filled form builds a half-filled body on\n * purpose, so the schema refuses it with the reason under each field instead\n * of a builder hiding the gap.\n *\n * @module founder-schema/domains/onboarding/onboarding-answers\n */\n\nimport {\n type Industry,\n normalizeLinkUrl,\n normalizePhone,\n type StartupStage,\n tidyFullName,\n} from '../../core/common.js';\nimport { FOUNDED_YEAR_MIN } from '../../core/limits.js';\nimport { type Place, pickOfPlace } from '../location/areas.js';\nimport {\n type CompleteOnboardingBodyInput,\n FOUNDER_ONBOARDING_STEPS,\n GUIDELINES_VERSION,\n ONBOARDING_STEP_KEYS,\n type OnboardingForm,\n type OnboardingStepKey,\n readOnboardingDraft,\n teamSizeDigits,\n} from './onboarding.js';\n\ntype DeepPartial<T> = T extends readonly (infer Item)[]\n ? DeepPartial<Item>[]\n : T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\n/**\n * A founding year as typed, kept to digits, as many as a year has (0.18.0,\n * moved from the web's Me editor beside `teamSizeDigits`).\n */\nexport const foundedYearDigits = (raw: string): string =>\n raw.replace(/\\D/g, '').slice(0, String(FOUNDED_YEAR_MIN).length);\n\n/**\n * A venture body from what was typed (0.18.0): ONE builder for onboarding's\n * business step and Me's business editor, which each built it by hand and\n * cleaned the team size two ways. Text trimmed, the website made a link\n * (`normalizeLinkUrl`), digits kept (`teamSizeDigits`, `foundedYearDigits`);\n * an empty optional answer is ABSENT. A missing name, industry or stage is\n * left missing, so `ventureSchema` refuses it under its field.\n */\nexport function ventureBodyFrom(v: {\n name: string;\n website: string;\n industry: Industry | null;\n stage: StartupStage | null;\n teamSize: string;\n tagline?: string;\n foundedYear?: string;\n}): {\n name: string;\n industry: Industry | undefined;\n stage: StartupStage | undefined;\n tagline?: string;\n website?: string;\n teamSize?: number;\n foundedYear?: number;\n} {\n const tagline = v.tagline?.trim();\n const website = normalizeLinkUrl(v.website);\n const teamSize = teamSizeDigits(v.teamSize);\n const foundedYear = foundedYearDigits(v.foundedYear ?? '');\n return {\n name: v.name.trim(),\n industry: v.industry ?? undefined,\n stage: v.stage ?? undefined,\n ...(tagline ? { tagline } : {}),\n ...(website ? { website } : {}),\n ...(teamSize ? { teamSize: Number(teamSize) } : {}),\n ...(foundedYear ? { foundedYear: Number(foundedYear) } : {}),\n };\n}\n\n/**\n * What `completeOnboardingBodyFrom` builds: the finish body's INPUT, any part\n * of it possibly still missing. Not a valid body until\n * `completeOnboardingBodySchema` says so.\n */\nexport type CompleteOnboardingBodyCandidate = DeepPartial<CompleteOnboardingBodyInput>;\n\n/** Answers with nothing filled in: what a new member starts from. */\nexport function emptyOnboardingForm(): OnboardingForm {\n return readOnboardingDraft({});\n}\n\n/**\n * True when the member has started describing a business: any of the\n * venture's own answers. Then it is sent, and the schema asks for its name,\n * industry and stage.\n *\n * The business type and the registration do not start it: they DESCRIBE a\n * business. Picked without one, each is sent anyway and refused on its own\n * field (`ventureRequired`: add the business, or clear this), never dropped\n * without a word (hary's ruling).\n */\nexport function ventureStarted(form: Pick<OnboardingForm, 'venture'>): boolean {\n const v = form.venture;\n return Boolean(v.name.trim() || v.website.trim() || v.industry || v.stage || v.teamSize.trim());\n}\n\n/**\n * True when a place has been given (0.19.0). The drawer hands back only a\n * whole place (state, district, and a locality or the whole district), so\n * there is no half answer: a place is there or it is not.\n */\nexport function locationStarted(place: Place | null): boolean {\n return place !== null;\n}\n\n/**\n * The draft one step saves: exactly the fields that step owns\n * (`FOUNDER_ONBOARDING_STEPS[].fields`, the same picks its validation uses),\n * as typed. Only the step's own fields, so a save can never overwrite another\n * step's answers (the server merges per field); raw, so a member who comes back\n * sees what they typed. The photo step's field is its upload id, which the\n * server holds rather than drafts.\n */\nexport function onboardingDraftForStep(\n form: OnboardingForm,\n key: OnboardingStepKey,\n): Partial<OnboardingForm> {\n const step = FOUNDER_ONBOARDING_STEPS[ONBOARDING_STEP_KEYS.indexOf(key)];\n const draft: Partial<OnboardingForm> = {};\n for (const field of step?.fields ?? []) copyField(draft, form, field);\n return draft;\n}\n\n/** One field across, typed by its key (0.18.0: the draft is the FORM's shape, never `unknown`). */\nfunction copyField<K extends keyof OnboardingForm>(\n to: Partial<OnboardingForm>,\n from: OnboardingForm,\n key: K,\n): void {\n to[key] = from[key];\n}\n\n/**\n * What Finish sends, and what every step is CHECKED as (each step's slice\n * reads its own fields from it).\n *\n * ⚠ ABSENT, NEVER A DEFAULT. The sibling gym product sent `bloodGroup ?? 'O+'`\n * and recorded everyone who skipped the question as O-positive. An optional\n * answer not given is left out; nothing is filled with a plausible value.\n *\n * Cleaned the way the schema reads it: the name tidied (`tidyFullName`), the\n * phone to ten digits (`normalizePhone`), links given their scheme\n * (`normalizeLinkUrl`), the place as its area ids (`pickOfPlace`, 0.19.0:\n * the server names it), the team size a number. A half-answered part is\n * SENT, not hidden: a business without its stage reaches the schema and is\n * refused there, under the field.\n */\nexport function completeOnboardingBodyFrom(form: OnboardingForm): CompleteOnboardingBodyCandidate {\n const headline = form.headline.trim();\n const about = form.about.trim();\n\n const links: Partial<Record<keyof OnboardingForm['links'], string>> = {};\n for (const k of Object.keys(form.links) as (keyof OnboardingForm['links'])[]) {\n const url = normalizeLinkUrl(form.links[k]);\n if (url) links[k] = url;\n }\n\n const body: CompleteOnboardingBodyCandidate = {\n fullName: tidyFullName(form.fullName),\n gender: form.gender ?? undefined,\n dateOfBirth: form.dateOfBirth.trim(),\n phone: normalizePhone(form.phone),\n goals: form.goals,\n interests: form.interests,\n // Only agreement to the CURRENT text is sent; anything else is absent, so\n // the schema refuses it as not agreed. Consent to an older text is not\n // consent to this one.\n guidelinesVersion:\n form.guidelinesVersion === GUIDELINES_VERSION ? GUIDELINES_VERSION : undefined,\n };\n if (headline) body.headline = headline;\n if (about) body.about = about;\n if (form.avatarMediaId) body.avatarMediaId = form.avatarMediaId;\n if (form.skills.length) body.skills = form.skills;\n if (Object.keys(links).length) body.links = links;\n\n if (form.location) body.location = pickOfPlace(form.location);\n\n if (ventureStarted(form)) body.venture = ventureBodyFrom(form.venture);\n // Sent whenever given: with a business they describe it, without one the\n // schema refuses each on its own field rather than anything vanishing.\n if (form.businessType) body.businessType = form.businessType;\n if (form.legalStructure) body.legalStructure = form.legalStructure;\n\n return body;\n}\n"]}
@@ -457,8 +457,9 @@ export declare const teamSizeDigits: (raw: string) => string;
457
457
  *
458
458
  * Screens may hold a different shape on top of this one. Derive that type from
459
459
  * `OnboardingForm` rather than writing it out, so a field added here reaches
460
- * every screen. (Since 0.16.0 the name is asked as one full name, which is
461
- * `displayName` as typed; first and last name are deduced by `splitFullName`.)
460
+ * every screen. (Since 0.16.0 the name is asked as one full name; since 0.20.0
461
+ * its key is `fullName`, and the server splits it into the first and last name
462
+ * it stores, the display name being those two joined.)
462
463
  *
463
464
  * A stored draft is UNTRUSTED when it comes back: an older client, or another
464
465
  * one, wrote it, and the server stores values opaquely. Read it with
@@ -471,7 +472,7 @@ export declare const PHONE_INPUT_MAX = 20;
471
472
  /** Longest guidelines version an answer may carry (`GUIDELINES_VERSION` is a date). */
472
473
  export declare const GUIDELINES_VERSION_MAX = 32;
473
474
  export declare const onboardingFormSchema: z.ZodObject<{
474
- displayName: z.ZodString;
475
+ fullName: z.ZodString;
475
476
  gender: z.ZodNullable<z.ZodEnum<{
476
477
  other: "other";
477
478
  male: "male";
@@ -752,7 +753,7 @@ export declare function readOnboardingDraft(draft: unknown): OnboardingForm;
752
753
  * `.shape.<field>`, a step's with `ONBOARDING_STEP_SCHEMAS.<step>`.
753
754
  */
754
755
  export declare const completeOnboardingBodySchema: z.ZodObject<{
755
- displayName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
756
+ fullName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
756
757
  gender: z.ZodEnum<{
757
758
  other: "other";
758
759
  male: "male";
@@ -966,7 +967,6 @@ export type CompleteOnboardingBodyInput = z.input<typeof completeOnboardingBodyS
966
967
  */
967
968
  export declare const ONBOARDING_STEP_SCHEMAS: {
968
969
  readonly basics: z.ZodObject<{
969
- displayName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
970
970
  gender: z.ZodEnum<{
971
971
  other: "other";
972
972
  male: "male";
@@ -974,6 +974,7 @@ export declare const ONBOARDING_STEP_SCHEMAS: {
974
974
  prefer_not_to_say: "prefer_not_to_say";
975
975
  }>;
976
976
  dateOfBirth: z.ZodString;
977
+ fullName: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
977
978
  }, z.core.$strip>;
978
979
  readonly photo: z.ZodObject<{
979
980
  avatarMediaId: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
@@ -1233,7 +1234,6 @@ export type CompleteOnboardingResponse = z.infer<typeof completeOnboardingRespon
1233
1234
  export declare const onboardingDraftKeySchema: z.ZodEnum<{
1234
1235
  location: "location";
1235
1236
  about: "about";
1236
- displayName: "displayName";
1237
1237
  headline: "headline";
1238
1238
  venture: "venture";
1239
1239
  skills: "skills";
@@ -1242,13 +1242,14 @@ export declare const onboardingDraftKeySchema: z.ZodEnum<{
1242
1242
  phone: "phone";
1243
1243
  gender: "gender";
1244
1244
  dateOfBirth: "dateOfBirth";
1245
+ fullName: "fullName";
1245
1246
  interests: "interests";
1246
1247
  avatarMediaId: "avatarMediaId";
1247
1248
  businessType: "businessType";
1248
1249
  legalStructure: "legalStructure";
1249
1250
  guidelinesVersion: "guidelinesVersion";
1250
1251
  }>;
1251
- export declare const ONBOARDING_DRAFT_KEYS: ("location" | "about" | "displayName" | "headline" | "venture" | "skills" | "goals" | "links" | "phone" | "gender" | "dateOfBirth" | "interests" | "avatarMediaId" | "businessType" | "legalStructure" | "guidelinesVersion")[];
1252
+ export declare const ONBOARDING_DRAFT_KEYS: ("location" | "about" | "headline" | "venture" | "skills" | "goals" | "links" | "phone" | "gender" | "dateOfBirth" | "fullName" | "interests" | "avatarMediaId" | "businessType" | "legalStructure" | "guidelinesVersion")[];
1252
1253
  export type OnboardingDraftKey = z.infer<typeof onboardingDraftKeySchema>;
1253
1254
  /**
1254
1255
  * Where the member got to, kept in its own collection, separate from the
@@ -1270,7 +1271,6 @@ export type OnboardingDraftKey = z.infer<typeof onboardingDraftKeySchema>;
1270
1271
  export declare const onboardingDraftSchema: z.ZodRecord<z.ZodEnum<{
1271
1272
  location: "location";
1272
1273
  about: "about";
1273
- displayName: "displayName";
1274
1274
  headline: "headline";
1275
1275
  venture: "venture";
1276
1276
  skills: "skills";
@@ -1279,6 +1279,7 @@ export declare const onboardingDraftSchema: z.ZodRecord<z.ZodEnum<{
1279
1279
  phone: "phone";
1280
1280
  gender: "gender";
1281
1281
  dateOfBirth: "dateOfBirth";
1282
+ fullName: "fullName";
1282
1283
  interests: "interests";
1283
1284
  avatarMediaId: "avatarMediaId";
1284
1285
  businessType: "businessType";
@@ -1297,7 +1298,7 @@ export type OnboardingDraft = z.infer<typeof onboardingDraftSchema>;
1297
1298
  export declare const onboardingProgressUpdateSchema: z.ZodObject<{
1298
1299
  step: z.ZodOptional<z.ZodNumber>;
1299
1300
  draft: z.ZodOptional<z.ZodObject<{
1300
- displayName: z.ZodOptional<z.ZodString>;
1301
+ fullName: z.ZodOptional<z.ZodString>;
1301
1302
  gender: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
1302
1303
  other: "other";
1303
1304
  male: "male";
@@ -1555,7 +1556,6 @@ export declare const onboardingStatusSchema: z.ZodObject<{
1555
1556
  draft: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
1556
1557
  location: "location";
1557
1558
  about: "about";
1558
- displayName: "displayName";
1559
1559
  headline: "headline";
1560
1560
  venture: "venture";
1561
1561
  skills: "skills";
@@ -1564,6 +1564,7 @@ export declare const onboardingStatusSchema: z.ZodObject<{
1564
1564
  phone: "phone";
1565
1565
  gender: "gender";
1566
1566
  dateOfBirth: "dateOfBirth";
1567
+ fullName: "fullName";
1567
1568
  interests: "interests";
1568
1569
  avatarMediaId: "avatarMediaId";
1569
1570
  businessType: "businessType";
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../../src/domains/onboarding/onboarding.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../../src/domains/onboarding/onboarding.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,7 @@
26
26
  * @module founder-schema/domains/onboarding
27
27
  */
28
28
  import { z } from 'zod';
29
- import { displayNameSchema, eachOnce, GENDER_VALUES, GOAL_VALUES, genderSchema, goalSchema, INDUSTRY_VALUES, industrySchema, objectIdSchema, optionalTrimmedString, phoneSchema, requiredGoalListSchema, SKILL_VALUES, STARTUP_STAGE_VALUES, skillListSchema, skillSchema, startupStageSchema, usernameSchema, } from '../../core/common.js';
29
+ import { eachOnce, fullNameSchema, GENDER_VALUES, GOAL_VALUES, genderSchema, goalSchema, INDUSTRY_VALUES, industrySchema, objectIdSchema, optionalTrimmedString, phoneSchema, requiredGoalListSchema, SKILL_VALUES, STARTUP_STAGE_VALUES, skillListSchema, skillSchema, startupStageSchema, usernameSchema, } from '../../core/common.js';
30
30
  import { ABOUT_MAX, DAY_MS, DISPLAY_NAME_MAX, HEADLINE_MAX, INDIA_UTC_OFFSET_MS, LINK_URL_MAX, SKILLS_MAX, TEAM_SIZE_MAX, VENTURE_NAME_MAX, } from '../../core/limits.js';
31
31
  import { VALIDATION_MESSAGE } from '../../core/validation.js';
32
32
  import { locationPickSchema, placeSchema } from '../location/areas.js';
@@ -581,8 +581,9 @@ export const teamSizeDigits = (raw) => raw.replace(/\D/g, '').slice(0, TEAM_SIZE
581
581
  *
582
582
  * Screens may hold a different shape on top of this one. Derive that type from
583
583
  * `OnboardingForm` rather than writing it out, so a field added here reaches
584
- * every screen. (Since 0.16.0 the name is asked as one full name, which is
585
- * `displayName` as typed; first and last name are deduced by `splitFullName`.)
584
+ * every screen. (Since 0.16.0 the name is asked as one full name; since 0.20.0
585
+ * its key is `fullName`, and the server splits it into the first and last name
586
+ * it stores, the display name being those two joined.)
586
587
  *
587
588
  * A stored draft is UNTRUSTED when it comes back: an older client, or another
588
589
  * one, wrote it, and the server stores values opaquely. Read it with
@@ -595,7 +596,7 @@ export const PHONE_INPUT_MAX = 20;
595
596
  /** Longest guidelines version an answer may carry (`GUIDELINES_VERSION` is a date). */
596
597
  export const GUIDELINES_VERSION_MAX = 32;
597
598
  export const onboardingFormSchema = z.object({
598
- displayName: z.string().max(DISPLAY_NAME_MAX),
599
+ fullName: z.string().max(DISPLAY_NAME_MAX),
599
600
  gender: genderSchema.nullable(),
600
601
  /** `YYYY-MM-DD` once complete; whatever has been typed until then. */
601
602
  dateOfBirth: z.string().max(DATE_INPUT_MAX),
@@ -675,7 +676,7 @@ const draftObject = (shape) => z
675
676
  .catch(null)
676
677
  .pipe(z.union([z.null(), z.object(shape)]));
677
678
  const draftReaderSchema = z.object({
678
- displayName: draftText(DISPLAY_NAME_MAX),
679
+ fullName: draftText(DISPLAY_NAME_MAX),
679
680
  gender: draftChoice(GENDER_VALUES),
680
681
  dateOfBirth: draftText(DATE_INPUT_MAX),
681
682
  headline: draftText(HEADLINE_MAX),
@@ -733,7 +734,12 @@ export const EMPTY_ONBOARDING_VENTURE = {
733
734
  * Whatever a screen shows by default is that screen's choice.
734
735
  */
735
736
  export function readOnboardingDraft(draft) {
736
- const source = draft && typeof draft === 'object' && !Array.isArray(draft) ? draft : {};
737
+ const raw = draft && typeof draft === 'object' && !Array.isArray(draft)
738
+ ? draft
739
+ : {};
740
+ // 0.20.0 renamed the name answer `displayName` to `fullName`: a draft saved
741
+ // before keeps the name its member typed.
742
+ const source = 'fullName' in raw || !('displayName' in raw) ? raw : { ...raw, fullName: raw.displayName };
737
743
  return draftReaderSchema.parse(source);
738
744
  }
739
745
  // ─── The finalize body ───────────────────────────────────────────────────────
@@ -745,8 +751,9 @@ export function readOnboardingDraft(draft) {
745
751
  */
746
752
  const completeOnboardingBodyFields = z.object({
747
753
  // Plain bounds, no custom message: `too_small` with minimum 1 already says
748
- // "required", and the client words it in the member's language.
749
- displayName: displayNameSchema,
754
+ // "required", and the client words it in the member's language. The full
755
+ // name as typed (0.20.0): the server splits it and stores first and last.
756
+ fullName: fullNameSchema,
750
757
  /**
751
758
  * ⚠️ NO `username` HERE, and its absence is deliberate.
752
759
  *
@@ -852,7 +859,7 @@ export const ONBOARDING_STEP_SCHEMAS = {
852
859
  // 0.16.0: the old `identity` step, split three ways by the user. The basics
853
860
  // are the step's only required answers; the photo and the professional
854
861
  // details may each be passed over.
855
- basics: completeOnboardingBodyFields.pick({ displayName: true, gender: true, dateOfBirth: true }),
862
+ basics: completeOnboardingBodyFields.pick({ fullName: true, gender: true, dateOfBirth: true }),
856
863
  photo: completeOnboardingBodyFields.pick({ avatarMediaId: true }),
857
864
  professional: completeOnboardingBodyFields.pick({
858
865
  headline: true,
@@ -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. A step's label and title are translation KEYS\n * (`labelKey`, `titleKey`), 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 eachOnce,\n GENDER_VALUES,\n GOAL_VALUES,\n type Goal,\n genderSchema,\n goalSchema,\n INDUSTRY_VALUES,\n industrySchema,\n objectIdSchema,\n optionalTrimmedString,\n phoneSchema,\n requiredGoalListSchema,\n SKILL_VALUES,\n STARTUP_STAGE_VALUES,\n skillListSchema,\n skillSchema,\n startupStageSchema,\n usernameSchema,\n} from '../../core/common.js';\nimport {\n ABOUT_MAX,\n DAY_MS,\n DISPLAY_NAME_MAX,\n HEADLINE_MAX,\n INDIA_UTC_OFFSET_MS,\n LINK_URL_MAX,\n SKILLS_MAX,\n TEAM_SIZE_MAX,\n VENTURE_NAME_MAX,\n} from '../../core/limits.js';\nimport { VALIDATION_MESSAGE } from '../../core/validation.js';\nimport { locationPickSchema, placeSchema } from '../location/areas.js';\nimport { mediaImageSchema } from '../media/media.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 // 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_UTC_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 * True for a `YYYY-MM-DD` that is a real calendar date (0.17.0, exported so a\n * client's date picker checks a date exactly as `dateOfBirthSchema` does):\n * not 2026-02-30, not 2026-13-01.\n */\nexport function isRealIsoDate(value: string): boolean {\n return isoDateSchema.safeParse(value).success && isRealDate(value.trim());\n}\n\n/** `YYYY-MM-DD` for a moment, counted in India's calendar. */\nconst isoInIndia = (moment: number): IsoDate =>\n new Date(moment + INDIA_UTC_OFFSET_MS).toISOString().slice(0, 10);\n\n/**\n * Today in India, `YYYY-MM-DD` (0.17.0): the day every age here is counted\n * from (`ageInYears`), so a client's \"today\" must be this one, never the\n * device's own: east of India the device is already on tomorrow.\n */\nexport function todayInIndia(now: Date = new Date()): IsoDate {\n return isoInIndia(now.getTime());\n}\n\nconst isoOfUtc = (ms: number): IsoDate => new Date(ms).toISOString().slice(0, 10);\n\n/**\n * The dates of birth `dateOfBirthSchema` accepts TODAY, both ends included\n * (0.17.0): `latest` makes someone exactly `MIN_AGE_YEARS` today, `earliest`\n * exactly `MAX_AGE_YEARS`. Worked out with `ageInYears` itself, so a picker\n * that offers only this window can never offer a date the schema refuses, a\n * 29 February included.\n */\nexport function dateOfBirthBounds(now: Date = new Date()): { earliest: IsoDate; latest: IsoDate } {\n const [y, m, d] = todayInIndia(now).split('-').map(Number) as [number, number, number];\n let latest = Date.UTC(y - MIN_AGE_YEARS, m - 1, d);\n while (ageInYears(isoOfUtc(latest), now) < MIN_AGE_YEARS) latest -= DAY_MS;\n let earliest = Date.UTC(y - MAX_AGE_YEARS - 1, m - 1, d);\n while (ageInYears(isoOfUtc(earliest), now) > MAX_AGE_YEARS) earliest += DAY_MS;\n return { earliest: isoOfUtc(earliest), latest: isoOfUtc(latest) };\n}\n\n/**\n * True only for a COMPLETE, real date of birth that is under `MIN_AGE_YEARS`\n * today (0.17.0): the rule the server applies to a draft, where a date still\n * being typed must pass (\"19\" says nothing about anyone's age yet). Until\n * 0.17.0 the backend wrote this out by hand and skipped the real-date check.\n */\nexport function isUnderAgeDateOfBirth(value: unknown, now: Date = new Date()): boolean {\n if (typeof value !== 'string' || !isRealIsoDate(value)) return false;\n return ageInYears(value.trim(), now) < MIN_AGE_YEARS;\n}\n\n/** A `YYYY-MM-DD` as the instant it is stored as: midnight UTC that day (0.17.0). */\nexport const isoDateToDate = (iso: IsoDate): Date => new Date(`${iso.trim()}T00:00:00.000Z`);\n\n/** A stored date (midnight UTC) as `YYYY-MM-DD` (0.17.0): `isoDateToDate`'s inverse. */\nexport const dateToIsoDate = (date: Date): IsoDate => date.toISOString().slice(0, 10);\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\n/**\n * What KIND of business it is, which is not how it is registered\n * (`LEGAL_STRUCTURE_VALUES`): a freelancer may be a sole proprietorship, a\n * startup a private limited company, a social enterprise a Section 8 company.\n *\n * 0.16.0 (the user, 2026-10-18: \"check what more business types we can use\")\n * added the kinds an Indian founder network meets beyond the three it had: the\n * independent professional, the services firm, the social enterprise, the\n * family business and the franchise. `sme` is India's MSME.\n *\n * ⚠ Stored on the profile's venture and a Mongoose enum. Append only.\n */\nexport const BUSINESS_TYPE_VALUES = [\n 'startup',\n 'sme',\n 'enterprise',\n 'freelancer',\n 'agency',\n 'social_enterprise',\n 'family_business',\n 'franchise',\n] as const;\nexport const businessTypeSchema = z.enum(BUSINESS_TYPE_VALUES);\nexport type BusinessType = z.infer<typeof businessTypeSchema>;\n\n/**\n * How the business is registered in India, or that it is not yet (0.16.0, the\n * user, 2026-10-18: \"the categories that we have in India like private\n * limited, LLP or OPC or proprietorship\").\n *\n * The forms Indian law provides: a sole proprietorship and a partnership firm\n * (Indian Partnership Act, 1932), a limited liability partnership (LLP Act,\n * 2008), a one person, private limited, public limited or Section 8 (not for\n * profit) company (Companies Act, 2013), a trust or society, and a\n * co-operative society. Two more are answers a founder often has: not\n * registered yet (an idea, or a side project), and registered outside India\n * (an Indian team whose company is incorporated abroad, often in the US).\n *\n * Optional, like the business type, and private to the member: nothing here\n * verifies it (documents are a settings matter, by the user's ruling).\n *\n * ⚠ Stored on the profile's venture and a Mongoose enum. Append only.\n */\nexport const LEGAL_STRUCTURE_VALUES = [\n 'not_registered',\n 'sole_proprietorship',\n 'partnership',\n 'llp',\n 'opc',\n 'private_limited',\n 'public_limited',\n 'section_8',\n 'trust_or_society',\n 'cooperative',\n 'registered_abroad',\n] as const;\nexport const legalStructureSchema = z.enum(LEGAL_STRUCTURE_VALUES);\nexport type LegalStructure = z.infer<typeof legalStructureSchema>;\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// ─── Goals: the grouping the picker renders ──────────────────────────────────\n\n/**\n * The goals step's three headings (0.17.0, moved here from the web, where the\n * grouping lived in the screen): eighteen goals since 0.16.0, shown a group at\n * a time so the eye takes six tiles, not a wall of eighteen. A group is named\n * by its `key`, which the client words, like a topic category.\n *\n * ⚠ `GOAL_VALUES` stays the single source of truth for what a goal IS; this is\n * typed against it, and a test holds the two together in both directions:\n * every goal in exactly one group, nothing in a group that is not a goal.\n */\nexport const GOAL_CATEGORY_KEYS = ['build', 'grow', 'learn'] as const;\nexport type GoalCategoryKey = (typeof GOAL_CATEGORY_KEYS)[number];\n\n/** One group of the goals picker: its `key` (the client words it) and its goals, in order. */\nexport interface GoalCategory {\n key: GoalCategoryKey;\n values: readonly Goal[];\n}\n\nexport const GOAL_CATEGORIES: readonly GoalCategory[] = [\n {\n key: 'build',\n values: [\n 'start_company',\n 'get_feedback',\n 'find_cofounder',\n 'find_testers',\n 'hiring',\n 'find_service_providers',\n ],\n },\n {\n key: 'grow',\n values: [\n 'find_customers',\n 'find_investors',\n 'partnerships',\n 'market_insights',\n 'business_ideas',\n 'grow_network',\n ],\n },\n {\n key: 'learn',\n values: [\n 'learn_startup',\n 'mentorship',\n 'attend_events',\n 'join_startup',\n 'mentor_others',\n 'invest_in_startups',\n ],\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/**\n * A member's interests, by ONE rule (0.16.0): onboarding's finish and the Me\n * tab's editor (`putMyInterestsBodySchema`) both apply this very schema, so a\n * list one accepts the other can never refuse.\n *\n * Each topic only once: without that, three copies of one topic met the\n * minimum of three while meaning one interest.\n */\nexport const interestsSchema = z\n .array(topicSchema)\n .min(INTERESTS_MIN)\n .max(INTERESTS_MAX)\n .refine(eachOnce, {\n error: VALIDATION_MESSAGE.topicsDuplicate,\n });\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 *\n * 0.16.0 (the user, 2026-10-18) split the old first step, `identity`, into\n * three: `basics` (full name, gender, date of birth, nothing else), `photo`\n * (the photo alone) and `professional` (title, about, skills). Nine steps, up\n * from seven.\n *\n * ⚠ THE SERVER'S RESUME CURSOR IS AN INDEX INTO THIS LIST, so re-ordering it\n * moves every member who stopped part-way. A cursor saved under the old seven\n * is translated by the backend (its progress rows carry the list's version);\n * any further change needs the same.\n */\nexport const ONBOARDING_STEP_KEYS = [\n 'basics',\n 'photo',\n 'professional',\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;\n/**\n * Not agreed at all (the box left unticked) is `guidelinesRequired`; agreed to\n * another text is `guidelinesOutdated` (0.17.0: both were the second, so a\n * client had to word an unticked box itself).\n */\nexport const guidelinesVersionSchema = z.literal(GUIDELINES_VERSION, {\n error: (issue) =>\n issue.input === undefined || issue.input === null\n ? VALIDATION_MESSAGE.guidelinesRequired\n : 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/**\n * A team size as typed, kept to what the field may hold: digits only, at most\n * `TEAM_SIZE_DIGITS_MAX` (0.17.0: the draft reader and every client's field\n * clean it with this one rule).\n */\nexport const teamSizeDigits = (raw: string): string =>\n raw.replace(/\\D/g, '').slice(0, TEAM_SIZE_DIGITS_MAX);\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. Derive that type from\n * `OnboardingForm` rather than writing it out, so a field added here reaches\n * every screen. (Since 0.16.0 the name is asked as one full name, which is\n * `displayName` as typed; first and last name are deduced by `splitFullName`.)\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 */\n/** Longest date of birth an answer may be: `YYYY-MM-DD` (0.18.0: exported; the form and the draft reader use it). */\nexport const DATE_INPUT_MAX = 10;\n/** Longest phone number an answer may be, as typed with spaces and a `+91`. */\nexport const PHONE_INPUT_MAX = 20;\n/** Longest guidelines version an answer may carry (`GUIDELINES_VERSION` is a date). */\nexport const GUIDELINES_VERSION_MAX = 32;\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().max(DATE_INPUT_MAX),\n headline: z.string().max(HEADLINE_MAX),\n about: z.string().max(ABOUT_MAX),\n /**\n * The completed upload's id (`media`, purpose `avatar`), or `null` for no\n * photo.\n *\n * SAVED BY THE PHOTO STEP, KEPT BY THE SERVER, NOT IN THE DRAFT (0.17.0). A\n * step save carrying this key hands the upload to the server, which holds it\n * for the draft (so the unattached sweep, `MEDIA_UNATTACHED_TTL_HOURS`, never\n * deletes it) and lets go of the one it replaces; `null` lets go of it. It\n * comes back as the status's `photo`, read from what the server holds, never\n * from a stored draft: `readOnboardingDraft` still gives `null` here, so an\n * id an older client left in a draft is never trusted.\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().max(PHONE_INPUT_MAX),\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 /**\n * `null` until the member picks a place (the drawer, or GPS then confirmed),\n * and when they leave the step without one (0.19.0: a place from\n * `master_db`, with its names, so the step shows it again after a reload).\n */\n location: placeSchema.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 legalStructure: legalStructureSchema.nullable(),\n\n /** The guidelines text the member agreed to, or `null`. */\n guidelinesVersion: z.string().max(GUIDELINES_VERSION_MAX).nullable(),\n});\nexport type OnboardingForm = z.infer<typeof onboardingFormSchema>;\n\n// ─── Reading a stored draft back ─────────────────────────────────────────────\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 // A place, whole or not at all: a draft saved before 0.19.0 held a typed\n // city and state, which name no area, so it reads as \"not answered yet\".\n location: placeSchema.nullable().catch(null),\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.string().catch('').transform(teamSizeDigits),\n }).transform((venture) => venture ?? { ...EMPTY_ONBOARDING_VENTURE }),\n businessType: draftChoice(BUSINESS_TYPE_VALUES),\n legalStructure: draftChoice(LEGAL_STRUCTURE_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 from here (it comes back as the status's `photo`; see\n * `avatarMediaId`), and agreement only counts for the 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 * The finish body's fields, before the rules that span fields: what each\n * step's slice is PICKED from (Zod 4 refuses `.pick` on a refined object).\n * Everything outside this file reads `completeOnboardingBodySchema`, whose\n * note below says what the body is.\n */\nconst completeOnboardingBodyFields = 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 /**\n * Absent when the member left the step without a place. Area ids (0.19.0,\n * `locationPickSchema`): the server names the place from `master_db`.\n */\n location: locationPickSchema.optional(),\n\n /** The shared list rule (each goal once, 0.17.0) plus finish's minimum. */\n goals: requiredGoalListSchema,\n interests: interestsSchema,\n skills: skillListSchema.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 /** How the venture is registered, if the member says. Stored on the venture, like the type. */\n legalStructure: legalStructureSchema.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});\n\n/**\n * The business type and how it is registered DESCRIBE a venture, and are\n * stored on it (0.17.0): without one there is nothing to describe. Each is\n * refused ON ITS OWN FIELD (`ventureRequired`: add the business, or clear this\n * answer), never dropped without a word, as the server did and as the web did\n * with a lone \"Not registered yet\" (hary's ruling: no silent drop).\n */\ntype VentureAnswers = { venture?: unknown; businessType?: unknown; legalStructure?: unknown };\nconst typeHasVenture = (body: VentureAnswers): boolean =>\n body.venture !== undefined || body.businessType === undefined;\nconst registrationHasVenture = (body: VentureAnswers): boolean =>\n body.venture !== undefined || body.legalStructure === undefined;\nconst TYPE_NEEDS_VENTURE = { error: VALIDATION_MESSAGE.ventureRequired, path: ['businessType'] };\nconst REGISTRATION_NEEDS_VENTURE = {\n error: VALIDATION_MESSAGE.ventureRequired,\n path: ['legalStructure'],\n};\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 *\n * Refined (the business type and registration need a venture, above), so Zod 4\n * throws on `.pick` / `.omit` / `.partial` / `.merge` of it: read a field with\n * `.shape.<field>`, a step's with `ONBOARDING_STEP_SCHEMAS.<step>`.\n */\nexport const completeOnboardingBodySchema = completeOnboardingBodyFields\n .refine(typeHasVenture, TYPE_NEEDS_VENTURE)\n .refine(registrationHasVenture, REGISTRATION_NEEDS_VENTURE);\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 // 0.16.0: the old `identity` step, split three ways by the user. The basics\n // are the step's only required answers; the photo and the professional\n // details may each be passed over.\n basics: completeOnboardingBodyFields.pick({ displayName: true, gender: true, dateOfBirth: true }),\n photo: completeOnboardingBodyFields.pick({ avatarMediaId: true }),\n professional: completeOnboardingBodyFields.pick({\n headline: true,\n about: true,\n // Ruling D8 folded the design's \"title, achievements, skills\" screen into\n // the profile's first questions; it now has a step of its own again.\n skills: true,\n }),\n contact: completeOnboardingBodyFields.pick({ phone: true, links: true }),\n location: completeOnboardingBodyFields.pick({ location: true }),\n goals: completeOnboardingBodyFields.pick({ goals: true }),\n interests: completeOnboardingBodyFields.pick({ interests: true }),\n business: completeOnboardingBodyFields\n .pick({\n venture: true,\n businessType: true,\n legalStructure: true,\n })\n .refine(typeHasVenture, TYPE_NEEDS_VENTURE)\n .refine(registrationHasVenture, REGISTRATION_NEEDS_VENTURE),\n guidelines: completeOnboardingBodyFields.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 /**\n * Translation keys for what the step's header shows: its short label beside\n * the step number (\"STEP 5 OF 9 · LOCATION\") and its one question. The words\n * live in each client. There is no help line (the user removed it,\n * 2026-10-19; `helpKey` went in 0.17.0): who sees an answer is said on the\n * field it is about.\n */\n labelKey: `onboarding.steps.${OnboardingStepKey}.label`;\n titleKey: `onboarding.steps.${OnboardingStepKey}.title`;\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 labelKey: `onboarding.steps.${key}.label`,\n titleKey: `onboarding.steps.${key}.title`,\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: objectIdSchema,\n username: usernameSchema,\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 * What is READ BACK: the draft's KEYS come from the form, its VALUES are\n * opaque, since a stored draft may predate 0.18.0 (any JSON was stored then);\n * read it through `readOnboardingDraft`, never by casting. What is WRITTEN is\n * the form's own shape (`onboardingProgressUpdateSchema.draft`, 0.18.0), and\n * everything 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\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 *\n * The photo step's `avatarMediaId` is not kept in the draft (0.17.0): it is\n * handed to the server, which holds that upload for the member.\n */\nexport const onboardingProgressUpdateSchema = z.object({\n step: z.number().int().min(0).max(ONBOARDING_TOTAL_STEPS).optional(),\n /**\n * The answers of the step being saved, IN THE FORM'S OWN SHAPE (0.18.0):\n * half-answered is fine (that is the form: text as typed, `null` for \"not\n * yet\"), but every value has its type and its bound, and no other key is\n * taken. Before 0.18.0 any JSON up to the body limit was stored as sent,\n * for 90 days, and sent back. The photo's id reads as `objectIdSchema` reads\n * every id (lower case), since the server compares it with the upload it\n * holds.\n */\n draft: onboardingFormSchema.partial().strict().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 /**\n * The photo the member saved on the photo step, as it will appear (0.17.0):\n * the upload the server holds for this member's draft. Absent when they\n * saved none, removed it, or have finished. A client resumes the photo step\n * from this (its `id` is the finish body's `avatarMediaId`), never from the\n * draft.\n */\n photo: mediaImageSchema.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. A step's label and title are translation KEYS\n * (`labelKey`, `titleKey`), 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 eachOnce,\n fullNameSchema,\n GENDER_VALUES,\n GOAL_VALUES,\n type Goal,\n genderSchema,\n goalSchema,\n INDUSTRY_VALUES,\n industrySchema,\n objectIdSchema,\n optionalTrimmedString,\n phoneSchema,\n requiredGoalListSchema,\n SKILL_VALUES,\n STARTUP_STAGE_VALUES,\n skillListSchema,\n skillSchema,\n startupStageSchema,\n usernameSchema,\n} from '../../core/common.js';\nimport {\n ABOUT_MAX,\n DAY_MS,\n DISPLAY_NAME_MAX,\n HEADLINE_MAX,\n INDIA_UTC_OFFSET_MS,\n LINK_URL_MAX,\n SKILLS_MAX,\n TEAM_SIZE_MAX,\n VENTURE_NAME_MAX,\n} from '../../core/limits.js';\nimport { VALIDATION_MESSAGE } from '../../core/validation.js';\nimport { locationPickSchema, placeSchema } from '../location/areas.js';\nimport { mediaImageSchema } from '../media/media.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 // 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_UTC_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 * True for a `YYYY-MM-DD` that is a real calendar date (0.17.0, exported so a\n * client's date picker checks a date exactly as `dateOfBirthSchema` does):\n * not 2026-02-30, not 2026-13-01.\n */\nexport function isRealIsoDate(value: string): boolean {\n return isoDateSchema.safeParse(value).success && isRealDate(value.trim());\n}\n\n/** `YYYY-MM-DD` for a moment, counted in India's calendar. */\nconst isoInIndia = (moment: number): IsoDate =>\n new Date(moment + INDIA_UTC_OFFSET_MS).toISOString().slice(0, 10);\n\n/**\n * Today in India, `YYYY-MM-DD` (0.17.0): the day every age here is counted\n * from (`ageInYears`), so a client's \"today\" must be this one, never the\n * device's own: east of India the device is already on tomorrow.\n */\nexport function todayInIndia(now: Date = new Date()): IsoDate {\n return isoInIndia(now.getTime());\n}\n\nconst isoOfUtc = (ms: number): IsoDate => new Date(ms).toISOString().slice(0, 10);\n\n/**\n * The dates of birth `dateOfBirthSchema` accepts TODAY, both ends included\n * (0.17.0): `latest` makes someone exactly `MIN_AGE_YEARS` today, `earliest`\n * exactly `MAX_AGE_YEARS`. Worked out with `ageInYears` itself, so a picker\n * that offers only this window can never offer a date the schema refuses, a\n * 29 February included.\n */\nexport function dateOfBirthBounds(now: Date = new Date()): { earliest: IsoDate; latest: IsoDate } {\n const [y, m, d] = todayInIndia(now).split('-').map(Number) as [number, number, number];\n let latest = Date.UTC(y - MIN_AGE_YEARS, m - 1, d);\n while (ageInYears(isoOfUtc(latest), now) < MIN_AGE_YEARS) latest -= DAY_MS;\n let earliest = Date.UTC(y - MAX_AGE_YEARS - 1, m - 1, d);\n while (ageInYears(isoOfUtc(earliest), now) > MAX_AGE_YEARS) earliest += DAY_MS;\n return { earliest: isoOfUtc(earliest), latest: isoOfUtc(latest) };\n}\n\n/**\n * True only for a COMPLETE, real date of birth that is under `MIN_AGE_YEARS`\n * today (0.17.0): the rule the server applies to a draft, where a date still\n * being typed must pass (\"19\" says nothing about anyone's age yet). Until\n * 0.17.0 the backend wrote this out by hand and skipped the real-date check.\n */\nexport function isUnderAgeDateOfBirth(value: unknown, now: Date = new Date()): boolean {\n if (typeof value !== 'string' || !isRealIsoDate(value)) return false;\n return ageInYears(value.trim(), now) < MIN_AGE_YEARS;\n}\n\n/** A `YYYY-MM-DD` as the instant it is stored as: midnight UTC that day (0.17.0). */\nexport const isoDateToDate = (iso: IsoDate): Date => new Date(`${iso.trim()}T00:00:00.000Z`);\n\n/** A stored date (midnight UTC) as `YYYY-MM-DD` (0.17.0): `isoDateToDate`'s inverse. */\nexport const dateToIsoDate = (date: Date): IsoDate => date.toISOString().slice(0, 10);\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\n/**\n * What KIND of business it is, which is not how it is registered\n * (`LEGAL_STRUCTURE_VALUES`): a freelancer may be a sole proprietorship, a\n * startup a private limited company, a social enterprise a Section 8 company.\n *\n * 0.16.0 (the user, 2026-10-18: \"check what more business types we can use\")\n * added the kinds an Indian founder network meets beyond the three it had: the\n * independent professional, the services firm, the social enterprise, the\n * family business and the franchise. `sme` is India's MSME.\n *\n * ⚠ Stored on the profile's venture and a Mongoose enum. Append only.\n */\nexport const BUSINESS_TYPE_VALUES = [\n 'startup',\n 'sme',\n 'enterprise',\n 'freelancer',\n 'agency',\n 'social_enterprise',\n 'family_business',\n 'franchise',\n] as const;\nexport const businessTypeSchema = z.enum(BUSINESS_TYPE_VALUES);\nexport type BusinessType = z.infer<typeof businessTypeSchema>;\n\n/**\n * How the business is registered in India, or that it is not yet (0.16.0, the\n * user, 2026-10-18: \"the categories that we have in India like private\n * limited, LLP or OPC or proprietorship\").\n *\n * The forms Indian law provides: a sole proprietorship and a partnership firm\n * (Indian Partnership Act, 1932), a limited liability partnership (LLP Act,\n * 2008), a one person, private limited, public limited or Section 8 (not for\n * profit) company (Companies Act, 2013), a trust or society, and a\n * co-operative society. Two more are answers a founder often has: not\n * registered yet (an idea, or a side project), and registered outside India\n * (an Indian team whose company is incorporated abroad, often in the US).\n *\n * Optional, like the business type, and private to the member: nothing here\n * verifies it (documents are a settings matter, by the user's ruling).\n *\n * ⚠ Stored on the profile's venture and a Mongoose enum. Append only.\n */\nexport const LEGAL_STRUCTURE_VALUES = [\n 'not_registered',\n 'sole_proprietorship',\n 'partnership',\n 'llp',\n 'opc',\n 'private_limited',\n 'public_limited',\n 'section_8',\n 'trust_or_society',\n 'cooperative',\n 'registered_abroad',\n] as const;\nexport const legalStructureSchema = z.enum(LEGAL_STRUCTURE_VALUES);\nexport type LegalStructure = z.infer<typeof legalStructureSchema>;\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// ─── Goals: the grouping the picker renders ──────────────────────────────────\n\n/**\n * The goals step's three headings (0.17.0, moved here from the web, where the\n * grouping lived in the screen): eighteen goals since 0.16.0, shown a group at\n * a time so the eye takes six tiles, not a wall of eighteen. A group is named\n * by its `key`, which the client words, like a topic category.\n *\n * ⚠ `GOAL_VALUES` stays the single source of truth for what a goal IS; this is\n * typed against it, and a test holds the two together in both directions:\n * every goal in exactly one group, nothing in a group that is not a goal.\n */\nexport const GOAL_CATEGORY_KEYS = ['build', 'grow', 'learn'] as const;\nexport type GoalCategoryKey = (typeof GOAL_CATEGORY_KEYS)[number];\n\n/** One group of the goals picker: its `key` (the client words it) and its goals, in order. */\nexport interface GoalCategory {\n key: GoalCategoryKey;\n values: readonly Goal[];\n}\n\nexport const GOAL_CATEGORIES: readonly GoalCategory[] = [\n {\n key: 'build',\n values: [\n 'start_company',\n 'get_feedback',\n 'find_cofounder',\n 'find_testers',\n 'hiring',\n 'find_service_providers',\n ],\n },\n {\n key: 'grow',\n values: [\n 'find_customers',\n 'find_investors',\n 'partnerships',\n 'market_insights',\n 'business_ideas',\n 'grow_network',\n ],\n },\n {\n key: 'learn',\n values: [\n 'learn_startup',\n 'mentorship',\n 'attend_events',\n 'join_startup',\n 'mentor_others',\n 'invest_in_startups',\n ],\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/**\n * A member's interests, by ONE rule (0.16.0): onboarding's finish and the Me\n * tab's editor (`putMyInterestsBodySchema`) both apply this very schema, so a\n * list one accepts the other can never refuse.\n *\n * Each topic only once: without that, three copies of one topic met the\n * minimum of three while meaning one interest.\n */\nexport const interestsSchema = z\n .array(topicSchema)\n .min(INTERESTS_MIN)\n .max(INTERESTS_MAX)\n .refine(eachOnce, {\n error: VALIDATION_MESSAGE.topicsDuplicate,\n });\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 *\n * 0.16.0 (the user, 2026-10-18) split the old first step, `identity`, into\n * three: `basics` (full name, gender, date of birth, nothing else), `photo`\n * (the photo alone) and `professional` (title, about, skills). Nine steps, up\n * from seven.\n *\n * ⚠ THE SERVER'S RESUME CURSOR IS AN INDEX INTO THIS LIST, so re-ordering it\n * moves every member who stopped part-way. A cursor saved under the old seven\n * is translated by the backend (its progress rows carry the list's version);\n * any further change needs the same.\n */\nexport const ONBOARDING_STEP_KEYS = [\n 'basics',\n 'photo',\n 'professional',\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;\n/**\n * Not agreed at all (the box left unticked) is `guidelinesRequired`; agreed to\n * another text is `guidelinesOutdated` (0.17.0: both were the second, so a\n * client had to word an unticked box itself).\n */\nexport const guidelinesVersionSchema = z.literal(GUIDELINES_VERSION, {\n error: (issue) =>\n issue.input === undefined || issue.input === null\n ? VALIDATION_MESSAGE.guidelinesRequired\n : 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/**\n * A team size as typed, kept to what the field may hold: digits only, at most\n * `TEAM_SIZE_DIGITS_MAX` (0.17.0: the draft reader and every client's field\n * clean it with this one rule).\n */\nexport const teamSizeDigits = (raw: string): string =>\n raw.replace(/\\D/g, '').slice(0, TEAM_SIZE_DIGITS_MAX);\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. Derive that type from\n * `OnboardingForm` rather than writing it out, so a field added here reaches\n * every screen. (Since 0.16.0 the name is asked as one full name; since 0.20.0\n * its key is `fullName`, and the server splits it into the first and last name\n * it stores, the display name being those two joined.)\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 */\n/** Longest date of birth an answer may be: `YYYY-MM-DD` (0.18.0: exported; the form and the draft reader use it). */\nexport const DATE_INPUT_MAX = 10;\n/** Longest phone number an answer may be, as typed with spaces and a `+91`. */\nexport const PHONE_INPUT_MAX = 20;\n/** Longest guidelines version an answer may carry (`GUIDELINES_VERSION` is a date). */\nexport const GUIDELINES_VERSION_MAX = 32;\n\nexport const onboardingFormSchema = z.object({\n fullName: 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().max(DATE_INPUT_MAX),\n headline: z.string().max(HEADLINE_MAX),\n about: z.string().max(ABOUT_MAX),\n /**\n * The completed upload's id (`media`, purpose `avatar`), or `null` for no\n * photo.\n *\n * SAVED BY THE PHOTO STEP, KEPT BY THE SERVER, NOT IN THE DRAFT (0.17.0). A\n * step save carrying this key hands the upload to the server, which holds it\n * for the draft (so the unattached sweep, `MEDIA_UNATTACHED_TTL_HOURS`, never\n * deletes it) and lets go of the one it replaces; `null` lets go of it. It\n * comes back as the status's `photo`, read from what the server holds, never\n * from a stored draft: `readOnboardingDraft` still gives `null` here, so an\n * id an older client left in a draft is never trusted.\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().max(PHONE_INPUT_MAX),\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 /**\n * `null` until the member picks a place (the drawer, or GPS then confirmed),\n * and when they leave the step without one (0.19.0: a place from\n * `master_db`, with its names, so the step shows it again after a reload).\n */\n location: placeSchema.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 legalStructure: legalStructureSchema.nullable(),\n\n /** The guidelines text the member agreed to, or `null`. */\n guidelinesVersion: z.string().max(GUIDELINES_VERSION_MAX).nullable(),\n});\nexport type OnboardingForm = z.infer<typeof onboardingFormSchema>;\n\n// ─── Reading a stored draft back ─────────────────────────────────────────────\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 fullName: 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 // A place, whole or not at all: a draft saved before 0.19.0 held a typed\n // city and state, which name no area, so it reads as \"not answered yet\".\n location: placeSchema.nullable().catch(null),\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.string().catch('').transform(teamSizeDigits),\n }).transform((venture) => venture ?? { ...EMPTY_ONBOARDING_VENTURE }),\n businessType: draftChoice(BUSINESS_TYPE_VALUES),\n legalStructure: draftChoice(LEGAL_STRUCTURE_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 from here (it comes back as the status's `photo`; see\n * `avatarMediaId`), and agreement only counts for the 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 raw: Record<string, unknown> =\n draft && typeof draft === 'object' && !Array.isArray(draft)\n ? (draft as Record<string, unknown>)\n : {};\n // 0.20.0 renamed the name answer `displayName` to `fullName`: a draft saved\n // before keeps the name its member typed.\n const source =\n 'fullName' in raw || !('displayName' in raw) ? raw : { ...raw, fullName: raw.displayName };\n return draftReaderSchema.parse(source);\n}\n\n// ─── The finalize body ───────────────────────────────────────────────────────\n\n/**\n * The finish body's fields, before the rules that span fields: what each\n * step's slice is PICKED from (Zod 4 refuses `.pick` on a refined object).\n * Everything outside this file reads `completeOnboardingBodySchema`, whose\n * note below says what the body is.\n */\nconst completeOnboardingBodyFields = 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. The full\n // name as typed (0.20.0): the server splits it and stores first and last.\n fullName: fullNameSchema,\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 /**\n * Absent when the member left the step without a place. Area ids (0.19.0,\n * `locationPickSchema`): the server names the place from `master_db`.\n */\n location: locationPickSchema.optional(),\n\n /** The shared list rule (each goal once, 0.17.0) plus finish's minimum. */\n goals: requiredGoalListSchema,\n interests: interestsSchema,\n skills: skillListSchema.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 /** How the venture is registered, if the member says. Stored on the venture, like the type. */\n legalStructure: legalStructureSchema.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});\n\n/**\n * The business type and how it is registered DESCRIBE a venture, and are\n * stored on it (0.17.0): without one there is nothing to describe. Each is\n * refused ON ITS OWN FIELD (`ventureRequired`: add the business, or clear this\n * answer), never dropped without a word, as the server did and as the web did\n * with a lone \"Not registered yet\" (hary's ruling: no silent drop).\n */\ntype VentureAnswers = { venture?: unknown; businessType?: unknown; legalStructure?: unknown };\nconst typeHasVenture = (body: VentureAnswers): boolean =>\n body.venture !== undefined || body.businessType === undefined;\nconst registrationHasVenture = (body: VentureAnswers): boolean =>\n body.venture !== undefined || body.legalStructure === undefined;\nconst TYPE_NEEDS_VENTURE = { error: VALIDATION_MESSAGE.ventureRequired, path: ['businessType'] };\nconst REGISTRATION_NEEDS_VENTURE = {\n error: VALIDATION_MESSAGE.ventureRequired,\n path: ['legalStructure'],\n};\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 *\n * Refined (the business type and registration need a venture, above), so Zod 4\n * throws on `.pick` / `.omit` / `.partial` / `.merge` of it: read a field with\n * `.shape.<field>`, a step's with `ONBOARDING_STEP_SCHEMAS.<step>`.\n */\nexport const completeOnboardingBodySchema = completeOnboardingBodyFields\n .refine(typeHasVenture, TYPE_NEEDS_VENTURE)\n .refine(registrationHasVenture, REGISTRATION_NEEDS_VENTURE);\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 // 0.16.0: the old `identity` step, split three ways by the user. The basics\n // are the step's only required answers; the photo and the professional\n // details may each be passed over.\n basics: completeOnboardingBodyFields.pick({ fullName: true, gender: true, dateOfBirth: true }),\n photo: completeOnboardingBodyFields.pick({ avatarMediaId: true }),\n professional: completeOnboardingBodyFields.pick({\n headline: true,\n about: true,\n // Ruling D8 folded the design's \"title, achievements, skills\" screen into\n // the profile's first questions; it now has a step of its own again.\n skills: true,\n }),\n contact: completeOnboardingBodyFields.pick({ phone: true, links: true }),\n location: completeOnboardingBodyFields.pick({ location: true }),\n goals: completeOnboardingBodyFields.pick({ goals: true }),\n interests: completeOnboardingBodyFields.pick({ interests: true }),\n business: completeOnboardingBodyFields\n .pick({\n venture: true,\n businessType: true,\n legalStructure: true,\n })\n .refine(typeHasVenture, TYPE_NEEDS_VENTURE)\n .refine(registrationHasVenture, REGISTRATION_NEEDS_VENTURE),\n guidelines: completeOnboardingBodyFields.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 /**\n * Translation keys for what the step's header shows: its short label beside\n * the step number (\"STEP 5 OF 9 · LOCATION\") and its one question. The words\n * live in each client. There is no help line (the user removed it,\n * 2026-10-19; `helpKey` went in 0.17.0): who sees an answer is said on the\n * field it is about.\n */\n labelKey: `onboarding.steps.${OnboardingStepKey}.label`;\n titleKey: `onboarding.steps.${OnboardingStepKey}.title`;\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 labelKey: `onboarding.steps.${key}.label`,\n titleKey: `onboarding.steps.${key}.title`,\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: objectIdSchema,\n username: usernameSchema,\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 * What is READ BACK: the draft's KEYS come from the form, its VALUES are\n * opaque, since a stored draft may predate 0.18.0 (any JSON was stored then);\n * read it through `readOnboardingDraft`, never by casting. What is WRITTEN is\n * the form's own shape (`onboardingProgressUpdateSchema.draft`, 0.18.0), and\n * everything 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\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 *\n * The photo step's `avatarMediaId` is not kept in the draft (0.17.0): it is\n * handed to the server, which holds that upload for the member.\n */\nexport const onboardingProgressUpdateSchema = z.object({\n step: z.number().int().min(0).max(ONBOARDING_TOTAL_STEPS).optional(),\n /**\n * The answers of the step being saved, IN THE FORM'S OWN SHAPE (0.18.0):\n * half-answered is fine (that is the form: text as typed, `null` for \"not\n * yet\"), but every value has its type and its bound, and no other key is\n * taken. Before 0.18.0 any JSON up to the body limit was stored as sent,\n * for 90 days, and sent back. The photo's id reads as `objectIdSchema` reads\n * every id (lower case), since the server compares it with the upload it\n * holds.\n */\n draft: onboardingFormSchema.partial().strict().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 /**\n * The photo the member saved on the photo step, as it will appear (0.17.0):\n * the upload the server holds for this member's draft. Absent when they\n * saved none, removed it, or have finished. A client resumes the photo step\n * from this (its `id` is the finish body's `avatarMediaId`), never from the\n * draft.\n */\n photo: mediaImageSchema.optional(),\n});\nexport type OnboardingStatus = z.infer<typeof onboardingStatusSchema>;\n"]}