@odla-ai/chapter 0.25.6 → 0.26.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.
- package/README.md +118 -13
- package/dist/{chunk-5SWVMJZN.js → chunk-4QZEAWQL.js} +183 -45
- package/dist/chunk-4QZEAWQL.js.map +1 -0
- package/dist/{chunk-WGQO4WDJ.js → chunk-OIWCKF2G.js} +20 -3
- package/dist/chunk-OIWCKF2G.js.map +1 -0
- package/dist/{chunk-WHA3MUDQ.js → chunk-QBTFQUDL.js} +2 -2
- package/dist/{copy-context-DI21CYQ3.d.ts → copy-context-CLvhJhrF.d.ts} +73 -42
- package/dist/index.cjs +327 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +170 -58
- package/dist/index.d.ts +170 -58
- package/dist/index.js +321 -20
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +8 -3
- package/dist/ui/admin/index.js +4 -2
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +5 -3
- package/dist/ui/member/index.d.ts +2 -2
- package/dist/ui/member/index.js +2 -2
- package/dist/worker/index.cjs +552 -208
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +76 -42
- package/dist/worker/index.d.ts +76 -42
- package/dist/worker/index.js +558 -209
- package/dist/worker/index.js.map +1 -1
- package/package.json +3 -3
- package/runbooks/adopt-existing.md +12 -1
- package/runbooks/greenfield.md +29 -7
- package/dist/chunk-5SWVMJZN.js.map +0 -1
- package/dist/chunk-WGQO4WDJ.js.map +0 -1
- /package/dist/{chunk-WHA3MUDQ.js.map → chunk-QBTFQUDL.js.map} +0 -0
package/dist/worker/index.d.cts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { CrmConfig, Crm } from '@odla-ai/crm';
|
|
2
2
|
import { initAdmin } from '@odla-ai/db';
|
|
3
3
|
|
|
4
|
+
type TextFields$1<Key extends string> = {
|
|
5
|
+
[Field in Key]: string;
|
|
6
|
+
};
|
|
7
|
+
/** User-visible language for sharing, delivery state, and leader rollups. */
|
|
8
|
+
type AdminNetworkCopy = TextFields$1<"title" | "allowlistDescription" | "sharing" | "shareWith" | "shared" | "shareFailed" | "deliveryFailed" | "loadingRollup" | "loadRollupFailed" | "overview" | "configuredFollowers" | "reachableFollowers" | "recordsAcrossFollowers" | "noFollowers" | "followers" | "available" | "unavailable" | "recordTotals" | "noRecordTotals">;
|
|
9
|
+
|
|
4
10
|
type TextFields<Key extends string> = {
|
|
5
11
|
[Field in Key]: string;
|
|
6
12
|
};
|
|
7
|
-
/**
|
|
8
|
-
* Complete user-visible language owned by Chapter's packaged surfaces.
|
|
9
|
-
*
|
|
10
|
-
* Copy is serializable text; use render slots when presentation needs markup and
|
|
11
|
-
* `formatChapterCopy()` for typed placeholders.
|
|
12
|
-
*/
|
|
13
|
+
/** Complete serializable language for Chapter surfaces; use render slots for markup and `formatChapterCopy()` for placeholders. */
|
|
13
14
|
interface ChapterCopy {
|
|
14
15
|
common: TextFields<"loading" | "saved" | "unknown">;
|
|
15
16
|
join: {
|
|
@@ -35,7 +36,7 @@ interface ChapterCopy {
|
|
|
35
36
|
admin: {
|
|
36
37
|
auth: TextFields<"checking" | "notAuthorized" | "accountNotAuthorized" | "thisAccount" | "signOut" | "loading" | "signInNotConfigured" | "missingPublishableKey" | "noWorkspaces" | "signInTagline">;
|
|
37
38
|
shell: TextFields<"adminRole" | "adminConsole" | "adminName" | "navigationLabel">;
|
|
38
|
-
workspaces: TextFields<"dashboard" | "overview" | "billing" | "people" | "settings" | "calendar" | "email" | "dashboardViewsLabel" | "settingsViewsLabel" | "collectionsLabel">;
|
|
39
|
+
workspaces: TextFields<"dashboard" | "overview" | "billing" | "people" | "portfolio" | "settings" | "calendar" | "email" | "chapters" | "formations" | "dealFlow" | "dashboardViewsLabel" | "settingsViewsLabel" | "collectionsLabel" | "portfolioViewsLabel">;
|
|
39
40
|
dashboard: TextFields<"loading" | "loadFailed" | "upcomingCalls" | "callsNeedAttention" | "noUpcomingCalls" | "drift" | "open" | "meet" | "applications" | "newMembers" | "newMembersUnavailable" | "revenueAdded" | "revenue" | "revenueUnavailable" | "pipeline" | "pipelineLabel" | "thisWeek" | "noChange" | "activeMemberships" | "annualRunRate" | "testMode">;
|
|
40
41
|
billing: TextFields<"loading" | "loadFailed" | "notConfigured" | "active" | "annualized" | "renewingSoon" | "pastDue" | "subscriptions" | "testMode" | "truncated" | "name" | "email" | "application" | "subscription" | "cancelling" | "amount" | "renews">;
|
|
41
42
|
availability: TextFields<"loading" | "loadFailed" | "saved" | "title" | "days" | "startHour" | "endHour" | "slotMinutes" | "minNoticeHours" | "windowDays" | "timezone" | "summaryTemplate" | "save"> & {
|
|
@@ -43,7 +44,7 @@ interface ChapterCopy {
|
|
|
43
44
|
};
|
|
44
45
|
email: TextFields<"loading" | "loadFailed" | "saved" | "sent" | "testFailed" | "delivery" | "notificationAddress" | "replyTo" | "debugInbox" | "debugInboxHint" | "sendTest" | "enabled" | "subject" | "body" | "save" | "sendLog" | "sentColumn" | "templateColumn" | "statusColumn" | "toColumn" | "failed" | "redirected" | "delivered">;
|
|
45
46
|
meetings: TextFields<"loading" | "loadFailed" | "cancelConfirm" | "newStartPrompt" | "parseFailed" | "agenda" | "empty" | "unknown" | "drift" | "meet" | "reschedule" | "cancel">;
|
|
46
|
-
network:
|
|
47
|
+
network: AdminNetworkCopy;
|
|
47
48
|
records: TextFields<"workflowMissing" | "comms" | "commsHistory" | "scheduling" | "billing" | "notes" | "access" | "sharing" | "lifecycle" | "role" | "superAdminHint" | "noAccount" | "approve" | "refund" | "approved" | "refunded" | "roleSet" | "messageSent" | "messageNotSent" | "loadingTemplates" | "template" | "chooseTemplate" | "sending" | "send" | "noMessages" | "message" | "newStartPrompt" | "parseFailed" | "cancelConfirm" | "callCancelled" | "callRescheduled" | "noApplication" | "loadingMeetings" | "noMeetings" | "joinMeeting" | "openCalendar" | "reschedule" | "cancel">;
|
|
48
49
|
};
|
|
49
50
|
}
|
|
@@ -53,6 +54,66 @@ type DeepPartial<T> = T extends readonly (infer Item)[] ? readonly Item[] : T ex
|
|
|
53
54
|
/** Recursively partial copy overrides accepted by `defineChapter({ copy })`. */
|
|
54
55
|
type ChapterCopyInput = DeepPartial<ChapterCopy>;
|
|
55
56
|
|
|
57
|
+
/** One follower site a leader can push CRM records to. The secret VALUE never
|
|
58
|
+
* lives in config: `secretName` names the leader tenant's vaulted copy of the
|
|
59
|
+
* follower's `network_share_secret`. */
|
|
60
|
+
interface ChapterNetworkTarget {
|
|
61
|
+
/** Stable lowercase slug used by the UI, audit tags, and default secret name. */
|
|
62
|
+
id: string;
|
|
63
|
+
/** Human-facing site name. Defaults to `id`. */
|
|
64
|
+
name?: string;
|
|
65
|
+
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
66
|
+
url: string;
|
|
67
|
+
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
68
|
+
* `network_share_<id-with-underscores>`. */
|
|
69
|
+
secretName?: string;
|
|
70
|
+
/** Per-record-type field allowlist. If present, omitted types cannot be sent
|
|
71
|
+
* to this target. Without it, package-safe person/company defaults apply. */
|
|
72
|
+
fields?: Record<string, readonly string[]>;
|
|
73
|
+
}
|
|
74
|
+
/** Leader/follower network configuration. Followers need no code config to
|
|
75
|
+
* receive records; they only vault `network_share_secret`. */
|
|
76
|
+
interface ChapterNetwork {
|
|
77
|
+
targets?: readonly ChapterNetworkTarget[];
|
|
78
|
+
}
|
|
79
|
+
/** Public chapter-formation intake backed by one CRM record type. The host owns
|
|
80
|
+
* the branded form; Chapter owns the bounded, idempotent write contract. */
|
|
81
|
+
interface LeaderFormationConfig {
|
|
82
|
+
/** CRM type receiving submissions. Default `"chapter_application"`. */
|
|
83
|
+
type?: string;
|
|
84
|
+
/** Public fields that must be non-empty strings. */
|
|
85
|
+
required?: readonly string[];
|
|
86
|
+
/** Additional public fields accepted by the route. */
|
|
87
|
+
optional?: readonly string[];
|
|
88
|
+
maxLen?: Record<string, number>;
|
|
89
|
+
/** Per-string cap when `maxLen` has no field override. Default 4000. */
|
|
90
|
+
defaultMaxLen?: number;
|
|
91
|
+
/** Maximum JSON request size in characters. Default 32768. */
|
|
92
|
+
bodyCap?: number;
|
|
93
|
+
}
|
|
94
|
+
/** Fully resolved formation intake policy. */
|
|
95
|
+
interface ResolvedLeaderFormation {
|
|
96
|
+
enabled: boolean;
|
|
97
|
+
type: string;
|
|
98
|
+
required: readonly string[];
|
|
99
|
+
optional: readonly string[];
|
|
100
|
+
maxLen: Record<string, number>;
|
|
101
|
+
defaultMaxLen: number;
|
|
102
|
+
bodyCap: number;
|
|
103
|
+
}
|
|
104
|
+
/** A validated network target carried on the resolved chapter engine. */
|
|
105
|
+
interface ResolvedNetworkTarget {
|
|
106
|
+
id: string;
|
|
107
|
+
name: string;
|
|
108
|
+
url: string;
|
|
109
|
+
secretName: string;
|
|
110
|
+
fields?: Record<string, readonly string[]>;
|
|
111
|
+
}
|
|
112
|
+
/** Fully-resolved leader network configuration. */
|
|
113
|
+
interface ResolvedNetwork {
|
|
114
|
+
targets: readonly ResolvedNetworkTarget[];
|
|
115
|
+
}
|
|
116
|
+
|
|
56
117
|
/** Which feature profile a site runs. `chapter` is the full public member site
|
|
57
118
|
* (join, Stripe membership, booking, member area, admin, CRM); `hub` is
|
|
58
119
|
* admin-only and CRM-focused (a directory/registry over the same CRM). */
|
|
@@ -158,40 +219,6 @@ interface ChapterBrand {
|
|
|
158
219
|
}>>;
|
|
159
220
|
logos?: string;
|
|
160
221
|
}
|
|
161
|
-
/** One follower site a leader can push CRM records to. The secret VALUE never
|
|
162
|
-
* lives in config: `secretName` names the leader tenant's vaulted copy of the
|
|
163
|
-
* follower's `network_share_secret`. */
|
|
164
|
-
interface ChapterNetworkTarget {
|
|
165
|
-
/** Stable lowercase slug used by the UI, audit tags, and default secret name. */
|
|
166
|
-
id: string;
|
|
167
|
-
/** Human-facing site name. Defaults to `id`. */
|
|
168
|
-
name?: string;
|
|
169
|
-
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
170
|
-
url: string;
|
|
171
|
-
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
172
|
-
* `network_share_<id-with-underscores>`. */
|
|
173
|
-
secretName?: string;
|
|
174
|
-
/** Per-record-type field allowlist. If present, omitted types cannot be sent
|
|
175
|
-
* to this target. Without it, package-safe person/company defaults apply. */
|
|
176
|
-
fields?: Record<string, readonly string[]>;
|
|
177
|
-
}
|
|
178
|
-
/** Leader/follower network configuration. Followers need no code config to
|
|
179
|
-
* receive records; they only vault `network_share_secret`. */
|
|
180
|
-
interface ChapterNetwork {
|
|
181
|
-
targets?: readonly ChapterNetworkTarget[];
|
|
182
|
-
}
|
|
183
|
-
/** A validated network target carried on the resolved chapter engine. */
|
|
184
|
-
interface ResolvedNetworkTarget {
|
|
185
|
-
id: string;
|
|
186
|
-
name: string;
|
|
187
|
-
url: string;
|
|
188
|
-
secretName: string;
|
|
189
|
-
fields?: Record<string, readonly string[]>;
|
|
190
|
-
}
|
|
191
|
-
/** Fully-resolved leader network configuration. */
|
|
192
|
-
interface ResolvedNetwork {
|
|
193
|
-
targets: readonly ResolvedNetworkTarget[];
|
|
194
|
-
}
|
|
195
222
|
/** Membership pricing for the group row (chapter mode). */
|
|
196
223
|
interface ChapterPrices {
|
|
197
224
|
standardCents: number;
|
|
@@ -348,6 +375,8 @@ interface ChapterConfig {
|
|
|
348
375
|
/** Leader → follower delivery targets. Secret values stay in the leader
|
|
349
376
|
* tenant vault; see {@link ChapterNetworkTarget}. */
|
|
350
377
|
network?: ChapterNetwork;
|
|
378
|
+
/** Enable a public, host-rendered formation application workflow. */
|
|
379
|
+
formation?: LeaderFormationConfig;
|
|
351
380
|
thesis?: unknown;
|
|
352
381
|
/** Required in `chapter` mode. */
|
|
353
382
|
prices?: ChapterPrices;
|
|
@@ -438,6 +467,8 @@ interface Chapter {
|
|
|
438
467
|
copy: ChapterCopy;
|
|
439
468
|
/** Validated follower targets for leader-driven record pushes. */
|
|
440
469
|
network: ResolvedNetwork;
|
|
470
|
+
/** Resolved public formation intake contract (disabled when omitted). */
|
|
471
|
+
formation: ResolvedLeaderFormation;
|
|
441
472
|
/** Resolved CRM engine (from `defineCrm`). */
|
|
442
473
|
crm: Crm;
|
|
443
474
|
/** Resolved auth policy (source, claim, ladder, super-admin tier). */
|
|
@@ -480,6 +511,9 @@ interface ChapterEnv {
|
|
|
480
511
|
ODLA_TENANT: string;
|
|
481
512
|
ODLA_PLATFORM: string;
|
|
482
513
|
ODLA_APP_ID: string;
|
|
514
|
+
/** Registry lifetime for this exact app/database. Discussion reference
|
|
515
|
+
* reads fail closed when it is absent or stale. */
|
|
516
|
+
ODLA_APP_INCARNATION?: string;
|
|
483
517
|
ODLA_ENV: string;
|
|
484
518
|
ODLA_API_KEY: string;
|
|
485
519
|
SEND_EMAIL?: {
|
package/dist/worker/index.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { CrmConfig, Crm } from '@odla-ai/crm';
|
|
2
2
|
import { initAdmin } from '@odla-ai/db';
|
|
3
3
|
|
|
4
|
+
type TextFields$1<Key extends string> = {
|
|
5
|
+
[Field in Key]: string;
|
|
6
|
+
};
|
|
7
|
+
/** User-visible language for sharing, delivery state, and leader rollups. */
|
|
8
|
+
type AdminNetworkCopy = TextFields$1<"title" | "allowlistDescription" | "sharing" | "shareWith" | "shared" | "shareFailed" | "deliveryFailed" | "loadingRollup" | "loadRollupFailed" | "overview" | "configuredFollowers" | "reachableFollowers" | "recordsAcrossFollowers" | "noFollowers" | "followers" | "available" | "unavailable" | "recordTotals" | "noRecordTotals">;
|
|
9
|
+
|
|
4
10
|
type TextFields<Key extends string> = {
|
|
5
11
|
[Field in Key]: string;
|
|
6
12
|
};
|
|
7
|
-
/**
|
|
8
|
-
* Complete user-visible language owned by Chapter's packaged surfaces.
|
|
9
|
-
*
|
|
10
|
-
* Copy is serializable text; use render slots when presentation needs markup and
|
|
11
|
-
* `formatChapterCopy()` for typed placeholders.
|
|
12
|
-
*/
|
|
13
|
+
/** Complete serializable language for Chapter surfaces; use render slots for markup and `formatChapterCopy()` for placeholders. */
|
|
13
14
|
interface ChapterCopy {
|
|
14
15
|
common: TextFields<"loading" | "saved" | "unknown">;
|
|
15
16
|
join: {
|
|
@@ -35,7 +36,7 @@ interface ChapterCopy {
|
|
|
35
36
|
admin: {
|
|
36
37
|
auth: TextFields<"checking" | "notAuthorized" | "accountNotAuthorized" | "thisAccount" | "signOut" | "loading" | "signInNotConfigured" | "missingPublishableKey" | "noWorkspaces" | "signInTagline">;
|
|
37
38
|
shell: TextFields<"adminRole" | "adminConsole" | "adminName" | "navigationLabel">;
|
|
38
|
-
workspaces: TextFields<"dashboard" | "overview" | "billing" | "people" | "settings" | "calendar" | "email" | "dashboardViewsLabel" | "settingsViewsLabel" | "collectionsLabel">;
|
|
39
|
+
workspaces: TextFields<"dashboard" | "overview" | "billing" | "people" | "portfolio" | "settings" | "calendar" | "email" | "chapters" | "formations" | "dealFlow" | "dashboardViewsLabel" | "settingsViewsLabel" | "collectionsLabel" | "portfolioViewsLabel">;
|
|
39
40
|
dashboard: TextFields<"loading" | "loadFailed" | "upcomingCalls" | "callsNeedAttention" | "noUpcomingCalls" | "drift" | "open" | "meet" | "applications" | "newMembers" | "newMembersUnavailable" | "revenueAdded" | "revenue" | "revenueUnavailable" | "pipeline" | "pipelineLabel" | "thisWeek" | "noChange" | "activeMemberships" | "annualRunRate" | "testMode">;
|
|
40
41
|
billing: TextFields<"loading" | "loadFailed" | "notConfigured" | "active" | "annualized" | "renewingSoon" | "pastDue" | "subscriptions" | "testMode" | "truncated" | "name" | "email" | "application" | "subscription" | "cancelling" | "amount" | "renews">;
|
|
41
42
|
availability: TextFields<"loading" | "loadFailed" | "saved" | "title" | "days" | "startHour" | "endHour" | "slotMinutes" | "minNoticeHours" | "windowDays" | "timezone" | "summaryTemplate" | "save"> & {
|
|
@@ -43,7 +44,7 @@ interface ChapterCopy {
|
|
|
43
44
|
};
|
|
44
45
|
email: TextFields<"loading" | "loadFailed" | "saved" | "sent" | "testFailed" | "delivery" | "notificationAddress" | "replyTo" | "debugInbox" | "debugInboxHint" | "sendTest" | "enabled" | "subject" | "body" | "save" | "sendLog" | "sentColumn" | "templateColumn" | "statusColumn" | "toColumn" | "failed" | "redirected" | "delivered">;
|
|
45
46
|
meetings: TextFields<"loading" | "loadFailed" | "cancelConfirm" | "newStartPrompt" | "parseFailed" | "agenda" | "empty" | "unknown" | "drift" | "meet" | "reschedule" | "cancel">;
|
|
46
|
-
network:
|
|
47
|
+
network: AdminNetworkCopy;
|
|
47
48
|
records: TextFields<"workflowMissing" | "comms" | "commsHistory" | "scheduling" | "billing" | "notes" | "access" | "sharing" | "lifecycle" | "role" | "superAdminHint" | "noAccount" | "approve" | "refund" | "approved" | "refunded" | "roleSet" | "messageSent" | "messageNotSent" | "loadingTemplates" | "template" | "chooseTemplate" | "sending" | "send" | "noMessages" | "message" | "newStartPrompt" | "parseFailed" | "cancelConfirm" | "callCancelled" | "callRescheduled" | "noApplication" | "loadingMeetings" | "noMeetings" | "joinMeeting" | "openCalendar" | "reschedule" | "cancel">;
|
|
48
49
|
};
|
|
49
50
|
}
|
|
@@ -53,6 +54,66 @@ type DeepPartial<T> = T extends readonly (infer Item)[] ? readonly Item[] : T ex
|
|
|
53
54
|
/** Recursively partial copy overrides accepted by `defineChapter({ copy })`. */
|
|
54
55
|
type ChapterCopyInput = DeepPartial<ChapterCopy>;
|
|
55
56
|
|
|
57
|
+
/** One follower site a leader can push CRM records to. The secret VALUE never
|
|
58
|
+
* lives in config: `secretName` names the leader tenant's vaulted copy of the
|
|
59
|
+
* follower's `network_share_secret`. */
|
|
60
|
+
interface ChapterNetworkTarget {
|
|
61
|
+
/** Stable lowercase slug used by the UI, audit tags, and default secret name. */
|
|
62
|
+
id: string;
|
|
63
|
+
/** Human-facing site name. Defaults to `id`. */
|
|
64
|
+
name?: string;
|
|
65
|
+
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
66
|
+
url: string;
|
|
67
|
+
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
68
|
+
* `network_share_<id-with-underscores>`. */
|
|
69
|
+
secretName?: string;
|
|
70
|
+
/** Per-record-type field allowlist. If present, omitted types cannot be sent
|
|
71
|
+
* to this target. Without it, package-safe person/company defaults apply. */
|
|
72
|
+
fields?: Record<string, readonly string[]>;
|
|
73
|
+
}
|
|
74
|
+
/** Leader/follower network configuration. Followers need no code config to
|
|
75
|
+
* receive records; they only vault `network_share_secret`. */
|
|
76
|
+
interface ChapterNetwork {
|
|
77
|
+
targets?: readonly ChapterNetworkTarget[];
|
|
78
|
+
}
|
|
79
|
+
/** Public chapter-formation intake backed by one CRM record type. The host owns
|
|
80
|
+
* the branded form; Chapter owns the bounded, idempotent write contract. */
|
|
81
|
+
interface LeaderFormationConfig {
|
|
82
|
+
/** CRM type receiving submissions. Default `"chapter_application"`. */
|
|
83
|
+
type?: string;
|
|
84
|
+
/** Public fields that must be non-empty strings. */
|
|
85
|
+
required?: readonly string[];
|
|
86
|
+
/** Additional public fields accepted by the route. */
|
|
87
|
+
optional?: readonly string[];
|
|
88
|
+
maxLen?: Record<string, number>;
|
|
89
|
+
/** Per-string cap when `maxLen` has no field override. Default 4000. */
|
|
90
|
+
defaultMaxLen?: number;
|
|
91
|
+
/** Maximum JSON request size in characters. Default 32768. */
|
|
92
|
+
bodyCap?: number;
|
|
93
|
+
}
|
|
94
|
+
/** Fully resolved formation intake policy. */
|
|
95
|
+
interface ResolvedLeaderFormation {
|
|
96
|
+
enabled: boolean;
|
|
97
|
+
type: string;
|
|
98
|
+
required: readonly string[];
|
|
99
|
+
optional: readonly string[];
|
|
100
|
+
maxLen: Record<string, number>;
|
|
101
|
+
defaultMaxLen: number;
|
|
102
|
+
bodyCap: number;
|
|
103
|
+
}
|
|
104
|
+
/** A validated network target carried on the resolved chapter engine. */
|
|
105
|
+
interface ResolvedNetworkTarget {
|
|
106
|
+
id: string;
|
|
107
|
+
name: string;
|
|
108
|
+
url: string;
|
|
109
|
+
secretName: string;
|
|
110
|
+
fields?: Record<string, readonly string[]>;
|
|
111
|
+
}
|
|
112
|
+
/** Fully-resolved leader network configuration. */
|
|
113
|
+
interface ResolvedNetwork {
|
|
114
|
+
targets: readonly ResolvedNetworkTarget[];
|
|
115
|
+
}
|
|
116
|
+
|
|
56
117
|
/** Which feature profile a site runs. `chapter` is the full public member site
|
|
57
118
|
* (join, Stripe membership, booking, member area, admin, CRM); `hub` is
|
|
58
119
|
* admin-only and CRM-focused (a directory/registry over the same CRM). */
|
|
@@ -158,40 +219,6 @@ interface ChapterBrand {
|
|
|
158
219
|
}>>;
|
|
159
220
|
logos?: string;
|
|
160
221
|
}
|
|
161
|
-
/** One follower site a leader can push CRM records to. The secret VALUE never
|
|
162
|
-
* lives in config: `secretName` names the leader tenant's vaulted copy of the
|
|
163
|
-
* follower's `network_share_secret`. */
|
|
164
|
-
interface ChapterNetworkTarget {
|
|
165
|
-
/** Stable lowercase slug used by the UI, audit tags, and default secret name. */
|
|
166
|
-
id: string;
|
|
167
|
-
/** Human-facing site name. Defaults to `id`. */
|
|
168
|
-
name?: string;
|
|
169
|
-
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
170
|
-
url: string;
|
|
171
|
-
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
172
|
-
* `network_share_<id-with-underscores>`. */
|
|
173
|
-
secretName?: string;
|
|
174
|
-
/** Per-record-type field allowlist. If present, omitted types cannot be sent
|
|
175
|
-
* to this target. Without it, package-safe person/company defaults apply. */
|
|
176
|
-
fields?: Record<string, readonly string[]>;
|
|
177
|
-
}
|
|
178
|
-
/** Leader/follower network configuration. Followers need no code config to
|
|
179
|
-
* receive records; they only vault `network_share_secret`. */
|
|
180
|
-
interface ChapterNetwork {
|
|
181
|
-
targets?: readonly ChapterNetworkTarget[];
|
|
182
|
-
}
|
|
183
|
-
/** A validated network target carried on the resolved chapter engine. */
|
|
184
|
-
interface ResolvedNetworkTarget {
|
|
185
|
-
id: string;
|
|
186
|
-
name: string;
|
|
187
|
-
url: string;
|
|
188
|
-
secretName: string;
|
|
189
|
-
fields?: Record<string, readonly string[]>;
|
|
190
|
-
}
|
|
191
|
-
/** Fully-resolved leader network configuration. */
|
|
192
|
-
interface ResolvedNetwork {
|
|
193
|
-
targets: readonly ResolvedNetworkTarget[];
|
|
194
|
-
}
|
|
195
222
|
/** Membership pricing for the group row (chapter mode). */
|
|
196
223
|
interface ChapterPrices {
|
|
197
224
|
standardCents: number;
|
|
@@ -348,6 +375,8 @@ interface ChapterConfig {
|
|
|
348
375
|
/** Leader → follower delivery targets. Secret values stay in the leader
|
|
349
376
|
* tenant vault; see {@link ChapterNetworkTarget}. */
|
|
350
377
|
network?: ChapterNetwork;
|
|
378
|
+
/** Enable a public, host-rendered formation application workflow. */
|
|
379
|
+
formation?: LeaderFormationConfig;
|
|
351
380
|
thesis?: unknown;
|
|
352
381
|
/** Required in `chapter` mode. */
|
|
353
382
|
prices?: ChapterPrices;
|
|
@@ -438,6 +467,8 @@ interface Chapter {
|
|
|
438
467
|
copy: ChapterCopy;
|
|
439
468
|
/** Validated follower targets for leader-driven record pushes. */
|
|
440
469
|
network: ResolvedNetwork;
|
|
470
|
+
/** Resolved public formation intake contract (disabled when omitted). */
|
|
471
|
+
formation: ResolvedLeaderFormation;
|
|
441
472
|
/** Resolved CRM engine (from `defineCrm`). */
|
|
442
473
|
crm: Crm;
|
|
443
474
|
/** Resolved auth policy (source, claim, ladder, super-admin tier). */
|
|
@@ -480,6 +511,9 @@ interface ChapterEnv {
|
|
|
480
511
|
ODLA_TENANT: string;
|
|
481
512
|
ODLA_PLATFORM: string;
|
|
482
513
|
ODLA_APP_ID: string;
|
|
514
|
+
/** Registry lifetime for this exact app/database. Discussion reference
|
|
515
|
+
* reads fail closed when it is absent or stale. */
|
|
516
|
+
ODLA_APP_INCARNATION?: string;
|
|
483
517
|
ODLA_ENV: string;
|
|
484
518
|
ODLA_API_KEY: string;
|
|
485
519
|
SEND_EMAIL?: {
|