founder-schema 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,638 @@
1
+ /**
2
+ * founder-schema — Onboarding: steps, enums, and the two shapes of the answers
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.
10
+ *
11
+ * TWO SHAPES, ONE SET OF RULES. A half-filled form legitimately holds `null`
12
+ * for a choice nobody has made yet; the finalize body only ever sees completed
13
+ * answers. So the rules are written once and expressed over both shapes:
14
+ * `onboardingFormSchema` for work in progress and `completeOnboardingBodySchema`
15
+ * for the end. Letting those two drift is how a wizard says a step is optional
16
+ * and then answers 422 at Finish.
17
+ *
18
+ * @module founder-schema/onboarding
19
+ */
20
+ import { z } from 'zod';
21
+ /**
22
+ * 18, ruled by the user 2026-09-21. Under-18 would pull in parental-consent
23
+ * duties under the DPDP Act, which is a different and larger problem than a
24
+ * validation rule.
25
+ *
26
+ * ⚠️ The SERVER refuses at finalize. This schema exists so the member sees a
27
+ * useful message; it is not the gate.
28
+ */
29
+ export declare const MIN_AGE_YEARS = 18;
30
+ /** A sanity ceiling, not a product rule. Catches a mistyped year. */
31
+ export declare const MAX_AGE_YEARS = 120;
32
+ /**
33
+ * Whole years completed, by the calendar.
34
+ *
35
+ * ⚠️ NOT `elapsedMs / (365.25 * day)`, which is what the sibling product uses.
36
+ * That approximation reads 17.9986 at the start of somebody's eighteenth
37
+ * birthday and only crosses 18 about halfway through the day, so it refuses
38
+ * them for the half of their birthday they are most likely to be signing up on.
39
+ * Measured: it disagrees with the calendar on all 400 of the next 400 days.
40
+ * An age gate is exactly the place an approximation is not good enough.
41
+ */
42
+ export declare function ageInYears(isoDate: string, now?: Date): number;
43
+ /** A calendar date with no time component, `YYYY-MM-DD`. */
44
+ export declare const isoDateSchema: z.ZodString;
45
+ /**
46
+ * Date of birth, with the age gate applied per parse.
47
+ *
48
+ * ⚠️ THE CLIENT IS NOT THE GATE. This schema exists so the member sees a useful
49
+ * message, and the server must refuse the same dates at finalize regardless.
50
+ * The sibling dating product validates the identical rule on its client and
51
+ * still shipped a defect where an under-age date of birth produced a live,
52
+ * discoverable profile, because the client was the only thing checking.
53
+ */
54
+ export declare const dateOfBirthSchema: z.ZodString;
55
+ export declare const BUSINESS_TYPE_VALUES: readonly ["startup", "sme", "enterprise"];
56
+ export declare const businessTypeSchema: z.ZodEnum<{
57
+ startup: "startup";
58
+ sme: "sme";
59
+ enterprise: "enterprise";
60
+ }>;
61
+ export type BusinessType = z.infer<typeof businessTypeSchema>;
62
+ /**
63
+ * ONE vocabulary, used TWICE: a member picks these as their `interests`, and a
64
+ * post carries them as its `topics`. That is what makes relevance an index
65
+ * lookup rather than a guess, and it is why this list is not called "interests"
66
+ * - naming it for one of its two jobs would have invited a second list for the
67
+ * other, which is the mistake this package has already made once with goals.
68
+ * (User's ruling via hary, 2026-09-21.)
69
+ *
70
+ * Deliberately DISTINCT from two neighbours that will otherwise collect the
71
+ * same words:
72
+ *
73
+ * industry what your company does
74
+ * skills what you can do
75
+ * interests what you want to read about
76
+ *
77
+ * If the copy does not keep them apart, members fill all three identically and
78
+ * every one of them stops telling us anything.
79
+ *
80
+ * A closed list, consistent with industry, skill and stage, for the reason
81
+ * already written beside those: free text means two people typing "growth" and
82
+ * "Growth Marketing" never match, and matching is the entire point. The cost is
83
+ * that adding an interest needs a publish.
84
+ *
85
+ * Tuned down from the dating product's 246, which is mostly dating material.
86
+ * Values reuse its exact strings wherever one existed, so its Hindi
87
+ * translations can be lifted across.
88
+ *
89
+ * ⚠️ Stored per member. Append only; removing a value orphans data.
90
+ */
91
+ export declare const TOPIC_VALUES: readonly ["mentoring", "leadership", "networking", "public_speaking", "teaching", "hiring_talent", "personal_branding", "career_transition", "remote_work", "ai_ml", "blockchain", "crypto_web3", "robotics", "data_science", "cybersecurity", "game_dev", "ux_design", "app_development", "open_source", "electronics", "space_exploration", "green_tech", "deeptech", "no_code", "entrepreneurship", "investing", "stock_trading", "personal_finance", "fundraising", "marketing", "sales", "consulting", "ecommerce", "retail", "real_estate", "supply_chain", "product_management", "growth", "b2b_saas", "d2c", "meditation", "journaling", "self_improvement", "productivity", "reading", "online_courses", "philosophy", "psychology", "therapy", "sleep_optimization", "gym", "yoga", "photography", "writing", "graphic_design", "filmmaking", "digital_art", "content_creation", "blogging", "vlogging", "podcasts", "animation", "music_production", "volunteering", "ngo_work", "environmental", "women_empowerment", "community_service", "social_enterprise", "education_access"];
92
+ export declare const topicSchema: z.ZodEnum<{
93
+ ai_ml: "ai_ml";
94
+ b2b_saas: "b2b_saas";
95
+ d2c: "d2c";
96
+ deeptech: "deeptech";
97
+ robotics: "robotics";
98
+ growth: "growth";
99
+ sales: "sales";
100
+ marketing: "marketing";
101
+ supply_chain: "supply_chain";
102
+ fundraising: "fundraising";
103
+ mentoring: "mentoring";
104
+ leadership: "leadership";
105
+ networking: "networking";
106
+ public_speaking: "public_speaking";
107
+ teaching: "teaching";
108
+ hiring_talent: "hiring_talent";
109
+ personal_branding: "personal_branding";
110
+ career_transition: "career_transition";
111
+ remote_work: "remote_work";
112
+ blockchain: "blockchain";
113
+ crypto_web3: "crypto_web3";
114
+ data_science: "data_science";
115
+ cybersecurity: "cybersecurity";
116
+ game_dev: "game_dev";
117
+ ux_design: "ux_design";
118
+ app_development: "app_development";
119
+ open_source: "open_source";
120
+ electronics: "electronics";
121
+ space_exploration: "space_exploration";
122
+ green_tech: "green_tech";
123
+ no_code: "no_code";
124
+ entrepreneurship: "entrepreneurship";
125
+ investing: "investing";
126
+ stock_trading: "stock_trading";
127
+ personal_finance: "personal_finance";
128
+ consulting: "consulting";
129
+ ecommerce: "ecommerce";
130
+ retail: "retail";
131
+ real_estate: "real_estate";
132
+ product_management: "product_management";
133
+ meditation: "meditation";
134
+ journaling: "journaling";
135
+ self_improvement: "self_improvement";
136
+ productivity: "productivity";
137
+ reading: "reading";
138
+ online_courses: "online_courses";
139
+ philosophy: "philosophy";
140
+ psychology: "psychology";
141
+ therapy: "therapy";
142
+ sleep_optimization: "sleep_optimization";
143
+ gym: "gym";
144
+ yoga: "yoga";
145
+ photography: "photography";
146
+ writing: "writing";
147
+ graphic_design: "graphic_design";
148
+ filmmaking: "filmmaking";
149
+ digital_art: "digital_art";
150
+ content_creation: "content_creation";
151
+ blogging: "blogging";
152
+ vlogging: "vlogging";
153
+ podcasts: "podcasts";
154
+ animation: "animation";
155
+ music_production: "music_production";
156
+ volunteering: "volunteering";
157
+ ngo_work: "ngo_work";
158
+ environmental: "environmental";
159
+ women_empowerment: "women_empowerment";
160
+ community_service: "community_service";
161
+ social_enterprise: "social_enterprise";
162
+ education_access: "education_access";
163
+ }>;
164
+ export type Topic = z.infer<typeof topicSchema>;
165
+ /**
166
+ * The grouping the picker renders.
167
+ *
168
+ * ⚠️ `TOPIC_VALUES` above is the single source of truth and this is typed
169
+ * against it, so a typo here is a compile error rather than a chip that renders
170
+ * and can never be selected. The dating product keeps a categorised list and a
171
+ * flat list side by side and they have already drifted apart by two values;
172
+ * a test in this package asserts these two agree exactly, in both directions.
173
+ */
174
+ export interface TopicCategory {
175
+ key: string;
176
+ label: string;
177
+ values: readonly Topic[];
178
+ }
179
+ export declare const TOPIC_CATEGORIES: readonly TopicCategory[];
180
+ /**
181
+ * How many a member must pick. A minimum exists because these drive feed
182
+ * relevance and zero of them means no relevance at all.
183
+ *
184
+ * ⚠️ If 3 turns out to be hard to reach against this list, that is a signal
185
+ * about the LIST, not about the minimum. The sibling product enforces no
186
+ * minimum at all, and its own field config says "pick up to 10" while every
187
+ * screen and schema enforces 20.
188
+ */
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
+ export declare const INTERESTS_MIN = 3;
198
+ export declare const INTERESTS_MAX = 10;
199
+ /**
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.
207
+ */
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;
219
+ /**
220
+ * Fields gating each step, DERIVED from the list above so the two can never
221
+ * disagree.
222
+ */
223
+ export declare const ONBOARDING_STEP_FIELDS: readonly (readonly string[])[];
224
+ /**
225
+ * Indian mobile number, ten digits, stored raw with no country code, matching
226
+ * the standard used across this family. Display adds `+91`.
227
+ */
228
+ export declare const contactLinksSchema: z.ZodObject<{
229
+ linkedin: z.ZodOptional<z.ZodURL>;
230
+ x: z.ZodOptional<z.ZodURL>;
231
+ instagram: z.ZodOptional<z.ZodURL>;
232
+ }, z.core.$strip>;
233
+ /**
234
+ * The wizard's working shape.
235
+ *
236
+ * Every choice is nullable because "not answered yet" is a real state here and
237
+ * is NOT the same as "answered with nothing". Arrays start empty. Nothing in
238
+ * this schema is required, on purpose: it describes a form somebody is halfway
239
+ * through, and the rules that decide whether they may FINISH live in
240
+ * `completeOnboardingBodySchema`.
241
+ */
242
+ export declare const onboardingFormSchema: z.ZodObject<{
243
+ displayName: z.ZodString;
244
+ gender: z.ZodNullable<z.ZodEnum<{
245
+ other: "other";
246
+ male: "male";
247
+ female: "female";
248
+ prefer_not_to_say: "prefer_not_to_say";
249
+ }>>;
250
+ dateOfBirth: z.ZodString;
251
+ headline: z.ZodString;
252
+ about: z.ZodString;
253
+ avatarUploadKey: z.ZodNullable<z.ZodString>;
254
+ phone: z.ZodString;
255
+ links: z.ZodObject<{
256
+ linkedin: z.ZodOptional<z.ZodURL>;
257
+ x: z.ZodOptional<z.ZodURL>;
258
+ instagram: z.ZodOptional<z.ZodURL>;
259
+ }, z.core.$strip>;
260
+ location: z.ZodNullable<z.ZodObject<{
261
+ city: z.ZodString;
262
+ state: z.ZodString;
263
+ country: z.ZodString;
264
+ }, z.core.$strip>>;
265
+ goals: z.ZodArray<z.ZodEnum<{
266
+ find_cofounder: "find_cofounder";
267
+ find_investors: "find_investors";
268
+ find_customers: "find_customers";
269
+ hiring: "hiring";
270
+ partnerships: "partnerships";
271
+ mentorship: "mentorship";
272
+ grow_network: "grow_network";
273
+ business_ideas: "business_ideas";
274
+ market_insights: "market_insights";
275
+ learn_startup: "learn_startup";
276
+ start_company: "start_company";
277
+ }>>;
278
+ interests: z.ZodArray<z.ZodEnum<{
279
+ ai_ml: "ai_ml";
280
+ b2b_saas: "b2b_saas";
281
+ d2c: "d2c";
282
+ deeptech: "deeptech";
283
+ robotics: "robotics";
284
+ growth: "growth";
285
+ sales: "sales";
286
+ marketing: "marketing";
287
+ supply_chain: "supply_chain";
288
+ fundraising: "fundraising";
289
+ mentoring: "mentoring";
290
+ leadership: "leadership";
291
+ networking: "networking";
292
+ public_speaking: "public_speaking";
293
+ teaching: "teaching";
294
+ hiring_talent: "hiring_talent";
295
+ personal_branding: "personal_branding";
296
+ career_transition: "career_transition";
297
+ remote_work: "remote_work";
298
+ blockchain: "blockchain";
299
+ crypto_web3: "crypto_web3";
300
+ data_science: "data_science";
301
+ cybersecurity: "cybersecurity";
302
+ game_dev: "game_dev";
303
+ ux_design: "ux_design";
304
+ app_development: "app_development";
305
+ open_source: "open_source";
306
+ electronics: "electronics";
307
+ space_exploration: "space_exploration";
308
+ green_tech: "green_tech";
309
+ no_code: "no_code";
310
+ entrepreneurship: "entrepreneurship";
311
+ investing: "investing";
312
+ stock_trading: "stock_trading";
313
+ personal_finance: "personal_finance";
314
+ consulting: "consulting";
315
+ ecommerce: "ecommerce";
316
+ retail: "retail";
317
+ real_estate: "real_estate";
318
+ product_management: "product_management";
319
+ meditation: "meditation";
320
+ journaling: "journaling";
321
+ self_improvement: "self_improvement";
322
+ productivity: "productivity";
323
+ reading: "reading";
324
+ online_courses: "online_courses";
325
+ philosophy: "philosophy";
326
+ psychology: "psychology";
327
+ therapy: "therapy";
328
+ sleep_optimization: "sleep_optimization";
329
+ gym: "gym";
330
+ yoga: "yoga";
331
+ photography: "photography";
332
+ writing: "writing";
333
+ graphic_design: "graphic_design";
334
+ filmmaking: "filmmaking";
335
+ digital_art: "digital_art";
336
+ content_creation: "content_creation";
337
+ blogging: "blogging";
338
+ vlogging: "vlogging";
339
+ podcasts: "podcasts";
340
+ animation: "animation";
341
+ music_production: "music_production";
342
+ volunteering: "volunteering";
343
+ ngo_work: "ngo_work";
344
+ environmental: "environmental";
345
+ women_empowerment: "women_empowerment";
346
+ community_service: "community_service";
347
+ social_enterprise: "social_enterprise";
348
+ education_access: "education_access";
349
+ }>>;
350
+ venture: z.ZodNullable<z.ZodObject<{
351
+ name: z.ZodString;
352
+ tagline: z.ZodString;
353
+ website: z.ZodString;
354
+ industry: z.ZodNullable<z.ZodEnum<{
355
+ agritech: "agritech";
356
+ ai_ml: "ai_ml";
357
+ b2b_saas: "b2b_saas";
358
+ consumer: "consumer";
359
+ climate: "climate";
360
+ d2c: "d2c";
361
+ deeptech: "deeptech";
362
+ edtech: "edtech";
363
+ fintech: "fintech";
364
+ gaming: "gaming";
365
+ healthtech: "healthtech";
366
+ logistics: "logistics";
367
+ manufacturing: "manufacturing";
368
+ marketplace: "marketplace";
369
+ media: "media";
370
+ mobility: "mobility";
371
+ proptech: "proptech";
372
+ robotics: "robotics";
373
+ services: "services";
374
+ space: "space";
375
+ other: "other";
376
+ }>>;
377
+ stage: z.ZodNullable<z.ZodEnum<{
378
+ idea: "idea";
379
+ validation: "validation";
380
+ mvp: "mvp";
381
+ pre_seed: "pre_seed";
382
+ seed: "seed";
383
+ series_a_plus: "series_a_plus";
384
+ profitable: "profitable";
385
+ exited: "exited";
386
+ }>>;
387
+ teamSize: z.ZodString;
388
+ }, z.core.$strip>>;
389
+ businessType: z.ZodNullable<z.ZodEnum<{
390
+ startup: "startup";
391
+ sme: "sme";
392
+ enterprise: "enterprise";
393
+ }>>;
394
+ skills: z.ZodArray<z.ZodEnum<{
395
+ engineering: "engineering";
396
+ product: "product";
397
+ design: "design";
398
+ data: "data";
399
+ growth: "growth";
400
+ sales: "sales";
401
+ marketing: "marketing";
402
+ operations: "operations";
403
+ finance: "finance";
404
+ legal: "legal";
405
+ hr_people: "hr_people";
406
+ supply_chain: "supply_chain";
407
+ research: "research";
408
+ fundraising: "fundraising";
409
+ community: "community";
410
+ }>>;
411
+ guidelinesVersion: z.ZodNullable<z.ZodString>;
412
+ }, z.core.$strip>;
413
+ export type OnboardingForm = z.infer<typeof onboardingFormSchema>;
414
+ /**
415
+ * What the client sends to finish. Completed answers only.
416
+ *
417
+ * ⚠️ EVERY OPTIONAL FIELD HERE MUST BE ABSENT WHEN UNANSWERED, never a default
418
+ * standing in for one. The sibling gym product sent `bloodGroup ?? 'O+'`, so
419
+ * every member who skipped the question was recorded as O-positive: a real
420
+ * answer, indistinguishable from one somebody gave, sitting on a screen staff
421
+ * would read in an emergency. Absent has to stay absent.
422
+ *
423
+ * ⚠️ AND THIS IS NOT THE GATE EITHER. The server re-checks the age and refuses
424
+ * at finalize. `isOnboarded` may be set here and nowhere else: four of the
425
+ * profile's partial indexes are gated on it, so a half-built profile carrying
426
+ * it true appears in Discover half-built.
427
+ */
428
+ export declare const completeOnboardingBodySchema: z.ZodObject<{
429
+ displayName: z.ZodString;
430
+ gender: z.ZodEnum<{
431
+ other: "other";
432
+ male: "male";
433
+ female: "female";
434
+ prefer_not_to_say: "prefer_not_to_say";
435
+ }>;
436
+ dateOfBirth: z.ZodString;
437
+ headline: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
438
+ about: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
439
+ avatarUploadKey: z.ZodOptional<z.ZodString>;
440
+ phone: z.ZodString;
441
+ links: z.ZodOptional<z.ZodObject<{
442
+ linkedin: z.ZodOptional<z.ZodURL>;
443
+ x: z.ZodOptional<z.ZodURL>;
444
+ instagram: z.ZodOptional<z.ZodURL>;
445
+ }, z.core.$strip>>;
446
+ location: z.ZodOptional<z.ZodObject<{
447
+ city: z.ZodString;
448
+ state: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
449
+ country: z.ZodString;
450
+ }, z.core.$strip>>;
451
+ goals: z.ZodArray<z.ZodEnum<{
452
+ find_cofounder: "find_cofounder";
453
+ find_investors: "find_investors";
454
+ find_customers: "find_customers";
455
+ hiring: "hiring";
456
+ partnerships: "partnerships";
457
+ mentorship: "mentorship";
458
+ grow_network: "grow_network";
459
+ business_ideas: "business_ideas";
460
+ market_insights: "market_insights";
461
+ learn_startup: "learn_startup";
462
+ start_company: "start_company";
463
+ }>>;
464
+ interests: z.ZodArray<z.ZodEnum<{
465
+ ai_ml: "ai_ml";
466
+ b2b_saas: "b2b_saas";
467
+ d2c: "d2c";
468
+ deeptech: "deeptech";
469
+ robotics: "robotics";
470
+ growth: "growth";
471
+ sales: "sales";
472
+ marketing: "marketing";
473
+ supply_chain: "supply_chain";
474
+ fundraising: "fundraising";
475
+ mentoring: "mentoring";
476
+ leadership: "leadership";
477
+ networking: "networking";
478
+ public_speaking: "public_speaking";
479
+ teaching: "teaching";
480
+ hiring_talent: "hiring_talent";
481
+ personal_branding: "personal_branding";
482
+ career_transition: "career_transition";
483
+ remote_work: "remote_work";
484
+ blockchain: "blockchain";
485
+ crypto_web3: "crypto_web3";
486
+ data_science: "data_science";
487
+ cybersecurity: "cybersecurity";
488
+ game_dev: "game_dev";
489
+ ux_design: "ux_design";
490
+ app_development: "app_development";
491
+ open_source: "open_source";
492
+ electronics: "electronics";
493
+ space_exploration: "space_exploration";
494
+ green_tech: "green_tech";
495
+ no_code: "no_code";
496
+ entrepreneurship: "entrepreneurship";
497
+ investing: "investing";
498
+ stock_trading: "stock_trading";
499
+ personal_finance: "personal_finance";
500
+ consulting: "consulting";
501
+ ecommerce: "ecommerce";
502
+ retail: "retail";
503
+ real_estate: "real_estate";
504
+ product_management: "product_management";
505
+ meditation: "meditation";
506
+ journaling: "journaling";
507
+ self_improvement: "self_improvement";
508
+ productivity: "productivity";
509
+ reading: "reading";
510
+ online_courses: "online_courses";
511
+ philosophy: "philosophy";
512
+ psychology: "psychology";
513
+ therapy: "therapy";
514
+ sleep_optimization: "sleep_optimization";
515
+ gym: "gym";
516
+ yoga: "yoga";
517
+ photography: "photography";
518
+ writing: "writing";
519
+ graphic_design: "graphic_design";
520
+ filmmaking: "filmmaking";
521
+ digital_art: "digital_art";
522
+ content_creation: "content_creation";
523
+ blogging: "blogging";
524
+ vlogging: "vlogging";
525
+ podcasts: "podcasts";
526
+ animation: "animation";
527
+ music_production: "music_production";
528
+ volunteering: "volunteering";
529
+ ngo_work: "ngo_work";
530
+ environmental: "environmental";
531
+ women_empowerment: "women_empowerment";
532
+ community_service: "community_service";
533
+ social_enterprise: "social_enterprise";
534
+ education_access: "education_access";
535
+ }>>;
536
+ skills: z.ZodOptional<z.ZodArray<z.ZodEnum<{
537
+ engineering: "engineering";
538
+ product: "product";
539
+ design: "design";
540
+ data: "data";
541
+ growth: "growth";
542
+ sales: "sales";
543
+ marketing: "marketing";
544
+ operations: "operations";
545
+ finance: "finance";
546
+ legal: "legal";
547
+ hr_people: "hr_people";
548
+ supply_chain: "supply_chain";
549
+ research: "research";
550
+ fundraising: "fundraising";
551
+ community: "community";
552
+ }>>>;
553
+ 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
+ industry: z.ZodEnum<{
558
+ agritech: "agritech";
559
+ ai_ml: "ai_ml";
560
+ b2b_saas: "b2b_saas";
561
+ consumer: "consumer";
562
+ climate: "climate";
563
+ d2c: "d2c";
564
+ deeptech: "deeptech";
565
+ edtech: "edtech";
566
+ fintech: "fintech";
567
+ gaming: "gaming";
568
+ healthtech: "healthtech";
569
+ logistics: "logistics";
570
+ manufacturing: "manufacturing";
571
+ marketplace: "marketplace";
572
+ media: "media";
573
+ mobility: "mobility";
574
+ proptech: "proptech";
575
+ robotics: "robotics";
576
+ services: "services";
577
+ space: "space";
578
+ other: "other";
579
+ }>;
580
+ stage: z.ZodEnum<{
581
+ idea: "idea";
582
+ validation: "validation";
583
+ mvp: "mvp";
584
+ pre_seed: "pre_seed";
585
+ seed: "seed";
586
+ series_a_plus: "series_a_plus";
587
+ profitable: "profitable";
588
+ exited: "exited";
589
+ }>;
590
+ teamSize: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
591
+ }, z.core.$strip>>;
592
+ businessType: z.ZodOptional<z.ZodEnum<{
593
+ startup: "startup";
594
+ sme: "sme";
595
+ enterprise: "enterprise";
596
+ }>>;
597
+ guidelinesVersion: z.ZodString;
598
+ }, z.core.$strip>;
599
+ export type CompleteOnboardingBody = z.infer<typeof completeOnboardingBodySchema>;
600
+ /**
601
+ * Where the member got to, kept in its own collection, separate from the
602
+ * profile.
603
+ *
604
+ * `step` is a flat index into `FOUNDER_ONBOARDING_STEPS`, not a `(step, sub)`
605
+ * pair: one number is what lets a member start on the web and resume elsewhere,
606
+ * provided both ends agree on the encoding.
607
+ *
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.
611
+ */
612
+ export declare const onboardingDraftSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
613
+ export declare const onboardingProgressSchema: z.ZodObject<{
614
+ step: z.ZodNumber;
615
+ draft: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
616
+ }, z.core.$strip>;
617
+ export type OnboardingProgress = z.infer<typeof onboardingProgressSchema>;
618
+ /** `PUT` body: any subset of the cursor, merged server-side. No defaults. */
619
+ export declare const onboardingProgressUpdateSchema: z.ZodObject<{
620
+ step: z.ZodOptional<z.ZodNumber>;
621
+ draft: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
622
+ }, z.core.$strip>;
623
+ export type OnboardingProgressUpdate = z.infer<typeof onboardingProgressUpdateSchema>;
624
+ /**
625
+ * What the client reads on return.
626
+ *
627
+ * ⚠️ `onboarded` is the gate and it comes from the profile, not from the
628
+ * cursor: a finished member on a new device must be recognised even when the
629
+ * cursor row is gone, and a cursor that failed to load must never make an
630
+ * unfinished member look finished.
631
+ */
632
+ export declare const onboardingStatusSchema: z.ZodObject<{
633
+ onboarded: z.ZodBoolean;
634
+ step: z.ZodNumber;
635
+ draft: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
636
+ }, z.core.$strip>;
637
+ export type OnboardingStatus = z.infer<typeof onboardingStatusSchema>;
638
+ //# sourceMappingURL=onboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../src/onboarding.ts"],"names":[],"mappings":"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"}