@odla-ai/chapter 0.30.0 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-IVXVECKR.js +15 -0
- package/dist/chunk-IVXVECKR.js.map +1 -0
- package/dist/{chunk-IOHVFBXH.js → chunk-QWMP6TSM.js} +75 -34
- package/dist/chunk-QWMP6TSM.js.map +1 -0
- package/dist/{copy-context-efEMF_aD.d.ts → copy-context-HAhNTZdl.d.ts} +54 -19
- package/dist/index.cjs +168 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +160 -21
- package/dist/index.d.ts +160 -21
- package/dist/index.js +150 -2
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +2 -2
- package/dist/ui/conditions/index.d.ts +29 -0
- package/dist/ui/conditions/index.js +32 -0
- package/dist/ui/conditions/index.js.map +1 -0
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +10 -3
- package/dist/ui/member/index.d.ts +62 -3
- package/dist/ui/member/index.js +10 -3
- package/dist/worker/index.cjs +146 -39
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +54 -19
- package/dist/worker/index.d.ts +54 -19
- package/dist/worker/index.js +115 -8
- package/dist/worker/index.js.map +1 -1
- package/package.json +6 -2
- package/dist/chunk-IOHVFBXH.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,103 @@
|
|
|
1
|
-
import { CrmConfig, Crm, TypeDef, FieldDef, TypeSummary, CrmRecord } from '@odla-ai/crm';
|
|
1
|
+
import { CrmConfig, Crm, FieldConditions, TypeDef, FieldDef, TypeSummary, CrmRecord } from '@odla-ai/crm';
|
|
2
|
+
|
|
3
|
+
/** One membership tier a chapter offers. `priceCents: 0` means free. */
|
|
4
|
+
interface ChapterTier {
|
|
5
|
+
/** Stable slug, referenced by `applications.tierId`. Never renumbered. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** The group this tier belongs to. */
|
|
8
|
+
groupId: string;
|
|
9
|
+
/** Display name, e.g. "Founding". */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Price in minor units. `0` is free and needs no Stripe price. */
|
|
12
|
+
priceCents: number;
|
|
13
|
+
/** Stripe price to subscribe. Required only when `priceCents > 0`. */
|
|
14
|
+
stripePriceId?: string | null;
|
|
15
|
+
/** Short description shown beside the tier on the join page. */
|
|
16
|
+
blurb?: string;
|
|
17
|
+
/** Ascending display order; ties fall back to `id` for a stable sort. */
|
|
18
|
+
sortOrder: number;
|
|
19
|
+
/** An inactive tier is retained for existing members but never offered. */
|
|
20
|
+
active: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A tier as declared in `defineChapter`, before it becomes a row.
|
|
24
|
+
*
|
|
25
|
+
* `groupId` is absent here because the chapter owns exactly one group at seed
|
|
26
|
+
* time; the seeder fills it in.
|
|
27
|
+
*/
|
|
28
|
+
interface ChapterTierConfig {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
priceCents: number;
|
|
32
|
+
stripePriceId?: string;
|
|
33
|
+
blurb?: string;
|
|
34
|
+
/** Defaults to declaration order when omitted. */
|
|
35
|
+
sortOrder?: number;
|
|
36
|
+
/** Defaults to true; set false to retire a tier without deleting it. */
|
|
37
|
+
active?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Build the seed rows for a chapter's declared tiers. */
|
|
40
|
+
declare function buildTierSeeds(groupId: string, configured?: readonly ChapterTierConfig[], now?: number): Array<Record<string, unknown>>;
|
|
41
|
+
/** The `groups`-row fields tier payability depends on. */
|
|
42
|
+
interface TierGroup {
|
|
43
|
+
id?: string;
|
|
44
|
+
stripePublishableKey?: string | null;
|
|
45
|
+
/** Legacy single price, used only to synthesize an implicit tier. */
|
|
46
|
+
stripePriceId?: string | null;
|
|
47
|
+
standardPriceCents?: number;
|
|
48
|
+
foundingDiscountCents?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Whether this tier costs nothing. A free tier never touches Stripe.
|
|
52
|
+
*
|
|
53
|
+
* Free means both no price AND no Stripe price to charge against. The second
|
|
54
|
+
* half matters for chapters that predate tiers: a group can carry a real
|
|
55
|
+
* `stripePriceId` while `standardPriceCents` is 0, because the cents field is
|
|
56
|
+
* display copy and the amount actually lives in Stripe. Reading such a group as
|
|
57
|
+
* free would silently stop charging an existing paying chapter.
|
|
58
|
+
*/
|
|
59
|
+
declare function tierIsFree(tier: Pick<ChapterTier, "priceCents"> & {
|
|
60
|
+
stripePriceId?: string | null;
|
|
61
|
+
}): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Whether a tier can actually be joined right now.
|
|
64
|
+
*
|
|
65
|
+
* A free tier is always joinable — there is nothing to charge, so Stripe being
|
|
66
|
+
* unconfigured is irrelevant to it. A paid tier needs the group's publishable
|
|
67
|
+
* key, its own Stripe price, and the vault secret; missing any of those drops
|
|
68
|
+
* the tier rather than half-charging for it.
|
|
69
|
+
*/
|
|
70
|
+
declare function tierPayable(tier: Pick<ChapterTier, "priceCents" | "stripePriceId">, group: TierGroup, hasSecretKey: boolean): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* The tiers a chapter offers, given the stored rows.
|
|
73
|
+
*
|
|
74
|
+
* A chapter that predates tiers has no rows, and must keep working untouched:
|
|
75
|
+
* one implicit `"standard"` tier is synthesized from the group's legacy
|
|
76
|
+
* `standardPriceCents`/`stripePriceId` columns. That is why there is no
|
|
77
|
+
* migration — an existing chapter reads exactly as it did before, and writing
|
|
78
|
+
* its first real tier row takes over.
|
|
79
|
+
*/
|
|
80
|
+
declare function resolveTiers(group: TierGroup, rows?: readonly ChapterTier[]): ChapterTier[];
|
|
81
|
+
/** The tiers to show on the join page: active, and joinable as configured. */
|
|
82
|
+
declare function offerableTiers(tiers: readonly ChapterTier[], group: TierGroup, hasSecretKey: boolean): ChapterTier[];
|
|
83
|
+
/**
|
|
84
|
+
* Resolve the tier an application chose.
|
|
85
|
+
*
|
|
86
|
+
* An absent `tierId` is the pre-tier case and selects the only offered tier
|
|
87
|
+
* when exactly one exists; with several it is genuinely ambiguous and returns
|
|
88
|
+
* `null`, because guessing would charge someone the wrong price.
|
|
89
|
+
*/
|
|
90
|
+
declare function findTier(tiers: readonly ChapterTier[], tierId: string | null | undefined): ChapterTier | null;
|
|
91
|
+
/** The public shape of a tier on the join config. Never exposes Stripe ids. */
|
|
92
|
+
interface JoinConfigTier {
|
|
93
|
+
id: string;
|
|
94
|
+
name: string;
|
|
95
|
+
priceCents: number;
|
|
96
|
+
blurb: string;
|
|
97
|
+
free: boolean;
|
|
98
|
+
}
|
|
99
|
+
/** Project tiers for the public join config, dropping provider identifiers. */
|
|
100
|
+
declare function joinConfigTiers(tiers: readonly ChapterTier[]): JoinConfigTier[];
|
|
2
101
|
|
|
3
102
|
type TextFields$1<Key extends string> = {
|
|
4
103
|
[Field in Key]: string;
|
|
@@ -153,6 +252,30 @@ interface ResolvedNetwork {
|
|
|
153
252
|
readers: readonly ResolvedNetworkReader[];
|
|
154
253
|
}
|
|
155
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Membership pricing for the group row (chapter mode).
|
|
257
|
+
*
|
|
258
|
+
* This is the single-price model that predates tiers. It still seeds the group
|
|
259
|
+
* row and remains the fallback a chapter reads when it declares no tiers, so
|
|
260
|
+
* existing chapters keep working; new work should prefer `tiers`.
|
|
261
|
+
*/
|
|
262
|
+
interface ChapterPrices {
|
|
263
|
+
standardCents: number;
|
|
264
|
+
foundingDiscountCents?: number;
|
|
265
|
+
/** ISO currency, default "usd". */
|
|
266
|
+
currency?: string;
|
|
267
|
+
/** Billing interval, default "year". */
|
|
268
|
+
interval?: "year" | "month";
|
|
269
|
+
}
|
|
270
|
+
/** Membership policy + compliance copy stored on the group row. */
|
|
271
|
+
interface ChapterPolicy {
|
|
272
|
+
disclaimerText?: string;
|
|
273
|
+
refundPolicyText?: string;
|
|
274
|
+
trustCopy?: string;
|
|
275
|
+
commitmentText?: string;
|
|
276
|
+
normsText?: string;
|
|
277
|
+
}
|
|
278
|
+
|
|
156
279
|
/** Which feature profile a site runs. `chapter` is the full public member site
|
|
157
280
|
* (join, Stripe membership, booking, member area, admin, CRM); `hub` is
|
|
158
281
|
* admin-only and CRM-focused (a directory/registry over the same CRM). */
|
|
@@ -280,23 +403,7 @@ interface ChapterBrand {
|
|
|
280
403
|
}>>;
|
|
281
404
|
logos?: string;
|
|
282
405
|
}
|
|
283
|
-
|
|
284
|
-
interface ChapterPrices {
|
|
285
|
-
standardCents: number;
|
|
286
|
-
foundingDiscountCents?: number;
|
|
287
|
-
/** ISO currency, default "usd". */
|
|
288
|
-
currency?: string;
|
|
289
|
-
/** Billing interval, default "year". */
|
|
290
|
-
interval?: "year" | "month";
|
|
291
|
-
}
|
|
292
|
-
/** Membership policy + compliance copy stored on the group row. */
|
|
293
|
-
interface ChapterPolicy {
|
|
294
|
-
disclaimerText?: string;
|
|
295
|
-
refundPolicyText?: string;
|
|
296
|
-
trustCopy?: string;
|
|
297
|
-
commitmentText?: string;
|
|
298
|
-
normsText?: string;
|
|
299
|
-
}
|
|
406
|
+
|
|
300
407
|
/** One owner-editable transactional email template. */
|
|
301
408
|
interface EmailTemplate {
|
|
302
409
|
subject: string;
|
|
@@ -378,6 +485,11 @@ interface ResolvedPipeline {
|
|
|
378
485
|
interface ChapterApplication {
|
|
379
486
|
required?: readonly string[];
|
|
380
487
|
optional?: readonly string[];
|
|
488
|
+
/** Per-field CEL conditions — show a field, or demand it, based on the
|
|
489
|
+
* answers so far. Enforced server-side as well as rendered, so a hidden
|
|
490
|
+
* field is never demanded and a conditionally-required one cannot be
|
|
491
|
+
* skipped by posting directly. Validated when the chapter is defined. */
|
|
492
|
+
conditions?: Record<string, FieldConditions>;
|
|
381
493
|
/** Per-field character cap. Fields not listed use `defaultMaxLen`. */
|
|
382
494
|
maxLen?: Record<string, number>;
|
|
383
495
|
defaultMaxLen?: number;
|
|
@@ -418,6 +530,8 @@ interface ResolvedApplication {
|
|
|
418
530
|
crmFields: readonly string[];
|
|
419
531
|
maxArrayLen: number;
|
|
420
532
|
validateEmail: boolean;
|
|
533
|
+
/** Resolved per-field conditions. Empty means every field is unconditional. */
|
|
534
|
+
conditions: Record<string, FieldConditions>;
|
|
421
535
|
}
|
|
422
536
|
/** The `defineChapter()` config a site fills in. */
|
|
423
537
|
interface ChapterConfig {
|
|
@@ -439,8 +553,10 @@ interface ChapterConfig {
|
|
|
439
553
|
/** Enable a public, host-rendered formation application workflow. */
|
|
440
554
|
formation?: LeaderFormationConfig;
|
|
441
555
|
thesis?: unknown;
|
|
442
|
-
/** Required in `chapter` mode. */
|
|
556
|
+
/** Required in `chapter` mode, and the fallback when `tiers` is empty. */
|
|
443
557
|
prices?: ChapterPrices;
|
|
558
|
+
/** Membership tiers. A tier priced at 0 is free and never touches Stripe. */
|
|
559
|
+
tiers?: ChapterTierConfig[];
|
|
444
560
|
policy?: ChapterPolicy;
|
|
445
561
|
/** `notificationEmail` required in `chapter` mode. */
|
|
446
562
|
emails?: ChapterEmails;
|
|
@@ -1005,6 +1121,9 @@ declare function submitApplication(db: ChapterDb, chapter: Chapter, fields: Reco
|
|
|
1005
1121
|
groupId?: string;
|
|
1006
1122
|
now: number;
|
|
1007
1123
|
newId: () => string;
|
|
1124
|
+
/** Tier ids this chapter offers. A posted `tierId` outside it is refused;
|
|
1125
|
+
* omit to accept any (pre-tier callers). */
|
|
1126
|
+
tierIds?: readonly string[];
|
|
1008
1127
|
}): Promise<SubmitResult>;
|
|
1009
1128
|
/** The `groups`-row fields the join config exposes. */
|
|
1010
1129
|
interface JoinConfigGroup {
|
|
@@ -1023,8 +1142,14 @@ interface JoinConfigGroup {
|
|
|
1023
1142
|
* group row plus `paymentsReady`. When payments aren't wired the join flow drops
|
|
1024
1143
|
* the payment step (C2) — the worker computes `paymentsReady` from the group's
|
|
1025
1144
|
* Stripe keys + vault secret. Pure.
|
|
1145
|
+
*
|
|
1146
|
+
* `tiers` carries the offerable membership tiers. It is additive: the legacy
|
|
1147
|
+
* `standardPriceCents`/`foundingDiscountCents` fields still describe the first
|
|
1148
|
+
* tier, so a join page written before tiers keeps rendering unchanged. A free
|
|
1149
|
+
* tier appears here with `free: true` even when Stripe is unconfigured, because
|
|
1150
|
+
* nothing needs charging for it.
|
|
1026
1151
|
*/
|
|
1027
|
-
declare function joinConfig(group: JoinConfigGroup, paymentsReady: boolean): Record<string, unknown>;
|
|
1152
|
+
declare function joinConfig(group: JoinConfigGroup, paymentsReady: boolean, tiers?: readonly JoinConfigTier[], conditions?: Readonly<Record<string, FieldConditions>>): Record<string, unknown>;
|
|
1028
1153
|
|
|
1029
1154
|
/** The contact data the hub shares for a prospect. `hubRecordId` is the stable
|
|
1030
1155
|
* idempotency key (the hub's crm_record id). */
|
|
@@ -1724,4 +1849,18 @@ type ApplicationBookingPatch = {
|
|
|
1724
1849
|
* already there (never backward). */
|
|
1725
1850
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1726
1851
|
|
|
1727
|
-
|
|
1852
|
+
/** A `groups` row as the tier loader needs it. */
|
|
1853
|
+
type TierGroupRow = TierGroup & {
|
|
1854
|
+
id?: string;
|
|
1855
|
+
};
|
|
1856
|
+
/**
|
|
1857
|
+
* Every tier a group offers, ordered, including the implicit tier synthesized
|
|
1858
|
+
* for a chapter that predates tiers. Never throws on a missing namespace: a
|
|
1859
|
+
* deployment whose schema has not been pushed yet reads as "no rows", which
|
|
1860
|
+
* resolves to the legacy single tier.
|
|
1861
|
+
*/
|
|
1862
|
+
declare function loadTiers(db: ChapterDb, group: TierGroupRow): Promise<ChapterTier[]>;
|
|
1863
|
+
/** The tiers a join page may show: active, and joinable as configured. */
|
|
1864
|
+
declare function loadOfferableTiers(db: ChapterDb, group: TierGroupRow, hasSecretKey: boolean): Promise<ChapterTier[]>;
|
|
1865
|
+
|
|
1866
|
+
export { type AccountModel, type AdminNotificationTrigger, type Applicant, type ApplicationBookingPatch, type ApplicationRecord, type ApplicationSummary, type Attr, type AttrType, type Chapter, type ChapterApplication, type ChapterAuth, type ChapterBrand, type ChapterConfig, type ChapterCopy, type ChapterCopyInput, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkReader, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterRunbookHints, type ChapterScheduling, type ChapterSends, type ChapterTier, type ChapterTierConfig, type ClerkInviteInput, type ClerkMetadataInput, type ClerkResult, type ClerkUserInput, type ClerkUserRecord, type CompiledChapterBrandTokens, DEFAULT_CHAPTER_COPY, DEFAULT_SHARE_FIELDS, type DashboardMetricData, type DashboardMetricSeries, type DbOp, type DbRules, type DbSchema, type DeliveryDecision, type EmailGroup, type EmailTemplate, type EmailTemplateRow, type Entity, type ExistingMeeting, type GuardResult, type IntegrationDescriptor, type IntegrationProvision, type IntegrationSecret, type IntegrationSetting, type IntegrationSync, type JoinConfigGroup, type JoinConfigTier, type LeaderCrmOptions, type LeaderFormationConfig, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NetworkRecord, type NetworkRecordNote, type NetworkRecordPage, type NetworkRollup, type NetworkRollupTarget, type NetworkSharedNote, type NetworkSnapshot, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedLeaderFormation, type ResolvedNetwork, type ResolvedNetworkReader, type ResolvedNetworkTarget, type ResolvedOperations, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretMode, type SecretStore, type SessionUser, type SharedBusiness, type SharedPerson, type SharedRecord, type SharedRecordV1, type SharedRecordV2, type StripeEvent, type StripeResult, type SubmitResult, type TierGroup, type TierGroupRow, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, buildTierSeeds, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterBrandFromTokens, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, findTier, firstPaymentPatch, formatChapterCopy, formationFields, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, joinConfigTiers, leaderCrmConfig, loadOfferableTiers, loadTiers, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, offerableTiers, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolveChapterCopy, resolveLeaderFormation, resolvePipeline, resolveScheduling, resolveTiers, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, tierIsFree, tierPayable, updateClerkUserMetadata, updateClerkUserMetadataByEmail, validateScheduling, verifyStripeSignature, webhookMutationId };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,103 @@
|
|
|
1
|
-
import { CrmConfig, Crm, TypeDef, FieldDef, TypeSummary, CrmRecord } from '@odla-ai/crm';
|
|
1
|
+
import { CrmConfig, Crm, FieldConditions, TypeDef, FieldDef, TypeSummary, CrmRecord } from '@odla-ai/crm';
|
|
2
|
+
|
|
3
|
+
/** One membership tier a chapter offers. `priceCents: 0` means free. */
|
|
4
|
+
interface ChapterTier {
|
|
5
|
+
/** Stable slug, referenced by `applications.tierId`. Never renumbered. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** The group this tier belongs to. */
|
|
8
|
+
groupId: string;
|
|
9
|
+
/** Display name, e.g. "Founding". */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Price in minor units. `0` is free and needs no Stripe price. */
|
|
12
|
+
priceCents: number;
|
|
13
|
+
/** Stripe price to subscribe. Required only when `priceCents > 0`. */
|
|
14
|
+
stripePriceId?: string | null;
|
|
15
|
+
/** Short description shown beside the tier on the join page. */
|
|
16
|
+
blurb?: string;
|
|
17
|
+
/** Ascending display order; ties fall back to `id` for a stable sort. */
|
|
18
|
+
sortOrder: number;
|
|
19
|
+
/** An inactive tier is retained for existing members but never offered. */
|
|
20
|
+
active: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A tier as declared in `defineChapter`, before it becomes a row.
|
|
24
|
+
*
|
|
25
|
+
* `groupId` is absent here because the chapter owns exactly one group at seed
|
|
26
|
+
* time; the seeder fills it in.
|
|
27
|
+
*/
|
|
28
|
+
interface ChapterTierConfig {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
priceCents: number;
|
|
32
|
+
stripePriceId?: string;
|
|
33
|
+
blurb?: string;
|
|
34
|
+
/** Defaults to declaration order when omitted. */
|
|
35
|
+
sortOrder?: number;
|
|
36
|
+
/** Defaults to true; set false to retire a tier without deleting it. */
|
|
37
|
+
active?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Build the seed rows for a chapter's declared tiers. */
|
|
40
|
+
declare function buildTierSeeds(groupId: string, configured?: readonly ChapterTierConfig[], now?: number): Array<Record<string, unknown>>;
|
|
41
|
+
/** The `groups`-row fields tier payability depends on. */
|
|
42
|
+
interface TierGroup {
|
|
43
|
+
id?: string;
|
|
44
|
+
stripePublishableKey?: string | null;
|
|
45
|
+
/** Legacy single price, used only to synthesize an implicit tier. */
|
|
46
|
+
stripePriceId?: string | null;
|
|
47
|
+
standardPriceCents?: number;
|
|
48
|
+
foundingDiscountCents?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Whether this tier costs nothing. A free tier never touches Stripe.
|
|
52
|
+
*
|
|
53
|
+
* Free means both no price AND no Stripe price to charge against. The second
|
|
54
|
+
* half matters for chapters that predate tiers: a group can carry a real
|
|
55
|
+
* `stripePriceId` while `standardPriceCents` is 0, because the cents field is
|
|
56
|
+
* display copy and the amount actually lives in Stripe. Reading such a group as
|
|
57
|
+
* free would silently stop charging an existing paying chapter.
|
|
58
|
+
*/
|
|
59
|
+
declare function tierIsFree(tier: Pick<ChapterTier, "priceCents"> & {
|
|
60
|
+
stripePriceId?: string | null;
|
|
61
|
+
}): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Whether a tier can actually be joined right now.
|
|
64
|
+
*
|
|
65
|
+
* A free tier is always joinable — there is nothing to charge, so Stripe being
|
|
66
|
+
* unconfigured is irrelevant to it. A paid tier needs the group's publishable
|
|
67
|
+
* key, its own Stripe price, and the vault secret; missing any of those drops
|
|
68
|
+
* the tier rather than half-charging for it.
|
|
69
|
+
*/
|
|
70
|
+
declare function tierPayable(tier: Pick<ChapterTier, "priceCents" | "stripePriceId">, group: TierGroup, hasSecretKey: boolean): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* The tiers a chapter offers, given the stored rows.
|
|
73
|
+
*
|
|
74
|
+
* A chapter that predates tiers has no rows, and must keep working untouched:
|
|
75
|
+
* one implicit `"standard"` tier is synthesized from the group's legacy
|
|
76
|
+
* `standardPriceCents`/`stripePriceId` columns. That is why there is no
|
|
77
|
+
* migration — an existing chapter reads exactly as it did before, and writing
|
|
78
|
+
* its first real tier row takes over.
|
|
79
|
+
*/
|
|
80
|
+
declare function resolveTiers(group: TierGroup, rows?: readonly ChapterTier[]): ChapterTier[];
|
|
81
|
+
/** The tiers to show on the join page: active, and joinable as configured. */
|
|
82
|
+
declare function offerableTiers(tiers: readonly ChapterTier[], group: TierGroup, hasSecretKey: boolean): ChapterTier[];
|
|
83
|
+
/**
|
|
84
|
+
* Resolve the tier an application chose.
|
|
85
|
+
*
|
|
86
|
+
* An absent `tierId` is the pre-tier case and selects the only offered tier
|
|
87
|
+
* when exactly one exists; with several it is genuinely ambiguous and returns
|
|
88
|
+
* `null`, because guessing would charge someone the wrong price.
|
|
89
|
+
*/
|
|
90
|
+
declare function findTier(tiers: readonly ChapterTier[], tierId: string | null | undefined): ChapterTier | null;
|
|
91
|
+
/** The public shape of a tier on the join config. Never exposes Stripe ids. */
|
|
92
|
+
interface JoinConfigTier {
|
|
93
|
+
id: string;
|
|
94
|
+
name: string;
|
|
95
|
+
priceCents: number;
|
|
96
|
+
blurb: string;
|
|
97
|
+
free: boolean;
|
|
98
|
+
}
|
|
99
|
+
/** Project tiers for the public join config, dropping provider identifiers. */
|
|
100
|
+
declare function joinConfigTiers(tiers: readonly ChapterTier[]): JoinConfigTier[];
|
|
2
101
|
|
|
3
102
|
type TextFields$1<Key extends string> = {
|
|
4
103
|
[Field in Key]: string;
|
|
@@ -153,6 +252,30 @@ interface ResolvedNetwork {
|
|
|
153
252
|
readers: readonly ResolvedNetworkReader[];
|
|
154
253
|
}
|
|
155
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Membership pricing for the group row (chapter mode).
|
|
257
|
+
*
|
|
258
|
+
* This is the single-price model that predates tiers. It still seeds the group
|
|
259
|
+
* row and remains the fallback a chapter reads when it declares no tiers, so
|
|
260
|
+
* existing chapters keep working; new work should prefer `tiers`.
|
|
261
|
+
*/
|
|
262
|
+
interface ChapterPrices {
|
|
263
|
+
standardCents: number;
|
|
264
|
+
foundingDiscountCents?: number;
|
|
265
|
+
/** ISO currency, default "usd". */
|
|
266
|
+
currency?: string;
|
|
267
|
+
/** Billing interval, default "year". */
|
|
268
|
+
interval?: "year" | "month";
|
|
269
|
+
}
|
|
270
|
+
/** Membership policy + compliance copy stored on the group row. */
|
|
271
|
+
interface ChapterPolicy {
|
|
272
|
+
disclaimerText?: string;
|
|
273
|
+
refundPolicyText?: string;
|
|
274
|
+
trustCopy?: string;
|
|
275
|
+
commitmentText?: string;
|
|
276
|
+
normsText?: string;
|
|
277
|
+
}
|
|
278
|
+
|
|
156
279
|
/** Which feature profile a site runs. `chapter` is the full public member site
|
|
157
280
|
* (join, Stripe membership, booking, member area, admin, CRM); `hub` is
|
|
158
281
|
* admin-only and CRM-focused (a directory/registry over the same CRM). */
|
|
@@ -280,23 +403,7 @@ interface ChapterBrand {
|
|
|
280
403
|
}>>;
|
|
281
404
|
logos?: string;
|
|
282
405
|
}
|
|
283
|
-
|
|
284
|
-
interface ChapterPrices {
|
|
285
|
-
standardCents: number;
|
|
286
|
-
foundingDiscountCents?: number;
|
|
287
|
-
/** ISO currency, default "usd". */
|
|
288
|
-
currency?: string;
|
|
289
|
-
/** Billing interval, default "year". */
|
|
290
|
-
interval?: "year" | "month";
|
|
291
|
-
}
|
|
292
|
-
/** Membership policy + compliance copy stored on the group row. */
|
|
293
|
-
interface ChapterPolicy {
|
|
294
|
-
disclaimerText?: string;
|
|
295
|
-
refundPolicyText?: string;
|
|
296
|
-
trustCopy?: string;
|
|
297
|
-
commitmentText?: string;
|
|
298
|
-
normsText?: string;
|
|
299
|
-
}
|
|
406
|
+
|
|
300
407
|
/** One owner-editable transactional email template. */
|
|
301
408
|
interface EmailTemplate {
|
|
302
409
|
subject: string;
|
|
@@ -378,6 +485,11 @@ interface ResolvedPipeline {
|
|
|
378
485
|
interface ChapterApplication {
|
|
379
486
|
required?: readonly string[];
|
|
380
487
|
optional?: readonly string[];
|
|
488
|
+
/** Per-field CEL conditions — show a field, or demand it, based on the
|
|
489
|
+
* answers so far. Enforced server-side as well as rendered, so a hidden
|
|
490
|
+
* field is never demanded and a conditionally-required one cannot be
|
|
491
|
+
* skipped by posting directly. Validated when the chapter is defined. */
|
|
492
|
+
conditions?: Record<string, FieldConditions>;
|
|
381
493
|
/** Per-field character cap. Fields not listed use `defaultMaxLen`. */
|
|
382
494
|
maxLen?: Record<string, number>;
|
|
383
495
|
defaultMaxLen?: number;
|
|
@@ -418,6 +530,8 @@ interface ResolvedApplication {
|
|
|
418
530
|
crmFields: readonly string[];
|
|
419
531
|
maxArrayLen: number;
|
|
420
532
|
validateEmail: boolean;
|
|
533
|
+
/** Resolved per-field conditions. Empty means every field is unconditional. */
|
|
534
|
+
conditions: Record<string, FieldConditions>;
|
|
421
535
|
}
|
|
422
536
|
/** The `defineChapter()` config a site fills in. */
|
|
423
537
|
interface ChapterConfig {
|
|
@@ -439,8 +553,10 @@ interface ChapterConfig {
|
|
|
439
553
|
/** Enable a public, host-rendered formation application workflow. */
|
|
440
554
|
formation?: LeaderFormationConfig;
|
|
441
555
|
thesis?: unknown;
|
|
442
|
-
/** Required in `chapter` mode. */
|
|
556
|
+
/** Required in `chapter` mode, and the fallback when `tiers` is empty. */
|
|
443
557
|
prices?: ChapterPrices;
|
|
558
|
+
/** Membership tiers. A tier priced at 0 is free and never touches Stripe. */
|
|
559
|
+
tiers?: ChapterTierConfig[];
|
|
444
560
|
policy?: ChapterPolicy;
|
|
445
561
|
/** `notificationEmail` required in `chapter` mode. */
|
|
446
562
|
emails?: ChapterEmails;
|
|
@@ -1005,6 +1121,9 @@ declare function submitApplication(db: ChapterDb, chapter: Chapter, fields: Reco
|
|
|
1005
1121
|
groupId?: string;
|
|
1006
1122
|
now: number;
|
|
1007
1123
|
newId: () => string;
|
|
1124
|
+
/** Tier ids this chapter offers. A posted `tierId` outside it is refused;
|
|
1125
|
+
* omit to accept any (pre-tier callers). */
|
|
1126
|
+
tierIds?: readonly string[];
|
|
1008
1127
|
}): Promise<SubmitResult>;
|
|
1009
1128
|
/** The `groups`-row fields the join config exposes. */
|
|
1010
1129
|
interface JoinConfigGroup {
|
|
@@ -1023,8 +1142,14 @@ interface JoinConfigGroup {
|
|
|
1023
1142
|
* group row plus `paymentsReady`. When payments aren't wired the join flow drops
|
|
1024
1143
|
* the payment step (C2) — the worker computes `paymentsReady` from the group's
|
|
1025
1144
|
* Stripe keys + vault secret. Pure.
|
|
1145
|
+
*
|
|
1146
|
+
* `tiers` carries the offerable membership tiers. It is additive: the legacy
|
|
1147
|
+
* `standardPriceCents`/`foundingDiscountCents` fields still describe the first
|
|
1148
|
+
* tier, so a join page written before tiers keeps rendering unchanged. A free
|
|
1149
|
+
* tier appears here with `free: true` even when Stripe is unconfigured, because
|
|
1150
|
+
* nothing needs charging for it.
|
|
1026
1151
|
*/
|
|
1027
|
-
declare function joinConfig(group: JoinConfigGroup, paymentsReady: boolean): Record<string, unknown>;
|
|
1152
|
+
declare function joinConfig(group: JoinConfigGroup, paymentsReady: boolean, tiers?: readonly JoinConfigTier[], conditions?: Readonly<Record<string, FieldConditions>>): Record<string, unknown>;
|
|
1028
1153
|
|
|
1029
1154
|
/** The contact data the hub shares for a prospect. `hubRecordId` is the stable
|
|
1030
1155
|
* idempotency key (the hub's crm_record id). */
|
|
@@ -1724,4 +1849,18 @@ type ApplicationBookingPatch = {
|
|
|
1724
1849
|
* already there (never backward). */
|
|
1725
1850
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1726
1851
|
|
|
1727
|
-
|
|
1852
|
+
/** A `groups` row as the tier loader needs it. */
|
|
1853
|
+
type TierGroupRow = TierGroup & {
|
|
1854
|
+
id?: string;
|
|
1855
|
+
};
|
|
1856
|
+
/**
|
|
1857
|
+
* Every tier a group offers, ordered, including the implicit tier synthesized
|
|
1858
|
+
* for a chapter that predates tiers. Never throws on a missing namespace: a
|
|
1859
|
+
* deployment whose schema has not been pushed yet reads as "no rows", which
|
|
1860
|
+
* resolves to the legacy single tier.
|
|
1861
|
+
*/
|
|
1862
|
+
declare function loadTiers(db: ChapterDb, group: TierGroupRow): Promise<ChapterTier[]>;
|
|
1863
|
+
/** The tiers a join page may show: active, and joinable as configured. */
|
|
1864
|
+
declare function loadOfferableTiers(db: ChapterDb, group: TierGroupRow, hasSecretKey: boolean): Promise<ChapterTier[]>;
|
|
1865
|
+
|
|
1866
|
+
export { type AccountModel, type AdminNotificationTrigger, type Applicant, type ApplicationBookingPatch, type ApplicationRecord, type ApplicationSummary, type Attr, type AttrType, type Chapter, type ChapterApplication, type ChapterAuth, type ChapterBrand, type ChapterConfig, type ChapterCopy, type ChapterCopyInput, type ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkReader, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterRunbookHints, type ChapterScheduling, type ChapterSends, type ChapterTier, type ChapterTierConfig, type ClerkInviteInput, type ClerkMetadataInput, type ClerkResult, type ClerkUserInput, type ClerkUserRecord, type CompiledChapterBrandTokens, DEFAULT_CHAPTER_COPY, DEFAULT_SHARE_FIELDS, type DashboardMetricData, type DashboardMetricSeries, type DbOp, type DbRules, type DbSchema, type DeliveryDecision, type EmailGroup, type EmailTemplate, type EmailTemplateRow, type Entity, type ExistingMeeting, type GuardResult, type IntegrationDescriptor, type IntegrationProvision, type IntegrationSecret, type IntegrationSetting, type IntegrationSync, type JoinConfigGroup, type JoinConfigTier, type LeaderCrmOptions, type LeaderFormationConfig, type LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NetworkRecord, type NetworkRecordNote, type NetworkRecordPage, type NetworkRollup, type NetworkRollupTarget, type NetworkSharedNote, type NetworkSnapshot, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedLeaderFormation, type ResolvedNetwork, type ResolvedNetworkReader, type ResolvedNetworkTarget, type ResolvedOperations, type ResolvedPipeline, type ResolvedScheduling, type ResolvedSends, type RoleChangeContext, type Rule, SCHEDULING_DEFAULTS, type SchedulingErrors, type SecretMode, type SecretStore, type SessionUser, type SharedBusiness, type SharedPerson, type SharedRecord, type SharedRecordV1, type SharedRecordV2, type StripeEvent, type StripeResult, type SubmitResult, type TierGroup, type TierGroupRow, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, buildTierSeeds, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterBrandFromTokens, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, findTier, firstPaymentPatch, formatChapterCopy, formationFields, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, joinConfigTiers, leaderCrmConfig, loadOfferableTiers, loadTiers, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, offerableTiers, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolveChapterCopy, resolveLeaderFormation, resolvePipeline, resolveScheduling, resolveTiers, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, tierIsFree, tierPayable, updateClerkUserMetadata, updateClerkUserMetadataByEmail, validateScheduling, verifyStripeSignature, webhookMutationId };
|