@odla-ai/chapter 0.20.2 → 0.22.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 +147 -32
- package/dist/{chunk-LME2IHY5.js → chunk-ILGUJXSB.js} +1 -1
- package/dist/chunk-ILGUJXSB.js.map +1 -0
- package/dist/chunk-IWW5VAAC.js +1666 -0
- package/dist/chunk-IWW5VAAC.js.map +1 -0
- package/dist/chunk-VZPBTTO3.js +91 -0
- package/dist/chunk-VZPBTTO3.js.map +1 -0
- package/dist/index.cjs +72 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +78 -19
- package/dist/index.d.ts +78 -19
- package/dist/index.js +72 -6
- package/dist/index.js.map +1 -1
- package/dist/{types-D2fGiNG8.d.ts → types-CgWUQ2MH.d.ts} +50 -8
- package/dist/ui/admin/index.d.ts +150 -83
- package/dist/ui/admin/index.js +14 -2
- package/dist/ui/index.d.ts +3 -2
- package/dist/ui/index.js +15 -3
- package/dist/ui/member/index.d.ts +3 -1
- package/dist/ui/member/index.js +2 -2
- package/dist/worker/index.cjs +28 -16
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +50 -8
- package/dist/worker/index.d.ts +50 -8
- package/dist/worker/index.js +28 -16
- package/dist/worker/index.js.map +1 -1
- package/package.json +3 -3
- package/runbooks/adopt-existing.md +22 -4
- package/runbooks/greenfield.md +19 -9
- package/dist/chunk-LME2IHY5.js.map +0 -1
- package/dist/chunk-MKXHZMAP.js +0 -51
- package/dist/chunk-MKXHZMAP.js.map +0 -1
- package/dist/chunk-UIWFEESI.js +0 -922
- package/dist/chunk-UIWFEESI.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -53,8 +53,50 @@ interface Rule {
|
|
|
53
53
|
}
|
|
54
54
|
/** Namespace → rule set. */
|
|
55
55
|
type DbRules = Record<string, Rule>;
|
|
56
|
-
/**
|
|
56
|
+
/** Typed semantic roles shared by the public site and application surfaces. */
|
|
57
|
+
interface ChapterBrandTokens {
|
|
58
|
+
background?: string;
|
|
59
|
+
surface?: string;
|
|
60
|
+
surface2?: string;
|
|
61
|
+
text?: string;
|
|
62
|
+
textMuted?: string;
|
|
63
|
+
textFaint?: string;
|
|
64
|
+
border?: string;
|
|
65
|
+
borderStrong?: string;
|
|
66
|
+
accent?: string;
|
|
67
|
+
accentStrong?: string;
|
|
68
|
+
accentSoft?: string;
|
|
69
|
+
onAccent?: string;
|
|
70
|
+
good?: string;
|
|
71
|
+
warn?: string;
|
|
72
|
+
danger?: string;
|
|
73
|
+
chart1?: string;
|
|
74
|
+
chart2?: string;
|
|
75
|
+
chart3?: string;
|
|
76
|
+
chart4?: string;
|
|
77
|
+
chart5?: string;
|
|
78
|
+
chart6?: string;
|
|
79
|
+
chartPositive?: string;
|
|
80
|
+
chartNegative?: string;
|
|
81
|
+
/** Admin/application content width, e.g. `"960px"`. */
|
|
82
|
+
contentWidth?: string;
|
|
83
|
+
panelRadius?: string;
|
|
84
|
+
panelShadow?: string;
|
|
85
|
+
masterDetailColumns?: string;
|
|
86
|
+
masterDetailMinHeight?: string;
|
|
87
|
+
/** Chapter-admin page padding shorthand. */
|
|
88
|
+
pagePadding?: string;
|
|
89
|
+
/** Chapter-admin workspace-tab padding shorthand. */
|
|
90
|
+
workspacePadding?: string;
|
|
91
|
+
}
|
|
92
|
+
/** Brand tokens that theme the site: theme, semantic roles, fonts, and logos. */
|
|
57
93
|
interface ChapterBrand {
|
|
94
|
+
/** Preloaded @odla-ai/ui theme name used by ThemeScope. */
|
|
95
|
+
theme?: string;
|
|
96
|
+
/** Admin/application color mode. Explicit light is the safe default. */
|
|
97
|
+
colorScheme?: "light" | "dark" | "system";
|
|
98
|
+
tokens?: ChapterBrandTokens;
|
|
99
|
+
tokensDark?: ChapterBrandTokens;
|
|
58
100
|
/** Palette overrides written into styles.css :root (e.g. `{ moss: "#2F3E34" }`
|
|
59
101
|
* or `--ui-*` token names). Applies in BOTH light and dark unless overridden
|
|
60
102
|
* by {@link paletteDark}. */
|
|
@@ -88,7 +130,7 @@ interface ChapterNetworkTarget {
|
|
|
88
130
|
id: string;
|
|
89
131
|
/** Human-facing site name. Defaults to `id`. */
|
|
90
132
|
name?: string;
|
|
91
|
-
/** Absolute follower origin, e.g. `https://
|
|
133
|
+
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
92
134
|
url: string;
|
|
93
135
|
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
94
136
|
* `network_share_<id-with-underscores>`. */
|
|
@@ -159,10 +201,10 @@ interface ChapterScheduling {
|
|
|
159
201
|
}
|
|
160
202
|
/** How a signed-in user's role is determined.
|
|
161
203
|
*
|
|
162
|
-
* - `"claim"` reads a role ladder from a JWT claim (
|
|
204
|
+
* - `"claim"` reads a role ladder from a JWT claim (the member-site model:
|
|
163
205
|
* `provisional → member → admin`). Admin is the last (highest) rung; the
|
|
164
206
|
* read-only `superAdmins` tier sits above it.
|
|
165
|
-
* - `"table"` gates on the deny-all `admins` allowlist (
|
|
207
|
+
* - `"table"` gates on the deny-all `admins` allowlist (the hub model):
|
|
166
208
|
* a binary "email is an admin or isn't", set only in odla Studio.
|
|
167
209
|
*
|
|
168
210
|
* Defaults: `"claim"` in `chapter` mode, `"table"` in `hub` mode. */
|
|
@@ -189,7 +231,7 @@ interface ResolvedAuth {
|
|
|
189
231
|
}
|
|
190
232
|
/** The application status pipeline. Which statuses exist, and the subsets a site
|
|
191
233
|
* allows a call to be booked from / an application approved from. Defaults to
|
|
192
|
-
*
|
|
234
|
+
* the reference pipeline. Status never moves backwards (package-enforced). */
|
|
193
235
|
interface ChapterPipeline {
|
|
194
236
|
stages?: readonly string[];
|
|
195
237
|
bookableFrom?: readonly string[];
|
|
@@ -206,8 +248,8 @@ interface ResolvedPipeline {
|
|
|
206
248
|
}
|
|
207
249
|
/** The application (join form) validation surface — which string fields are
|
|
208
250
|
* required vs accepted, their max lengths, and the request body cap. Drives
|
|
209
|
-
* submit validation + the CRM slot projection; defaults to
|
|
210
|
-
* The `applications` schema attrs stay fixed
|
|
251
|
+
* submit validation + the CRM slot projection; defaults to the reference form.
|
|
252
|
+
* The `applications` schema attrs stay fixed; this is
|
|
211
253
|
* validation config, not schema generation. */
|
|
212
254
|
interface ChapterApplication {
|
|
213
255
|
required?: readonly string[];
|
|
@@ -279,7 +321,7 @@ interface ChapterConfig {
|
|
|
279
321
|
/** `notificationEmail` required in `chapter` mode. */
|
|
280
322
|
emails?: ChapterEmails;
|
|
281
323
|
scheduling?: ChapterScheduling;
|
|
282
|
-
/** Application status pipeline (stages + bookable/approvable subsets).
|
|
324
|
+
/** Application status pipeline (stages + bookable/approvable subsets). */
|
|
283
325
|
pipeline?: ChapterPipeline;
|
|
284
326
|
/** Join-form validation (required/optional fields, max lengths, body cap). */
|
|
285
327
|
application?: ChapterApplication;
|
|
@@ -439,7 +481,7 @@ declare function createChapterIntegration(chapter: Chapter, options?: ChapterInt
|
|
|
439
481
|
* `chapter` mode only. The auth tables follow {@link ResolvedAuth}: `source:
|
|
440
482
|
* "table"` adds the `admins` allowlist (hub/BNF); `superAdmins` adds the
|
|
441
483
|
* read-only super-admin tier (default on for the `"claim"` ladder). A `"claim"`
|
|
442
|
-
* chapter therefore emits
|
|
484
|
+
* chapter therefore emits the reference namespace set — `applications`,
|
|
443
485
|
* `groups`, `meetings`, `emailLog`, `superAdmins` — with no `admins` table. */
|
|
444
486
|
declare function chapterDb(mode: ChapterMode, auth: ResolvedAuth): {
|
|
445
487
|
schema: DbSchema;
|
|
@@ -457,8 +499,8 @@ declare function buildGroupSeed(config: ChapterConfig): Record<string, unknown>;
|
|
|
457
499
|
/**
|
|
458
500
|
* Apply defaults + validate the auth config into a {@link ResolvedAuth}. Defaults
|
|
459
501
|
* by mode: `chapter` → the `provisional/member/admin` claim ladder with the
|
|
460
|
-
* `superAdmins` tier
|
|
461
|
-
*
|
|
502
|
+
* `superAdmins` tier; `hub` → the `admins` allowlist table with no super tier.
|
|
503
|
+
* Throws at import on a bad policy.
|
|
462
504
|
*/
|
|
463
505
|
declare function resolveAuth(mode: ChapterMode, auth: ChapterAuth | undefined): ResolvedAuth;
|
|
464
506
|
/** The role from a verified JWT payload, per the resolved policy. An unknown or
|
|
@@ -633,8 +675,8 @@ declare function sendTemplated(deps: NotifyDeps, input: NotifyInput): Promise<No
|
|
|
633
675
|
declare function emailGroupFrom(row: Record<string, unknown>): EmailGroup;
|
|
634
676
|
|
|
635
677
|
/**
|
|
636
|
-
* Apply defaults + validate the pipeline config. With no config, the
|
|
637
|
-
*
|
|
678
|
+
* Apply defaults + validate the pipeline config. With no config, the complete
|
|
679
|
+
* reference pipeline. With `stages` given but the subsets omitted, the subsets
|
|
638
680
|
* default to empty (a site opts in to bookable/approvable states explicitly).
|
|
639
681
|
* Throws at import on a bad pipeline (empty/duplicate stages, an initial or a
|
|
640
682
|
* subset entry not on the ladder).
|
|
@@ -678,8 +720,7 @@ declare function paymentsReady(group: PaymentsGroup, hasSecretKey: boolean): boo
|
|
|
678
720
|
* of nested objects into bracket syntax (`metadata[applicationId]=...`). */
|
|
679
721
|
declare function stripeForm(params: Record<string, unknown>): string;
|
|
680
722
|
/** The Stripe idempotency key for creating an application's subscription — one
|
|
681
|
-
* per application, so a client retry can't orphan a second subscription
|
|
682
|
-
* lacked this; the package enforces it). */
|
|
723
|
+
* per application, so a client retry can't orphan a second subscription. */
|
|
683
724
|
declare function subscriptionIdempotencyKey(applicationId: string): string;
|
|
684
725
|
/** The db mutationId for a webhook-driven write — exactly-once per Stripe event,
|
|
685
726
|
* so replays are deduped at the db layer. */
|
|
@@ -941,6 +982,22 @@ declare function bucketSeries(points: Array<{
|
|
|
941
982
|
weekStart: number;
|
|
942
983
|
value: number;
|
|
943
984
|
}>;
|
|
985
|
+
/** Labels and current/previous values for one dashboard comparison window. */
|
|
986
|
+
interface DashboardMetricSeries {
|
|
987
|
+
labels: string[];
|
|
988
|
+
current: number[];
|
|
989
|
+
previous: number[];
|
|
990
|
+
}
|
|
991
|
+
/** Week-over-week and month-over-month series consumed by MetricWidget. */
|
|
992
|
+
interface DashboardMetricData {
|
|
993
|
+
wow: DashboardMetricSeries;
|
|
994
|
+
mom: DashboardMetricSeries;
|
|
995
|
+
}
|
|
996
|
+
/** MetricWidget-ready daily and weekly comparison windows. */
|
|
997
|
+
declare function dashboardMetricData(points: Array<{
|
|
998
|
+
t: number;
|
|
999
|
+
v: number;
|
|
1000
|
+
}>, now: number): DashboardMetricData;
|
|
944
1001
|
/** Annualized cents for a Stripe subscription: sum each item's
|
|
945
1002
|
* `unit_amount * quantity`, ×12 for monthly intervals. A yearly interval is
|
|
946
1003
|
* taken as-is. Returns 0 for a shape with no priced items. */
|
|
@@ -1183,7 +1240,9 @@ declare function memberSession(user: SessionUser, opts: {
|
|
|
1183
1240
|
* theme. These are brand OVERRIDES on top of a base theme — they do not replace
|
|
1184
1241
|
* the theme layer the components need (see {@link brandTokens} usage in the docs).
|
|
1185
1242
|
*/
|
|
1186
|
-
declare function brandTokens(brand: ChapterBrand | undefined
|
|
1243
|
+
declare function brandTokens(brand: ChapterBrand | undefined, options?: {
|
|
1244
|
+
selector?: string;
|
|
1245
|
+
}): string;
|
|
1187
1246
|
|
|
1188
1247
|
/** A `meetings` row, as far as reconciliation cares. */
|
|
1189
1248
|
interface MeetingForReconcile {
|
|
@@ -1235,13 +1294,13 @@ interface ResolvedScheduling {
|
|
|
1235
1294
|
windowDays: number;
|
|
1236
1295
|
summaryTemplate: string;
|
|
1237
1296
|
}
|
|
1238
|
-
/**
|
|
1297
|
+
/** Proven defaults: 45-minute weekday slots, 9–5 Pacific, 24h notice,
|
|
1239
1298
|
* a 14-day window. The summary is generic (a chapter's group seed supplies a
|
|
1240
1299
|
* name-branded one). */
|
|
1241
1300
|
declare const SCHEDULING_DEFAULTS: ResolvedScheduling;
|
|
1242
1301
|
/**
|
|
1243
1302
|
* Resolve a group's scheduling config against the defaults, validating every
|
|
1244
|
-
* bound
|
|
1303
|
+
* bound at config-write time (throws on a bad config, so a
|
|
1245
1304
|
* misconfiguration surfaces immediately rather than yielding empty slots).
|
|
1246
1305
|
* `windowDays` is capped at 62 because Google FreeBusy is.
|
|
1247
1306
|
*/
|
|
@@ -1345,4 +1404,4 @@ type ApplicationBookingPatch = {
|
|
|
1345
1404
|
* already there (never backward). */
|
|
1346
1405
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1347
1406
|
|
|
1348
|
-
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 ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterScheduling, type ChapterSends, type ClerkInviteInput, type ClerkResult, type ClerkUserInput, type ClerkUserRecord, DEFAULT_SHARE_FIELDS, 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 LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedNetwork, 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 StripeEvent, type StripeResult, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, validateScheduling, verifyStripeSignature, webhookMutationId };
|
|
1407
|
+
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 ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterScheduling, type ChapterSends, type ClerkInviteInput, type ClerkResult, type ClerkUserInput, type ClerkUserRecord, 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 LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedNetwork, 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 StripeEvent, type StripeResult, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, validateScheduling, verifyStripeSignature, webhookMutationId };
|
package/dist/index.d.ts
CHANGED
|
@@ -53,8 +53,50 @@ interface Rule {
|
|
|
53
53
|
}
|
|
54
54
|
/** Namespace → rule set. */
|
|
55
55
|
type DbRules = Record<string, Rule>;
|
|
56
|
-
/**
|
|
56
|
+
/** Typed semantic roles shared by the public site and application surfaces. */
|
|
57
|
+
interface ChapterBrandTokens {
|
|
58
|
+
background?: string;
|
|
59
|
+
surface?: string;
|
|
60
|
+
surface2?: string;
|
|
61
|
+
text?: string;
|
|
62
|
+
textMuted?: string;
|
|
63
|
+
textFaint?: string;
|
|
64
|
+
border?: string;
|
|
65
|
+
borderStrong?: string;
|
|
66
|
+
accent?: string;
|
|
67
|
+
accentStrong?: string;
|
|
68
|
+
accentSoft?: string;
|
|
69
|
+
onAccent?: string;
|
|
70
|
+
good?: string;
|
|
71
|
+
warn?: string;
|
|
72
|
+
danger?: string;
|
|
73
|
+
chart1?: string;
|
|
74
|
+
chart2?: string;
|
|
75
|
+
chart3?: string;
|
|
76
|
+
chart4?: string;
|
|
77
|
+
chart5?: string;
|
|
78
|
+
chart6?: string;
|
|
79
|
+
chartPositive?: string;
|
|
80
|
+
chartNegative?: string;
|
|
81
|
+
/** Admin/application content width, e.g. `"960px"`. */
|
|
82
|
+
contentWidth?: string;
|
|
83
|
+
panelRadius?: string;
|
|
84
|
+
panelShadow?: string;
|
|
85
|
+
masterDetailColumns?: string;
|
|
86
|
+
masterDetailMinHeight?: string;
|
|
87
|
+
/** Chapter-admin page padding shorthand. */
|
|
88
|
+
pagePadding?: string;
|
|
89
|
+
/** Chapter-admin workspace-tab padding shorthand. */
|
|
90
|
+
workspacePadding?: string;
|
|
91
|
+
}
|
|
92
|
+
/** Brand tokens that theme the site: theme, semantic roles, fonts, and logos. */
|
|
57
93
|
interface ChapterBrand {
|
|
94
|
+
/** Preloaded @odla-ai/ui theme name used by ThemeScope. */
|
|
95
|
+
theme?: string;
|
|
96
|
+
/** Admin/application color mode. Explicit light is the safe default. */
|
|
97
|
+
colorScheme?: "light" | "dark" | "system";
|
|
98
|
+
tokens?: ChapterBrandTokens;
|
|
99
|
+
tokensDark?: ChapterBrandTokens;
|
|
58
100
|
/** Palette overrides written into styles.css :root (e.g. `{ moss: "#2F3E34" }`
|
|
59
101
|
* or `--ui-*` token names). Applies in BOTH light and dark unless overridden
|
|
60
102
|
* by {@link paletteDark}. */
|
|
@@ -88,7 +130,7 @@ interface ChapterNetworkTarget {
|
|
|
88
130
|
id: string;
|
|
89
131
|
/** Human-facing site name. Defaults to `id`. */
|
|
90
132
|
name?: string;
|
|
91
|
-
/** Absolute follower origin, e.g. `https://
|
|
133
|
+
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
92
134
|
url: string;
|
|
93
135
|
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
94
136
|
* `network_share_<id-with-underscores>`. */
|
|
@@ -159,10 +201,10 @@ interface ChapterScheduling {
|
|
|
159
201
|
}
|
|
160
202
|
/** How a signed-in user's role is determined.
|
|
161
203
|
*
|
|
162
|
-
* - `"claim"` reads a role ladder from a JWT claim (
|
|
204
|
+
* - `"claim"` reads a role ladder from a JWT claim (the member-site model:
|
|
163
205
|
* `provisional → member → admin`). Admin is the last (highest) rung; the
|
|
164
206
|
* read-only `superAdmins` tier sits above it.
|
|
165
|
-
* - `"table"` gates on the deny-all `admins` allowlist (
|
|
207
|
+
* - `"table"` gates on the deny-all `admins` allowlist (the hub model):
|
|
166
208
|
* a binary "email is an admin or isn't", set only in odla Studio.
|
|
167
209
|
*
|
|
168
210
|
* Defaults: `"claim"` in `chapter` mode, `"table"` in `hub` mode. */
|
|
@@ -189,7 +231,7 @@ interface ResolvedAuth {
|
|
|
189
231
|
}
|
|
190
232
|
/** The application status pipeline. Which statuses exist, and the subsets a site
|
|
191
233
|
* allows a call to be booked from / an application approved from. Defaults to
|
|
192
|
-
*
|
|
234
|
+
* the reference pipeline. Status never moves backwards (package-enforced). */
|
|
193
235
|
interface ChapterPipeline {
|
|
194
236
|
stages?: readonly string[];
|
|
195
237
|
bookableFrom?: readonly string[];
|
|
@@ -206,8 +248,8 @@ interface ResolvedPipeline {
|
|
|
206
248
|
}
|
|
207
249
|
/** The application (join form) validation surface — which string fields are
|
|
208
250
|
* required vs accepted, their max lengths, and the request body cap. Drives
|
|
209
|
-
* submit validation + the CRM slot projection; defaults to
|
|
210
|
-
* The `applications` schema attrs stay fixed
|
|
251
|
+
* submit validation + the CRM slot projection; defaults to the reference form.
|
|
252
|
+
* The `applications` schema attrs stay fixed; this is
|
|
211
253
|
* validation config, not schema generation. */
|
|
212
254
|
interface ChapterApplication {
|
|
213
255
|
required?: readonly string[];
|
|
@@ -279,7 +321,7 @@ interface ChapterConfig {
|
|
|
279
321
|
/** `notificationEmail` required in `chapter` mode. */
|
|
280
322
|
emails?: ChapterEmails;
|
|
281
323
|
scheduling?: ChapterScheduling;
|
|
282
|
-
/** Application status pipeline (stages + bookable/approvable subsets).
|
|
324
|
+
/** Application status pipeline (stages + bookable/approvable subsets). */
|
|
283
325
|
pipeline?: ChapterPipeline;
|
|
284
326
|
/** Join-form validation (required/optional fields, max lengths, body cap). */
|
|
285
327
|
application?: ChapterApplication;
|
|
@@ -439,7 +481,7 @@ declare function createChapterIntegration(chapter: Chapter, options?: ChapterInt
|
|
|
439
481
|
* `chapter` mode only. The auth tables follow {@link ResolvedAuth}: `source:
|
|
440
482
|
* "table"` adds the `admins` allowlist (hub/BNF); `superAdmins` adds the
|
|
441
483
|
* read-only super-admin tier (default on for the `"claim"` ladder). A `"claim"`
|
|
442
|
-
* chapter therefore emits
|
|
484
|
+
* chapter therefore emits the reference namespace set — `applications`,
|
|
443
485
|
* `groups`, `meetings`, `emailLog`, `superAdmins` — with no `admins` table. */
|
|
444
486
|
declare function chapterDb(mode: ChapterMode, auth: ResolvedAuth): {
|
|
445
487
|
schema: DbSchema;
|
|
@@ -457,8 +499,8 @@ declare function buildGroupSeed(config: ChapterConfig): Record<string, unknown>;
|
|
|
457
499
|
/**
|
|
458
500
|
* Apply defaults + validate the auth config into a {@link ResolvedAuth}. Defaults
|
|
459
501
|
* by mode: `chapter` → the `provisional/member/admin` claim ladder with the
|
|
460
|
-
* `superAdmins` tier
|
|
461
|
-
*
|
|
502
|
+
* `superAdmins` tier; `hub` → the `admins` allowlist table with no super tier.
|
|
503
|
+
* Throws at import on a bad policy.
|
|
462
504
|
*/
|
|
463
505
|
declare function resolveAuth(mode: ChapterMode, auth: ChapterAuth | undefined): ResolvedAuth;
|
|
464
506
|
/** The role from a verified JWT payload, per the resolved policy. An unknown or
|
|
@@ -633,8 +675,8 @@ declare function sendTemplated(deps: NotifyDeps, input: NotifyInput): Promise<No
|
|
|
633
675
|
declare function emailGroupFrom(row: Record<string, unknown>): EmailGroup;
|
|
634
676
|
|
|
635
677
|
/**
|
|
636
|
-
* Apply defaults + validate the pipeline config. With no config, the
|
|
637
|
-
*
|
|
678
|
+
* Apply defaults + validate the pipeline config. With no config, the complete
|
|
679
|
+
* reference pipeline. With `stages` given but the subsets omitted, the subsets
|
|
638
680
|
* default to empty (a site opts in to bookable/approvable states explicitly).
|
|
639
681
|
* Throws at import on a bad pipeline (empty/duplicate stages, an initial or a
|
|
640
682
|
* subset entry not on the ladder).
|
|
@@ -678,8 +720,7 @@ declare function paymentsReady(group: PaymentsGroup, hasSecretKey: boolean): boo
|
|
|
678
720
|
* of nested objects into bracket syntax (`metadata[applicationId]=...`). */
|
|
679
721
|
declare function stripeForm(params: Record<string, unknown>): string;
|
|
680
722
|
/** The Stripe idempotency key for creating an application's subscription — one
|
|
681
|
-
* per application, so a client retry can't orphan a second subscription
|
|
682
|
-
* lacked this; the package enforces it). */
|
|
723
|
+
* per application, so a client retry can't orphan a second subscription. */
|
|
683
724
|
declare function subscriptionIdempotencyKey(applicationId: string): string;
|
|
684
725
|
/** The db mutationId for a webhook-driven write — exactly-once per Stripe event,
|
|
685
726
|
* so replays are deduped at the db layer. */
|
|
@@ -941,6 +982,22 @@ declare function bucketSeries(points: Array<{
|
|
|
941
982
|
weekStart: number;
|
|
942
983
|
value: number;
|
|
943
984
|
}>;
|
|
985
|
+
/** Labels and current/previous values for one dashboard comparison window. */
|
|
986
|
+
interface DashboardMetricSeries {
|
|
987
|
+
labels: string[];
|
|
988
|
+
current: number[];
|
|
989
|
+
previous: number[];
|
|
990
|
+
}
|
|
991
|
+
/** Week-over-week and month-over-month series consumed by MetricWidget. */
|
|
992
|
+
interface DashboardMetricData {
|
|
993
|
+
wow: DashboardMetricSeries;
|
|
994
|
+
mom: DashboardMetricSeries;
|
|
995
|
+
}
|
|
996
|
+
/** MetricWidget-ready daily and weekly comparison windows. */
|
|
997
|
+
declare function dashboardMetricData(points: Array<{
|
|
998
|
+
t: number;
|
|
999
|
+
v: number;
|
|
1000
|
+
}>, now: number): DashboardMetricData;
|
|
944
1001
|
/** Annualized cents for a Stripe subscription: sum each item's
|
|
945
1002
|
* `unit_amount * quantity`, ×12 for monthly intervals. A yearly interval is
|
|
946
1003
|
* taken as-is. Returns 0 for a shape with no priced items. */
|
|
@@ -1183,7 +1240,9 @@ declare function memberSession(user: SessionUser, opts: {
|
|
|
1183
1240
|
* theme. These are brand OVERRIDES on top of a base theme — they do not replace
|
|
1184
1241
|
* the theme layer the components need (see {@link brandTokens} usage in the docs).
|
|
1185
1242
|
*/
|
|
1186
|
-
declare function brandTokens(brand: ChapterBrand | undefined
|
|
1243
|
+
declare function brandTokens(brand: ChapterBrand | undefined, options?: {
|
|
1244
|
+
selector?: string;
|
|
1245
|
+
}): string;
|
|
1187
1246
|
|
|
1188
1247
|
/** A `meetings` row, as far as reconciliation cares. */
|
|
1189
1248
|
interface MeetingForReconcile {
|
|
@@ -1235,13 +1294,13 @@ interface ResolvedScheduling {
|
|
|
1235
1294
|
windowDays: number;
|
|
1236
1295
|
summaryTemplate: string;
|
|
1237
1296
|
}
|
|
1238
|
-
/**
|
|
1297
|
+
/** Proven defaults: 45-minute weekday slots, 9–5 Pacific, 24h notice,
|
|
1239
1298
|
* a 14-day window. The summary is generic (a chapter's group seed supplies a
|
|
1240
1299
|
* name-branded one). */
|
|
1241
1300
|
declare const SCHEDULING_DEFAULTS: ResolvedScheduling;
|
|
1242
1301
|
/**
|
|
1243
1302
|
* Resolve a group's scheduling config against the defaults, validating every
|
|
1244
|
-
* bound
|
|
1303
|
+
* bound at config-write time (throws on a bad config, so a
|
|
1245
1304
|
* misconfiguration surfaces immediately rather than yielding empty slots).
|
|
1246
1305
|
* `windowDays` is capped at 62 because Google FreeBusy is.
|
|
1247
1306
|
*/
|
|
@@ -1345,4 +1404,4 @@ type ApplicationBookingPatch = {
|
|
|
1345
1404
|
* already there (never backward). */
|
|
1346
1405
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1347
1406
|
|
|
1348
|
-
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 ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterScheduling, type ChapterSends, type ClerkInviteInput, type ClerkResult, type ClerkUserInput, type ClerkUserRecord, DEFAULT_SHARE_FIELDS, 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 LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedNetwork, 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 StripeEvent, type StripeResult, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, validateScheduling, verifyStripeSignature, webhookMutationId };
|
|
1407
|
+
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 ChapterDb, type ChapterEmails, type ChapterIntegrationDescriptor, type ChapterIntegrationOptions, type ChapterMode, type ChapterNetwork, type ChapterNetworkTarget, type ChapterOperations, type ChapterPipeline, type ChapterPolicy, type ChapterPrices, type ChapterScheduling, type ChapterSends, type ClerkInviteInput, type ClerkResult, type ClerkUserInput, type ClerkUserRecord, 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 LiveEvent, type MailSender, type MeetingForReconcile, type MeetingRecord, type MeetingReschedulePatch, type MemberApplication, type MemberSession, type NewMeetingRow, type NotifyDeps, type NotifyInput, type NotifyResult, type PaymentsGroup, type ProjectionDeps, type ReconcileDecision, type ResolvedApplication, type ResolvedAuth, type ResolvedNetwork, 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 StripeEvent, type StripeResult, type SubmitResult, type WebhookEvent, applicantProfile, applicationBookingUpdate, applicationSummary, backfillCrm, bookingDecision, brandTokens, bucketSeries, buildGroupSeed, canApprove, canBook, canChangeRole, canTransition, canceledPatch, chapterDb, clampArray, clerkGetUser, clerkGetUserByEmail, clerkIntegration, clerkInviteRequest, clerkListUsers, clerkSetRole, clerkUserRequest, createChapterIntegration, createClerkInvitation, createClerkUser, dashboardMetricData, defaultCrm, defineChapter, emailGroupFrom, endForSlot, findApplicationRef, firstPaymentPatch, getVaultSecret, hasDisclaimerAck, introIdempotencyKey, isAdminRole, isAlreadySent, isReconcilable, isSlotAvailable, isValidEmail, joinConfig, meetingCreateRow, meetingRescheduleUpdate, memberApplication, memberSession, networkSourceTag, normalizeSharedRecord, normalizeWebhookEvent, paymentsReady, personInputFromApp, planDelivery, projectApplicant, projectSharedRecord, reconcileMeetings, refundedPatch, render, renderSummary, renderTemplateBody, renewalPatch, resolveApplication, resolveAuth, resolvePipeline, resolveScheduling, roleFromClaim, sendTemplated, sharedPersonInput, sharedRecordFromCrm, slotWindow, stageIndex, stripeCall, stripeForm, subAnnualCents, submitApplication, subscriptionIdempotencyKey, syncApplicationToCrm, validateScheduling, verifyStripeSignature, webhookMutationId };
|
package/dist/index.js
CHANGED
|
@@ -1111,6 +1111,31 @@ function bucketSeries(points, now, weeks = 12) {
|
|
|
1111
1111
|
}
|
|
1112
1112
|
return buckets;
|
|
1113
1113
|
}
|
|
1114
|
+
function periodSeries(points, now, count, periodMs) {
|
|
1115
|
+
const start = now - count * periodMs;
|
|
1116
|
+
const previousStart = start - count * periodMs;
|
|
1117
|
+
const current = Array.from({ length: count }, () => 0);
|
|
1118
|
+
const previous = Array.from({ length: count }, () => 0);
|
|
1119
|
+
for (const point of points) {
|
|
1120
|
+
if (!Number.isFinite(point.t) || !Number.isFinite(point.v)) continue;
|
|
1121
|
+
if (point.t >= start && point.t <= now) {
|
|
1122
|
+
const index = Math.min(count - 1, Math.floor((point.t - start) / periodMs));
|
|
1123
|
+
current[index] = (current[index] ?? 0) + point.v;
|
|
1124
|
+
} else if (point.t >= previousStart && point.t < start) {
|
|
1125
|
+
const index = Math.min(count - 1, Math.floor((point.t - previousStart) / periodMs));
|
|
1126
|
+
previous[index] = (previous[index] ?? 0) + point.v;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
const labels = current.map((_, index) => new Date(start + index * periodMs).toISOString().slice(5, 10));
|
|
1130
|
+
return { labels, current, previous };
|
|
1131
|
+
}
|
|
1132
|
+
function dashboardMetricData(points, now) {
|
|
1133
|
+
const DAY = 864e5;
|
|
1134
|
+
return {
|
|
1135
|
+
wow: periodSeries(points, now, 7, DAY),
|
|
1136
|
+
mom: periodSeries(points, now, 4, 7 * DAY)
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1114
1139
|
function subAnnualCents(sub) {
|
|
1115
1140
|
const items = sub.items?.data ?? [];
|
|
1116
1141
|
let cents = 0;
|
|
@@ -1367,15 +1392,55 @@ function paletteDecls(palette) {
|
|
|
1367
1392
|
}
|
|
1368
1393
|
return decls;
|
|
1369
1394
|
}
|
|
1370
|
-
|
|
1395
|
+
var TOKEN_VARS = {
|
|
1396
|
+
background: "--ui-bg",
|
|
1397
|
+
surface: "--ui-surface",
|
|
1398
|
+
surface2: "--ui-surface-2",
|
|
1399
|
+
text: "--ui-text",
|
|
1400
|
+
textMuted: "--ui-text-muted",
|
|
1401
|
+
textFaint: "--ui-text-faint",
|
|
1402
|
+
border: "--ui-border",
|
|
1403
|
+
borderStrong: "--ui-border-strong",
|
|
1404
|
+
accent: "--ui-accent",
|
|
1405
|
+
accentStrong: "--ui-accent-strong",
|
|
1406
|
+
accentSoft: "--ui-accent-soft",
|
|
1407
|
+
onAccent: "--ui-on-accent",
|
|
1408
|
+
good: "--ui-good",
|
|
1409
|
+
warn: "--ui-warn",
|
|
1410
|
+
danger: "--ui-danger",
|
|
1411
|
+
chart1: "--ui-chart-1",
|
|
1412
|
+
chart2: "--ui-chart-2",
|
|
1413
|
+
chart3: "--ui-chart-3",
|
|
1414
|
+
chart4: "--ui-chart-4",
|
|
1415
|
+
chart5: "--ui-chart-5",
|
|
1416
|
+
chart6: "--ui-chart-6",
|
|
1417
|
+
chartPositive: "--ui-chart-pos",
|
|
1418
|
+
chartNegative: "--ui-chart-neg",
|
|
1419
|
+
contentWidth: "--ui-content-width",
|
|
1420
|
+
panelRadius: "--ui-radius-lg",
|
|
1421
|
+
panelShadow: "--ui-shadow",
|
|
1422
|
+
masterDetailColumns: "--ui-master-detail-columns",
|
|
1423
|
+
masterDetailMinHeight: "--ui-master-detail-min-height",
|
|
1424
|
+
pagePadding: "--chapter-admin-page-padding",
|
|
1425
|
+
workspacePadding: "--chapter-admin-workspace-padding"
|
|
1426
|
+
};
|
|
1427
|
+
function semanticDecls(tokens) {
|
|
1428
|
+
return Object.entries(tokens ?? {}).flatMap(
|
|
1429
|
+
([key, value]) => typeof value === "string" && value.trim() ? [`${TOKEN_VARS[key]}: ${cleanValue(value)};`] : []
|
|
1430
|
+
);
|
|
1431
|
+
}
|
|
1432
|
+
function brandTokens(brand, options = {}) {
|
|
1371
1433
|
if (!brand) return "";
|
|
1372
|
-
const light = paletteDecls(brand.palette);
|
|
1434
|
+
const light = [...paletteDecls(brand.palette), ...semanticDecls(brand.tokens)];
|
|
1373
1435
|
const fonts = brand.fonts;
|
|
1374
1436
|
if (fonts?.display) light.push(`--ui-font-display: ${cleanValue(fonts.display)};`);
|
|
1375
1437
|
if (fonts?.body) light.push(`--ui-font-sans: ${cleanValue(fonts.body)};`);
|
|
1376
1438
|
if (fonts?.numeral) light.push(`--ui-font-numeral: ${cleanValue(fonts.numeral)};`);
|
|
1377
|
-
const dark = paletteDecls(brand.paletteDark);
|
|
1378
|
-
|
|
1439
|
+
const dark = [...paletteDecls(brand.paletteDark), ...semanticDecls(brand.tokensDark)];
|
|
1440
|
+
const selector = options.selector ?? ":root";
|
|
1441
|
+
const darkSelector = selector === ":root" ? ':root[data-theme="dark"]' : `${selector}[data-theme="dark"]`;
|
|
1442
|
+
const systemSelector = selector === ":root" ? ':root:not([data-theme="light"])' : `${selector}:not([data-theme="light"])`;
|
|
1443
|
+
let css = light.length ? `${selector} {
|
|
1379
1444
|
${light.join("\n ")}
|
|
1380
1445
|
}
|
|
1381
1446
|
` : "";
|
|
@@ -1383,9 +1448,9 @@ function brandTokens(brand) {
|
|
|
1383
1448
|
const block = `{
|
|
1384
1449
|
${dark.join("\n ")}
|
|
1385
1450
|
}`;
|
|
1386
|
-
css +=
|
|
1451
|
+
css += `${darkSelector} ${block}
|
|
1387
1452
|
@media (prefers-color-scheme: dark) {
|
|
1388
|
-
|
|
1453
|
+
${systemSelector} ${block}
|
|
1389
1454
|
}
|
|
1390
1455
|
`;
|
|
1391
1456
|
}
|
|
@@ -1558,6 +1623,7 @@ export {
|
|
|
1558
1623
|
createChapterIntegration,
|
|
1559
1624
|
createClerkInvitation,
|
|
1560
1625
|
createClerkUser,
|
|
1626
|
+
dashboardMetricData,
|
|
1561
1627
|
defaultCrm,
|
|
1562
1628
|
defineChapter,
|
|
1563
1629
|
emailGroupFrom,
|