founder-schema 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +112 -40
  2. package/dist/account.d.ts +40 -0
  3. package/dist/account.d.ts.map +1 -0
  4. package/dist/account.js +39 -0
  5. package/dist/account.js.map +1 -0
  6. package/dist/chat.d.ts +63 -15
  7. package/dist/chat.d.ts.map +1 -1
  8. package/dist/chat.js +55 -17
  9. package/dist/chat.js.map +1 -1
  10. package/dist/common.d.ts +84 -8
  11. package/dist/common.d.ts.map +1 -1
  12. package/dist/common.js +109 -17
  13. package/dist/common.js.map +1 -1
  14. package/dist/discover.d.ts +98 -6
  15. package/dist/discover.d.ts.map +1 -1
  16. package/dist/discover.js +25 -11
  17. package/dist/discover.js.map +1 -1
  18. package/dist/errors.d.ts +85 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +89 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/feed.d.ts +400 -52
  23. package/dist/feed.d.ts.map +1 -1
  24. package/dist/feed.js +98 -68
  25. package/dist/feed.js.map +1 -1
  26. package/dist/founder-profile.d.ts +76 -46
  27. package/dist/founder-profile.d.ts.map +1 -1
  28. package/dist/founder-profile.js +46 -46
  29. package/dist/founder-profile.js.map +1 -1
  30. package/dist/index.d.ts +15 -9
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +22 -10
  33. package/dist/index.js.map +1 -1
  34. package/dist/limits.d.ts +76 -0
  35. package/dist/limits.d.ts.map +1 -0
  36. package/dist/limits.js +84 -0
  37. package/dist/limits.js.map +1 -0
  38. package/dist/onboarding.d.ts +407 -53
  39. package/dist/onboarding.d.ts.map +1 -1
  40. package/dist/onboarding.js +281 -234
  41. package/dist/onboarding.js.map +1 -1
  42. package/dist/responses/common.d.ts +122 -4
  43. package/dist/responses/common.d.ts.map +1 -1
  44. package/dist/responses/common.js +26 -3
  45. package/dist/responses/common.js.map +1 -1
  46. package/dist/responses/index.d.ts +1 -1
  47. package/dist/responses/index.d.ts.map +1 -1
  48. package/dist/responses/index.js +1 -1
  49. package/dist/responses/index.js.map +1 -1
  50. package/dist/uploads.d.ts +113 -0
  51. package/dist/uploads.d.ts.map +1 -0
  52. package/dist/uploads.js +106 -0
  53. package/dist/uploads.js.map +1 -0
  54. package/dist/validation.d.ts +136 -0
  55. package/dist/validation.d.ts.map +1 -0
  56. package/dist/validation.js +142 -0
  57. package/dist/validation.js.map +1 -0
  58. package/package.json +4 -3
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * founder-schema — Onboarding: steps, enums, and the two shapes of the answers
3
3
  *
4
- * ONE LIST DEFINES THE FLOW. `FOUNDER_ONBOARDING_STEPS` carries the screen
5
- * title, the help line, the progress denominator AND the fields each step
6
- * gates on. GymMonk arrived here after keeping two lists in sync by hand, where
7
- * a step could exist with no title or, worse, be left with no validation gate
8
- * at all. Dating reached the same place independently. One list makes both
9
- * impossible.
4
+ * ONE LIST DEFINES THE FLOW, AND IT IS DERIVED. Each step's fields are a pick
5
+ * of the finish body (`ONBOARDING_STEP_SCHEMAS`), and `FOUNDER_ONBOARDING_STEPS`
6
+ * is built FROM those picks: its `fields`, and even whether a step may be
7
+ * skipped, come from the schema rather than from a second hand-written list.
8
+ * GymMonk arrived at one list after keeping two in sync by hand, where a step
9
+ * could exist with no title or, worse, no validation gate at all; until 0.2.0
10
+ * this file still wrote the field lists twice.
10
11
  *
11
12
  * TWO SHAPES, ONE SET OF RULES. A half-filled form legitimately holds `null`
12
13
  * for a choice nobody has made yet; the finalize body only ever sees completed
@@ -15,6 +16,11 @@
15
16
  * for the end. Letting those two drift is how a wizard says a step is optional
16
17
  * and then answers 422 at Finish.
17
18
  *
19
+ * NO COPY IN HERE. Step titles, help lines and topic category names are
20
+ * translation KEYS (`titleKey`, `helpKey`, `labelKey`), Jansathi's rule for
21
+ * every config string: an English sentence in a shared package is a sentence
22
+ * every other language has to match by wording.
23
+ *
18
24
  * @module founder-schema/onboarding
19
25
  */
20
26
  import { z } from 'zod';
@@ -42,6 +48,7 @@ export declare const MAX_AGE_YEARS = 120;
42
48
  export declare function ageInYears(isoDate: string, now?: Date): number;
43
49
  /** A calendar date with no time component, `YYYY-MM-DD`. */
44
50
  export declare const isoDateSchema: z.ZodString;
51
+ export type IsoDate = z.infer<typeof isoDateSchema>;
45
52
  /**
46
53
  * Date of birth, with the age gate applied per parse.
47
54
  *
@@ -52,6 +59,7 @@ export declare const isoDateSchema: z.ZodString;
52
59
  * discoverable profile, because the client was the only thing checking.
53
60
  */
54
61
  export declare const dateOfBirthSchema: z.ZodString;
62
+ export type DateOfBirth = z.infer<typeof dateOfBirthSchema>;
55
63
  export declare const BUSINESS_TYPE_VALUES: readonly ["startup", "sme", "enterprise"];
56
64
  export declare const businessTypeSchema: z.ZodEnum<{
57
65
  startup: "startup";
@@ -171,9 +179,19 @@ export type Topic = z.infer<typeof topicSchema>;
171
179
  * flat list side by side and they have already drifted apart by two values;
172
180
  * a test in this package asserts these two agree exactly, in both directions.
173
181
  */
182
+ export declare const TOPIC_CATEGORY_KEYS: readonly ["career", "tech", "business", "growth", "creative", "impact"];
183
+ export type TopicCategoryKey = (typeof TOPIC_CATEGORY_KEYS)[number];
184
+ /**
185
+ * ⚠ TRANSLATION KEY SHAPE, for whoever builds the picker: `topics.category.<key>`
186
+ * for a category and `topics.value.<topic>` for a topic. The dating product's
187
+ * interests JSON is keyed by CATEGORY NAME instead, so all five of its label
188
+ * lookups miss and every chip renders its raw English in every locale, with a
189
+ * fully translated Hindi file sitting unreachable.
190
+ */
174
191
  export interface TopicCategory {
175
- key: string;
176
- label: string;
192
+ key: TopicCategoryKey;
193
+ /** A translation key. The English lives in the client's message files, not here. */
194
+ labelKey: `topics.category.${TopicCategoryKey}`;
177
195
  values: readonly Topic[];
178
196
  }
179
197
  export declare const TOPIC_CATEGORIES: readonly TopicCategory[];
@@ -186,50 +204,41 @@ export declare const TOPIC_CATEGORIES: readonly TopicCategory[];
186
204
  * minimum at all, and its own field config says "pick up to 10" while every
187
205
  * screen and schema enforces 20.
188
206
  */
189
- /**
190
- * ⚠️ TRANSLATION KEY SHAPE, for whoever builds the picker:
191
- * `<fieldKey>.<value>` for a value and `<fieldKey>._label` for the field name.
192
- * The dating product's interests JSON is keyed by CATEGORY instead, so all five
193
- * of its label lookups miss and every chip renders its raw English in every
194
- * locale, with a fully translated Hindi file sitting unreachable. Lift the
195
- * translations, reshape the keys.
196
- */
197
207
  export declare const INTERESTS_MIN = 3;
198
208
  export declare const INTERESTS_MAX = 10;
199
209
  /**
200
- * One step of the wizard.
201
- *
202
- * `fields` is what gates leaving this step, and it is why this list and the
203
- * validation map are the same object: a field that appears in no step is
204
- * unreachable twice over, because Continue will not surface its error and the
205
- * final submit's jump-to-the-bad-step finds no step to jump to and leaves the
206
- * last screen dead.
210
+ * The step keys, in order, as a literal union, so a consumer can key a table by
211
+ * step and have TypeScript insist on every one. Before 0.2.0 `key` was a plain
212
+ * string and the web client kept its own copy of this list to get the same
213
+ * check; a test there held the two together. Now there is one list.
207
214
  */
208
- export interface OnboardingStepConfig {
209
- /** Stable identifier. Safe for analytics and for a resume cursor, unlike an index. */
210
- key: string;
211
- title: string;
212
- helpText: string;
213
- fields: readonly string[];
214
- /** False when the whole step may be passed without answering anything. */
215
- required: boolean;
216
- }
217
- export declare const FOUNDER_ONBOARDING_STEPS: readonly OnboardingStepConfig[];
218
- export declare const ONBOARDING_TOTAL_STEPS: number;
215
+ export declare const ONBOARDING_STEP_KEYS: readonly ["identity", "contact", "location", "goals", "interests", "business", "guidelines"];
216
+ export type OnboardingStepKey = (typeof ONBOARDING_STEP_KEYS)[number];
219
217
  /**
220
- * Fields gating each step, DERIVED from the list above so the two can never
221
- * disagree.
218
+ * The community guidelines a member agrees to at the last step, by version.
219
+ *
220
+ * The finish body accepts THIS version and no other: an old tab still showing
221
+ * last month's text cannot record agreement to text it never displayed, and
222
+ * `'whatever'` is not a version. Until 0.2.0 any non-empty string passed, and
223
+ * the web client held this constant on its own.
224
+ *
225
+ * ⚠ Changing the guidelines text means bumping this, in the same publish.
226
+ * Every member who agreed to an earlier version keeps that version on their
227
+ * profile; that record is the point.
222
228
  */
223
- export declare const ONBOARDING_STEP_FIELDS: readonly (readonly string[])[];
229
+ export declare const GUIDELINES_VERSION: "2026-10-03";
230
+ export declare const guidelinesVersionSchema: z.ZodLiteral<"2026-10-03">;
224
231
  /**
225
- * Indian mobile number, ten digits, stored raw with no country code, matching
226
- * the standard used across this family. Display adds `+91`.
232
+ * The links the contact step collects, picked from the profile's own links so
233
+ * the two cannot disagree on what a link is. The phone is `phoneSchema`: ten
234
+ * digits, stored raw with no country code, on the account rather than here.
227
235
  */
228
236
  export declare const contactLinksSchema: z.ZodObject<{
229
237
  linkedin: z.ZodOptional<z.ZodURL>;
230
238
  x: z.ZodOptional<z.ZodURL>;
231
239
  instagram: z.ZodOptional<z.ZodURL>;
232
240
  }, z.core.$strip>;
241
+ export type ContactLinks = z.infer<typeof contactLinksSchema>;
233
242
  /**
234
243
  * The wizard's working shape.
235
244
  *
@@ -238,6 +247,10 @@ export declare const contactLinksSchema: z.ZodObject<{
238
247
  * this schema is required, on purpose: it describes a form somebody is halfway
239
248
  * through, and the rules that decide whether they may FINISH live in
240
249
  * `completeOnboardingBodySchema`.
250
+ *
251
+ * Text inputs stay text here (`teamSize`, `dateOfBirth`), because that is what
252
+ * an input holds while somebody types; the form converts them when it builds
253
+ * the finish body, which takes real numbers.
241
254
  */
242
255
  export declare const onboardingFormSchema: z.ZodObject<{
243
256
  displayName: z.ZodString;
@@ -424,6 +437,9 @@ export type OnboardingForm = z.infer<typeof onboardingFormSchema>;
424
437
  * at finalize. `isOnboarded` may be set here and nowhere else: four of the
425
438
  * profile's partial indexes are gated on it, so a half-built profile carrying
426
439
  * it true appears in Discover half-built.
440
+ *
441
+ * Location, venture and links are the profile's own shapes, not copies: the
442
+ * copies are how the profile model came to lack Instagram.
427
443
  */
428
444
  export declare const completeOnboardingBodySchema: z.ZodObject<{
429
445
  displayName: z.ZodString;
@@ -551,9 +567,6 @@ export declare const completeOnboardingBodySchema: z.ZodObject<{
551
567
  community: "community";
552
568
  }>>>;
553
569
  venture: z.ZodOptional<z.ZodObject<{
554
- name: z.ZodString;
555
- tagline: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
556
- website: z.ZodOptional<z.ZodURL>;
557
570
  industry: z.ZodEnum<{
558
571
  agritech: "agritech";
559
572
  ai_ml: "ai_ml";
@@ -587,16 +600,285 @@ export declare const completeOnboardingBodySchema: z.ZodObject<{
587
600
  profitable: "profitable";
588
601
  exited: "exited";
589
602
  }>;
590
- teamSize: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
603
+ name: z.ZodString;
604
+ tagline: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
605
+ website: z.ZodOptional<z.ZodURL>;
606
+ teamSize: z.ZodOptional<z.ZodNumber>;
591
607
  }, z.core.$strip>>;
592
608
  businessType: z.ZodOptional<z.ZodEnum<{
593
609
  startup: "startup";
594
610
  sme: "sme";
595
611
  enterprise: "enterprise";
596
612
  }>>;
597
- guidelinesVersion: z.ZodString;
613
+ guidelinesVersion: z.ZodLiteral<"2026-10-03">;
598
614
  }, z.core.$strip>;
599
615
  export type CompleteOnboardingBody = z.infer<typeof completeOnboardingBodySchema>;
616
+ /** What a form may hand to the finish body before parsing. */
617
+ export type CompleteOnboardingBodyInput = z.input<typeof completeOnboardingBodySchema>;
618
+ /**
619
+ * Each step's slice of the finish body, picked FROM it, so a client validating
620
+ * "may I leave this step" and the server validating the finish apply the very
621
+ * same rules. A copy would drift, and the drift shows up as a wizard that lets
622
+ * a step pass and a finish that refuses it, on the last screen.
623
+ *
624
+ * THIS IS THE ONE PLACE A STEP'S FIELDS ARE WRITTEN. `FOUNDER_ONBOARDING_STEPS`
625
+ * below reads them from here. A test asserts that every finish field belongs to
626
+ * exactly one step.
627
+ *
628
+ * These validate the FINISH shape (skipped = absent), not the in-progress form:
629
+ * a client maps its form state to the slice first. The server does not run them
630
+ * on a draft save, because a half-answered step must be storable.
631
+ */
632
+ export declare const ONBOARDING_STEP_SCHEMAS: {
633
+ readonly identity: z.ZodObject<{
634
+ about: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
635
+ displayName: z.ZodString;
636
+ headline: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
637
+ skills: z.ZodOptional<z.ZodArray<z.ZodEnum<{
638
+ engineering: "engineering";
639
+ product: "product";
640
+ design: "design";
641
+ data: "data";
642
+ growth: "growth";
643
+ sales: "sales";
644
+ marketing: "marketing";
645
+ operations: "operations";
646
+ finance: "finance";
647
+ legal: "legal";
648
+ hr_people: "hr_people";
649
+ supply_chain: "supply_chain";
650
+ research: "research";
651
+ fundraising: "fundraising";
652
+ community: "community";
653
+ }>>>;
654
+ gender: z.ZodEnum<{
655
+ other: "other";
656
+ male: "male";
657
+ female: "female";
658
+ prefer_not_to_say: "prefer_not_to_say";
659
+ }>;
660
+ dateOfBirth: z.ZodString;
661
+ avatarUploadKey: z.ZodOptional<z.ZodString>;
662
+ }, z.core.$strip>;
663
+ readonly contact: z.ZodObject<{
664
+ links: z.ZodOptional<z.ZodObject<{
665
+ linkedin: z.ZodOptional<z.ZodURL>;
666
+ x: z.ZodOptional<z.ZodURL>;
667
+ instagram: z.ZodOptional<z.ZodURL>;
668
+ }, z.core.$strip>>;
669
+ phone: z.ZodString;
670
+ }, z.core.$strip>;
671
+ readonly location: z.ZodObject<{
672
+ location: z.ZodOptional<z.ZodObject<{
673
+ city: z.ZodString;
674
+ state: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
675
+ country: z.ZodString;
676
+ }, z.core.$strip>>;
677
+ }, z.core.$strip>;
678
+ readonly goals: z.ZodObject<{
679
+ goals: z.ZodArray<z.ZodEnum<{
680
+ find_cofounder: "find_cofounder";
681
+ find_investors: "find_investors";
682
+ find_customers: "find_customers";
683
+ hiring: "hiring";
684
+ partnerships: "partnerships";
685
+ mentorship: "mentorship";
686
+ grow_network: "grow_network";
687
+ business_ideas: "business_ideas";
688
+ market_insights: "market_insights";
689
+ learn_startup: "learn_startup";
690
+ start_company: "start_company";
691
+ }>>;
692
+ }, z.core.$strip>;
693
+ readonly interests: z.ZodObject<{
694
+ interests: z.ZodArray<z.ZodEnum<{
695
+ ai_ml: "ai_ml";
696
+ b2b_saas: "b2b_saas";
697
+ d2c: "d2c";
698
+ deeptech: "deeptech";
699
+ robotics: "robotics";
700
+ growth: "growth";
701
+ sales: "sales";
702
+ marketing: "marketing";
703
+ supply_chain: "supply_chain";
704
+ fundraising: "fundraising";
705
+ mentoring: "mentoring";
706
+ leadership: "leadership";
707
+ networking: "networking";
708
+ public_speaking: "public_speaking";
709
+ teaching: "teaching";
710
+ hiring_talent: "hiring_talent";
711
+ personal_branding: "personal_branding";
712
+ career_transition: "career_transition";
713
+ remote_work: "remote_work";
714
+ blockchain: "blockchain";
715
+ crypto_web3: "crypto_web3";
716
+ data_science: "data_science";
717
+ cybersecurity: "cybersecurity";
718
+ game_dev: "game_dev";
719
+ ux_design: "ux_design";
720
+ app_development: "app_development";
721
+ open_source: "open_source";
722
+ electronics: "electronics";
723
+ space_exploration: "space_exploration";
724
+ green_tech: "green_tech";
725
+ no_code: "no_code";
726
+ entrepreneurship: "entrepreneurship";
727
+ investing: "investing";
728
+ stock_trading: "stock_trading";
729
+ personal_finance: "personal_finance";
730
+ consulting: "consulting";
731
+ ecommerce: "ecommerce";
732
+ retail: "retail";
733
+ real_estate: "real_estate";
734
+ product_management: "product_management";
735
+ meditation: "meditation";
736
+ journaling: "journaling";
737
+ self_improvement: "self_improvement";
738
+ productivity: "productivity";
739
+ reading: "reading";
740
+ online_courses: "online_courses";
741
+ philosophy: "philosophy";
742
+ psychology: "psychology";
743
+ therapy: "therapy";
744
+ sleep_optimization: "sleep_optimization";
745
+ gym: "gym";
746
+ yoga: "yoga";
747
+ photography: "photography";
748
+ writing: "writing";
749
+ graphic_design: "graphic_design";
750
+ filmmaking: "filmmaking";
751
+ digital_art: "digital_art";
752
+ content_creation: "content_creation";
753
+ blogging: "blogging";
754
+ vlogging: "vlogging";
755
+ podcasts: "podcasts";
756
+ animation: "animation";
757
+ music_production: "music_production";
758
+ volunteering: "volunteering";
759
+ ngo_work: "ngo_work";
760
+ environmental: "environmental";
761
+ women_empowerment: "women_empowerment";
762
+ community_service: "community_service";
763
+ social_enterprise: "social_enterprise";
764
+ education_access: "education_access";
765
+ }>>;
766
+ }, z.core.$strip>;
767
+ readonly business: z.ZodObject<{
768
+ venture: z.ZodOptional<z.ZodObject<{
769
+ industry: z.ZodEnum<{
770
+ agritech: "agritech";
771
+ ai_ml: "ai_ml";
772
+ b2b_saas: "b2b_saas";
773
+ consumer: "consumer";
774
+ climate: "climate";
775
+ d2c: "d2c";
776
+ deeptech: "deeptech";
777
+ edtech: "edtech";
778
+ fintech: "fintech";
779
+ gaming: "gaming";
780
+ healthtech: "healthtech";
781
+ logistics: "logistics";
782
+ manufacturing: "manufacturing";
783
+ marketplace: "marketplace";
784
+ media: "media";
785
+ mobility: "mobility";
786
+ proptech: "proptech";
787
+ robotics: "robotics";
788
+ services: "services";
789
+ space: "space";
790
+ other: "other";
791
+ }>;
792
+ stage: z.ZodEnum<{
793
+ idea: "idea";
794
+ validation: "validation";
795
+ mvp: "mvp";
796
+ pre_seed: "pre_seed";
797
+ seed: "seed";
798
+ series_a_plus: "series_a_plus";
799
+ profitable: "profitable";
800
+ exited: "exited";
801
+ }>;
802
+ name: z.ZodString;
803
+ tagline: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
804
+ website: z.ZodOptional<z.ZodURL>;
805
+ teamSize: z.ZodOptional<z.ZodNumber>;
806
+ }, z.core.$strip>>;
807
+ businessType: z.ZodOptional<z.ZodEnum<{
808
+ startup: "startup";
809
+ sme: "sme";
810
+ enterprise: "enterprise";
811
+ }>>;
812
+ }, z.core.$strip>;
813
+ readonly guidelines: z.ZodObject<{
814
+ guidelinesVersion: z.ZodLiteral<"2026-10-03">;
815
+ }, z.core.$strip>;
816
+ };
817
+ /** One step's slice, parsed: `OnboardingStepBody<'contact'>` is `{ phone, links? }`. */
818
+ export type OnboardingStepBody<K extends OnboardingStepKey> = z.infer<(typeof ONBOARDING_STEP_SCHEMAS)[K]>;
819
+ /** A finish-body field name. */
820
+ export type OnboardingField = keyof CompleteOnboardingBody;
821
+ /**
822
+ * One step of the wizard, as a client renders it.
823
+ *
824
+ * `fields` is what gates leaving this step: a field that appears in no step is
825
+ * unreachable twice over, because Continue will not surface its error and the
826
+ * final submit's jump-to-the-bad-step finds no step to jump to and leaves the
827
+ * last screen dead.
828
+ */
829
+ export interface OnboardingStepConfig {
830
+ /** Stable identifier. Safe for analytics and for a resume cursor, unlike an index. */
831
+ key: OnboardingStepKey;
832
+ /** Translation keys. The words live in the client's message files. */
833
+ titleKey: `onboarding.steps.${OnboardingStepKey}.title`;
834
+ helpKey: `onboarding.steps.${OnboardingStepKey}.help`;
835
+ /** The step's slice of the finish body, in schema order. */
836
+ fields: readonly OnboardingField[];
837
+ /**
838
+ * False when the whole step may be passed without answering anything.
839
+ * DERIVED: a step is optional exactly when its slice accepts an empty
840
+ * object, so "skippable" can never disagree with what the finish accepts.
841
+ */
842
+ required: boolean;
843
+ }
844
+ export declare const FOUNDER_ONBOARDING_STEPS: readonly OnboardingStepConfig[];
845
+ export declare const ONBOARDING_TOTAL_STEPS: number;
846
+ /** Fields gating each step, in step order. Read from the same picks. */
847
+ export declare const ONBOARDING_STEP_FIELDS: readonly (readonly OnboardingField[])[];
848
+ /** What finishing answers: the new profile's id and the handle derived for it. */
849
+ export declare const completeOnboardingResponseSchema: z.ZodObject<{
850
+ id: z.ZodString;
851
+ username: z.ZodString;
852
+ }, z.core.$strip>;
853
+ export type CompleteOnboardingResponse = z.infer<typeof completeOnboardingResponseSchema>;
854
+ /**
855
+ * The keys a draft may hold: exactly the in-progress form's fields.
856
+ *
857
+ * ⚠ The server writes each key as a dot path (`draft.<key>`). Unchecked, a key
858
+ * holding a dot writes somewhere nested the form never asked for, and the
859
+ * collection fills with whatever a client invents. Until 0.2.0 the backend
860
+ * kept its own copy of this list and DROPPED unknown keys without a word; now a
861
+ * draft carrying one is refused, with the key in the issue's path.
862
+ */
863
+ export declare const onboardingDraftKeySchema: z.ZodEnum<{
864
+ location: "location";
865
+ about: "about";
866
+ displayName: "displayName";
867
+ headline: "headline";
868
+ venture: "venture";
869
+ skills: "skills";
870
+ goals: "goals";
871
+ links: "links";
872
+ interests: "interests";
873
+ gender: "gender";
874
+ dateOfBirth: "dateOfBirth";
875
+ avatarUploadKey: "avatarUploadKey";
876
+ phone: "phone";
877
+ businessType: "businessType";
878
+ guidelinesVersion: "guidelinesVersion";
879
+ }>;
880
+ export declare const ONBOARDING_DRAFT_KEYS: ("location" | "about" | "displayName" | "headline" | "venture" | "skills" | "goals" | "links" | "interests" | "gender" | "dateOfBirth" | "avatarUploadKey" | "phone" | "businessType" | "guidelinesVersion")[];
881
+ export type OnboardingDraftKey = z.infer<typeof onboardingDraftKeySchema>;
600
882
  /**
601
883
  * Where the member got to, kept in its own collection, separate from the
602
884
  * profile.
@@ -605,24 +887,80 @@ export type CompleteOnboardingBody = z.infer<typeof completeOnboardingBodySchema
605
887
  * pair: one number is what lets a member start on the web and resume elsewhere,
606
888
  * provided both ends agree on the encoding.
607
889
  *
608
- * `draft` is opaque here on purpose. The client owns the form's shape, and it is
609
- * re-validated strictly at finalize, so this schema has no business describing
610
- * it.
890
+ * The draft's KEYS come from the form; its VALUES are opaque on purpose. A
891
+ * half-answered step must be storable even though it would fail the finish,
892
+ * and everything in it is re-validated strictly at finalize.
893
+ *
894
+ * `partialRecord`, not `record`: in Zod 4 an enum-keyed `z.record` demands
895
+ * every key, and a draft holds whichever steps the member has reached.
611
896
  */
612
- export declare const onboardingDraftSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
897
+ export declare const onboardingDraftSchema: z.ZodRecord<z.ZodEnum<{
898
+ location: "location";
899
+ about: "about";
900
+ displayName: "displayName";
901
+ headline: "headline";
902
+ venture: "venture";
903
+ skills: "skills";
904
+ goals: "goals";
905
+ links: "links";
906
+ interests: "interests";
907
+ gender: "gender";
908
+ dateOfBirth: "dateOfBirth";
909
+ avatarUploadKey: "avatarUploadKey";
910
+ phone: "phone";
911
+ businessType: "businessType";
912
+ guidelinesVersion: "guidelinesVersion";
913
+ }> & z.core.$partial, z.ZodUnknown>;
914
+ export type OnboardingDraft = z.infer<typeof onboardingDraftSchema>;
613
915
  export declare const onboardingProgressSchema: z.ZodObject<{
614
916
  step: z.ZodNumber;
615
- draft: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
917
+ draft: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
918
+ location: "location";
919
+ about: "about";
920
+ displayName: "displayName";
921
+ headline: "headline";
922
+ venture: "venture";
923
+ skills: "skills";
924
+ goals: "goals";
925
+ links: "links";
926
+ interests: "interests";
927
+ gender: "gender";
928
+ dateOfBirth: "dateOfBirth";
929
+ avatarUploadKey: "avatarUploadKey";
930
+ phone: "phone";
931
+ businessType: "businessType";
932
+ guidelinesVersion: "guidelinesVersion";
933
+ }> & z.core.$partial, z.ZodUnknown>>;
616
934
  }, z.core.$strip>;
617
935
  export type OnboardingProgress = z.infer<typeof onboardingProgressSchema>;
618
- /** `PUT` body: any subset of the cursor, merged server-side. No defaults. */
936
+ /**
937
+ * `PATCH` body: any subset of the cursor, merged server-side. No defaults.
938
+ * `step` may equal `ONBOARDING_TOTAL_STEPS`: "past the last step", which the
939
+ * client sends on its way to finish.
940
+ */
619
941
  export declare const onboardingProgressUpdateSchema: z.ZodObject<{
620
942
  step: z.ZodOptional<z.ZodNumber>;
621
- draft: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
943
+ draft: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
944
+ location: "location";
945
+ about: "about";
946
+ displayName: "displayName";
947
+ headline: "headline";
948
+ venture: "venture";
949
+ skills: "skills";
950
+ goals: "goals";
951
+ links: "links";
952
+ interests: "interests";
953
+ gender: "gender";
954
+ dateOfBirth: "dateOfBirth";
955
+ avatarUploadKey: "avatarUploadKey";
956
+ phone: "phone";
957
+ businessType: "businessType";
958
+ guidelinesVersion: "guidelinesVersion";
959
+ }> & z.core.$partial, z.ZodUnknown>>;
622
960
  }, z.core.$strip>;
623
961
  export type OnboardingProgressUpdate = z.infer<typeof onboardingProgressUpdateSchema>;
624
962
  /**
625
- * What the client reads on return.
963
+ * What the client reads on return, from `GET` and from every `PATCH`.
626
964
  *
627
965
  * ⚠️ `onboarded` is the gate and it comes from the profile, not from the
628
966
  * cursor: a finished member on a new device must be recognised even when the
@@ -632,7 +970,23 @@ export type OnboardingProgressUpdate = z.infer<typeof onboardingProgressUpdateSc
632
970
  export declare const onboardingStatusSchema: z.ZodObject<{
633
971
  onboarded: z.ZodBoolean;
634
972
  step: z.ZodNumber;
635
- draft: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
973
+ draft: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
974
+ location: "location";
975
+ about: "about";
976
+ displayName: "displayName";
977
+ headline: "headline";
978
+ venture: "venture";
979
+ skills: "skills";
980
+ goals: "goals";
981
+ links: "links";
982
+ interests: "interests";
983
+ gender: "gender";
984
+ dateOfBirth: "dateOfBirth";
985
+ avatarUploadKey: "avatarUploadKey";
986
+ phone: "phone";
987
+ businessType: "businessType";
988
+ guidelinesVersion: "guidelinesVersion";
989
+ }> & z.core.$partial, z.ZodUnknown>>;
636
990
  }, z.core.$strip>;
637
991
  export type OnboardingStatus = z.infer<typeof onboardingStatusSchema>;
638
992
  //# sourceMappingURL=onboarding.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../src/onboarding.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../src/onboarding.ts"],"names":[],"mappings":"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"}