@odla-ai/chapter 0.20.2 → 0.21.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 +78 -32
- package/dist/chunk-3JG5X2LT.js +80 -0
- package/dist/chunk-3JG5X2LT.js.map +1 -0
- package/dist/chunk-AOTWFOH4.js +1481 -0
- package/dist/chunk-AOTWFOH4.js.map +1 -0
- package/dist/{chunk-LME2IHY5.js → chunk-ILGUJXSB.js} +1 -1
- package/dist/chunk-ILGUJXSB.js.map +1 -0
- package/dist/index.cjs +61 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -19
- package/dist/index.d.ts +64 -19
- package/dist/index.js +61 -6
- package/dist/index.js.map +1 -1
- package/dist/{types-D2fGiNG8.d.ts → types-CXDiDj_s.d.ts} +36 -8
- package/dist/ui/admin/index.d.ts +85 -84
- package/dist/ui/admin/index.js +8 -2
- package/dist/ui/index.d.ts +3 -2
- package/dist/ui/index.js +9 -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 +36 -8
- package/dist/worker/index.d.ts +36 -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 +13 -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,36 @@ 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
|
+
chartPositive?: string;
|
|
76
|
+
chartNegative?: string;
|
|
77
|
+
}
|
|
78
|
+
/** Brand tokens that theme the site: theme, semantic roles, fonts, and logos. */
|
|
57
79
|
interface ChapterBrand {
|
|
80
|
+
/** Preloaded @odla-ai/ui theme name used by ThemeScope. */
|
|
81
|
+
theme?: string;
|
|
82
|
+
/** Admin/application color mode. Explicit light is the safe default. */
|
|
83
|
+
colorScheme?: "light" | "dark" | "system";
|
|
84
|
+
tokens?: ChapterBrandTokens;
|
|
85
|
+
tokensDark?: ChapterBrandTokens;
|
|
58
86
|
/** Palette overrides written into styles.css :root (e.g. `{ moss: "#2F3E34" }`
|
|
59
87
|
* or `--ui-*` token names). Applies in BOTH light and dark unless overridden
|
|
60
88
|
* by {@link paletteDark}. */
|
|
@@ -88,7 +116,7 @@ interface ChapterNetworkTarget {
|
|
|
88
116
|
id: string;
|
|
89
117
|
/** Human-facing site name. Defaults to `id`. */
|
|
90
118
|
name?: string;
|
|
91
|
-
/** Absolute follower origin, e.g. `https://
|
|
119
|
+
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
92
120
|
url: string;
|
|
93
121
|
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
94
122
|
* `network_share_<id-with-underscores>`. */
|
|
@@ -159,10 +187,10 @@ interface ChapterScheduling {
|
|
|
159
187
|
}
|
|
160
188
|
/** How a signed-in user's role is determined.
|
|
161
189
|
*
|
|
162
|
-
* - `"claim"` reads a role ladder from a JWT claim (
|
|
190
|
+
* - `"claim"` reads a role ladder from a JWT claim (the member-site model:
|
|
163
191
|
* `provisional → member → admin`). Admin is the last (highest) rung; the
|
|
164
192
|
* read-only `superAdmins` tier sits above it.
|
|
165
|
-
* - `"table"` gates on the deny-all `admins` allowlist (
|
|
193
|
+
* - `"table"` gates on the deny-all `admins` allowlist (the hub model):
|
|
166
194
|
* a binary "email is an admin or isn't", set only in odla Studio.
|
|
167
195
|
*
|
|
168
196
|
* Defaults: `"claim"` in `chapter` mode, `"table"` in `hub` mode. */
|
|
@@ -189,7 +217,7 @@ interface ResolvedAuth {
|
|
|
189
217
|
}
|
|
190
218
|
/** The application status pipeline. Which statuses exist, and the subsets a site
|
|
191
219
|
* allows a call to be booked from / an application approved from. Defaults to
|
|
192
|
-
*
|
|
220
|
+
* the reference pipeline. Status never moves backwards (package-enforced). */
|
|
193
221
|
interface ChapterPipeline {
|
|
194
222
|
stages?: readonly string[];
|
|
195
223
|
bookableFrom?: readonly string[];
|
|
@@ -206,8 +234,8 @@ interface ResolvedPipeline {
|
|
|
206
234
|
}
|
|
207
235
|
/** The application (join form) validation surface — which string fields are
|
|
208
236
|
* 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
|
|
237
|
+
* submit validation + the CRM slot projection; defaults to the reference form.
|
|
238
|
+
* The `applications` schema attrs stay fixed; this is
|
|
211
239
|
* validation config, not schema generation. */
|
|
212
240
|
interface ChapterApplication {
|
|
213
241
|
required?: readonly string[];
|
|
@@ -279,7 +307,7 @@ interface ChapterConfig {
|
|
|
279
307
|
/** `notificationEmail` required in `chapter` mode. */
|
|
280
308
|
emails?: ChapterEmails;
|
|
281
309
|
scheduling?: ChapterScheduling;
|
|
282
|
-
/** Application status pipeline (stages + bookable/approvable subsets).
|
|
310
|
+
/** Application status pipeline (stages + bookable/approvable subsets). */
|
|
283
311
|
pipeline?: ChapterPipeline;
|
|
284
312
|
/** Join-form validation (required/optional fields, max lengths, body cap). */
|
|
285
313
|
application?: ChapterApplication;
|
|
@@ -439,7 +467,7 @@ declare function createChapterIntegration(chapter: Chapter, options?: ChapterInt
|
|
|
439
467
|
* `chapter` mode only. The auth tables follow {@link ResolvedAuth}: `source:
|
|
440
468
|
* "table"` adds the `admins` allowlist (hub/BNF); `superAdmins` adds the
|
|
441
469
|
* read-only super-admin tier (default on for the `"claim"` ladder). A `"claim"`
|
|
442
|
-
* chapter therefore emits
|
|
470
|
+
* chapter therefore emits the reference namespace set — `applications`,
|
|
443
471
|
* `groups`, `meetings`, `emailLog`, `superAdmins` — with no `admins` table. */
|
|
444
472
|
declare function chapterDb(mode: ChapterMode, auth: ResolvedAuth): {
|
|
445
473
|
schema: DbSchema;
|
|
@@ -457,8 +485,8 @@ declare function buildGroupSeed(config: ChapterConfig): Record<string, unknown>;
|
|
|
457
485
|
/**
|
|
458
486
|
* Apply defaults + validate the auth config into a {@link ResolvedAuth}. Defaults
|
|
459
487
|
* by mode: `chapter` → the `provisional/member/admin` claim ladder with the
|
|
460
|
-
* `superAdmins` tier
|
|
461
|
-
*
|
|
488
|
+
* `superAdmins` tier; `hub` → the `admins` allowlist table with no super tier.
|
|
489
|
+
* Throws at import on a bad policy.
|
|
462
490
|
*/
|
|
463
491
|
declare function resolveAuth(mode: ChapterMode, auth: ChapterAuth | undefined): ResolvedAuth;
|
|
464
492
|
/** The role from a verified JWT payload, per the resolved policy. An unknown or
|
|
@@ -633,8 +661,8 @@ declare function sendTemplated(deps: NotifyDeps, input: NotifyInput): Promise<No
|
|
|
633
661
|
declare function emailGroupFrom(row: Record<string, unknown>): EmailGroup;
|
|
634
662
|
|
|
635
663
|
/**
|
|
636
|
-
* Apply defaults + validate the pipeline config. With no config, the
|
|
637
|
-
*
|
|
664
|
+
* Apply defaults + validate the pipeline config. With no config, the complete
|
|
665
|
+
* reference pipeline. With `stages` given but the subsets omitted, the subsets
|
|
638
666
|
* default to empty (a site opts in to bookable/approvable states explicitly).
|
|
639
667
|
* Throws at import on a bad pipeline (empty/duplicate stages, an initial or a
|
|
640
668
|
* subset entry not on the ladder).
|
|
@@ -678,8 +706,7 @@ declare function paymentsReady(group: PaymentsGroup, hasSecretKey: boolean): boo
|
|
|
678
706
|
* of nested objects into bracket syntax (`metadata[applicationId]=...`). */
|
|
679
707
|
declare function stripeForm(params: Record<string, unknown>): string;
|
|
680
708
|
/** 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). */
|
|
709
|
+
* per application, so a client retry can't orphan a second subscription. */
|
|
683
710
|
declare function subscriptionIdempotencyKey(applicationId: string): string;
|
|
684
711
|
/** The db mutationId for a webhook-driven write — exactly-once per Stripe event,
|
|
685
712
|
* so replays are deduped at the db layer. */
|
|
@@ -941,6 +968,22 @@ declare function bucketSeries(points: Array<{
|
|
|
941
968
|
weekStart: number;
|
|
942
969
|
value: number;
|
|
943
970
|
}>;
|
|
971
|
+
/** Labels and current/previous values for one dashboard comparison window. */
|
|
972
|
+
interface DashboardMetricSeries {
|
|
973
|
+
labels: string[];
|
|
974
|
+
current: number[];
|
|
975
|
+
previous: number[];
|
|
976
|
+
}
|
|
977
|
+
/** Week-over-week and month-over-month series consumed by MetricWidget. */
|
|
978
|
+
interface DashboardMetricData {
|
|
979
|
+
wow: DashboardMetricSeries;
|
|
980
|
+
mom: DashboardMetricSeries;
|
|
981
|
+
}
|
|
982
|
+
/** MetricWidget-ready daily and weekly comparison windows. */
|
|
983
|
+
declare function dashboardMetricData(points: Array<{
|
|
984
|
+
t: number;
|
|
985
|
+
v: number;
|
|
986
|
+
}>, now: number): DashboardMetricData;
|
|
944
987
|
/** Annualized cents for a Stripe subscription: sum each item's
|
|
945
988
|
* `unit_amount * quantity`, ×12 for monthly intervals. A yearly interval is
|
|
946
989
|
* taken as-is. Returns 0 for a shape with no priced items. */
|
|
@@ -1183,7 +1226,9 @@ declare function memberSession(user: SessionUser, opts: {
|
|
|
1183
1226
|
* theme. These are brand OVERRIDES on top of a base theme — they do not replace
|
|
1184
1227
|
* the theme layer the components need (see {@link brandTokens} usage in the docs).
|
|
1185
1228
|
*/
|
|
1186
|
-
declare function brandTokens(brand: ChapterBrand | undefined
|
|
1229
|
+
declare function brandTokens(brand: ChapterBrand | undefined, options?: {
|
|
1230
|
+
selector?: string;
|
|
1231
|
+
}): string;
|
|
1187
1232
|
|
|
1188
1233
|
/** A `meetings` row, as far as reconciliation cares. */
|
|
1189
1234
|
interface MeetingForReconcile {
|
|
@@ -1235,13 +1280,13 @@ interface ResolvedScheduling {
|
|
|
1235
1280
|
windowDays: number;
|
|
1236
1281
|
summaryTemplate: string;
|
|
1237
1282
|
}
|
|
1238
|
-
/**
|
|
1283
|
+
/** Proven defaults: 45-minute weekday slots, 9–5 Pacific, 24h notice,
|
|
1239
1284
|
* a 14-day window. The summary is generic (a chapter's group seed supplies a
|
|
1240
1285
|
* name-branded one). */
|
|
1241
1286
|
declare const SCHEDULING_DEFAULTS: ResolvedScheduling;
|
|
1242
1287
|
/**
|
|
1243
1288
|
* Resolve a group's scheduling config against the defaults, validating every
|
|
1244
|
-
* bound
|
|
1289
|
+
* bound at config-write time (throws on a bad config, so a
|
|
1245
1290
|
* misconfiguration surfaces immediately rather than yielding empty slots).
|
|
1246
1291
|
* `windowDays` is capped at 62 because Google FreeBusy is.
|
|
1247
1292
|
*/
|
|
@@ -1345,4 +1390,4 @@ type ApplicationBookingPatch = {
|
|
|
1345
1390
|
* already there (never backward). */
|
|
1346
1391
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1347
1392
|
|
|
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 };
|
|
1393
|
+
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,36 @@ 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
|
+
chartPositive?: string;
|
|
76
|
+
chartNegative?: string;
|
|
77
|
+
}
|
|
78
|
+
/** Brand tokens that theme the site: theme, semantic roles, fonts, and logos. */
|
|
57
79
|
interface ChapterBrand {
|
|
80
|
+
/** Preloaded @odla-ai/ui theme name used by ThemeScope. */
|
|
81
|
+
theme?: string;
|
|
82
|
+
/** Admin/application color mode. Explicit light is the safe default. */
|
|
83
|
+
colorScheme?: "light" | "dark" | "system";
|
|
84
|
+
tokens?: ChapterBrandTokens;
|
|
85
|
+
tokensDark?: ChapterBrandTokens;
|
|
58
86
|
/** Palette overrides written into styles.css :root (e.g. `{ moss: "#2F3E34" }`
|
|
59
87
|
* or `--ui-*` token names). Applies in BOTH light and dark unless overridden
|
|
60
88
|
* by {@link paletteDark}. */
|
|
@@ -88,7 +116,7 @@ interface ChapterNetworkTarget {
|
|
|
88
116
|
id: string;
|
|
89
117
|
/** Human-facing site name. Defaults to `id`. */
|
|
90
118
|
name?: string;
|
|
91
|
-
/** Absolute follower origin, e.g. `https://
|
|
119
|
+
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
92
120
|
url: string;
|
|
93
121
|
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
94
122
|
* `network_share_<id-with-underscores>`. */
|
|
@@ -159,10 +187,10 @@ interface ChapterScheduling {
|
|
|
159
187
|
}
|
|
160
188
|
/** How a signed-in user's role is determined.
|
|
161
189
|
*
|
|
162
|
-
* - `"claim"` reads a role ladder from a JWT claim (
|
|
190
|
+
* - `"claim"` reads a role ladder from a JWT claim (the member-site model:
|
|
163
191
|
* `provisional → member → admin`). Admin is the last (highest) rung; the
|
|
164
192
|
* read-only `superAdmins` tier sits above it.
|
|
165
|
-
* - `"table"` gates on the deny-all `admins` allowlist (
|
|
193
|
+
* - `"table"` gates on the deny-all `admins` allowlist (the hub model):
|
|
166
194
|
* a binary "email is an admin or isn't", set only in odla Studio.
|
|
167
195
|
*
|
|
168
196
|
* Defaults: `"claim"` in `chapter` mode, `"table"` in `hub` mode. */
|
|
@@ -189,7 +217,7 @@ interface ResolvedAuth {
|
|
|
189
217
|
}
|
|
190
218
|
/** The application status pipeline. Which statuses exist, and the subsets a site
|
|
191
219
|
* allows a call to be booked from / an application approved from. Defaults to
|
|
192
|
-
*
|
|
220
|
+
* the reference pipeline. Status never moves backwards (package-enforced). */
|
|
193
221
|
interface ChapterPipeline {
|
|
194
222
|
stages?: readonly string[];
|
|
195
223
|
bookableFrom?: readonly string[];
|
|
@@ -206,8 +234,8 @@ interface ResolvedPipeline {
|
|
|
206
234
|
}
|
|
207
235
|
/** The application (join form) validation surface — which string fields are
|
|
208
236
|
* 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
|
|
237
|
+
* submit validation + the CRM slot projection; defaults to the reference form.
|
|
238
|
+
* The `applications` schema attrs stay fixed; this is
|
|
211
239
|
* validation config, not schema generation. */
|
|
212
240
|
interface ChapterApplication {
|
|
213
241
|
required?: readonly string[];
|
|
@@ -279,7 +307,7 @@ interface ChapterConfig {
|
|
|
279
307
|
/** `notificationEmail` required in `chapter` mode. */
|
|
280
308
|
emails?: ChapterEmails;
|
|
281
309
|
scheduling?: ChapterScheduling;
|
|
282
|
-
/** Application status pipeline (stages + bookable/approvable subsets).
|
|
310
|
+
/** Application status pipeline (stages + bookable/approvable subsets). */
|
|
283
311
|
pipeline?: ChapterPipeline;
|
|
284
312
|
/** Join-form validation (required/optional fields, max lengths, body cap). */
|
|
285
313
|
application?: ChapterApplication;
|
|
@@ -439,7 +467,7 @@ declare function createChapterIntegration(chapter: Chapter, options?: ChapterInt
|
|
|
439
467
|
* `chapter` mode only. The auth tables follow {@link ResolvedAuth}: `source:
|
|
440
468
|
* "table"` adds the `admins` allowlist (hub/BNF); `superAdmins` adds the
|
|
441
469
|
* read-only super-admin tier (default on for the `"claim"` ladder). A `"claim"`
|
|
442
|
-
* chapter therefore emits
|
|
470
|
+
* chapter therefore emits the reference namespace set — `applications`,
|
|
443
471
|
* `groups`, `meetings`, `emailLog`, `superAdmins` — with no `admins` table. */
|
|
444
472
|
declare function chapterDb(mode: ChapterMode, auth: ResolvedAuth): {
|
|
445
473
|
schema: DbSchema;
|
|
@@ -457,8 +485,8 @@ declare function buildGroupSeed(config: ChapterConfig): Record<string, unknown>;
|
|
|
457
485
|
/**
|
|
458
486
|
* Apply defaults + validate the auth config into a {@link ResolvedAuth}. Defaults
|
|
459
487
|
* by mode: `chapter` → the `provisional/member/admin` claim ladder with the
|
|
460
|
-
* `superAdmins` tier
|
|
461
|
-
*
|
|
488
|
+
* `superAdmins` tier; `hub` → the `admins` allowlist table with no super tier.
|
|
489
|
+
* Throws at import on a bad policy.
|
|
462
490
|
*/
|
|
463
491
|
declare function resolveAuth(mode: ChapterMode, auth: ChapterAuth | undefined): ResolvedAuth;
|
|
464
492
|
/** The role from a verified JWT payload, per the resolved policy. An unknown or
|
|
@@ -633,8 +661,8 @@ declare function sendTemplated(deps: NotifyDeps, input: NotifyInput): Promise<No
|
|
|
633
661
|
declare function emailGroupFrom(row: Record<string, unknown>): EmailGroup;
|
|
634
662
|
|
|
635
663
|
/**
|
|
636
|
-
* Apply defaults + validate the pipeline config. With no config, the
|
|
637
|
-
*
|
|
664
|
+
* Apply defaults + validate the pipeline config. With no config, the complete
|
|
665
|
+
* reference pipeline. With `stages` given but the subsets omitted, the subsets
|
|
638
666
|
* default to empty (a site opts in to bookable/approvable states explicitly).
|
|
639
667
|
* Throws at import on a bad pipeline (empty/duplicate stages, an initial or a
|
|
640
668
|
* subset entry not on the ladder).
|
|
@@ -678,8 +706,7 @@ declare function paymentsReady(group: PaymentsGroup, hasSecretKey: boolean): boo
|
|
|
678
706
|
* of nested objects into bracket syntax (`metadata[applicationId]=...`). */
|
|
679
707
|
declare function stripeForm(params: Record<string, unknown>): string;
|
|
680
708
|
/** 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). */
|
|
709
|
+
* per application, so a client retry can't orphan a second subscription. */
|
|
683
710
|
declare function subscriptionIdempotencyKey(applicationId: string): string;
|
|
684
711
|
/** The db mutationId for a webhook-driven write — exactly-once per Stripe event,
|
|
685
712
|
* so replays are deduped at the db layer. */
|
|
@@ -941,6 +968,22 @@ declare function bucketSeries(points: Array<{
|
|
|
941
968
|
weekStart: number;
|
|
942
969
|
value: number;
|
|
943
970
|
}>;
|
|
971
|
+
/** Labels and current/previous values for one dashboard comparison window. */
|
|
972
|
+
interface DashboardMetricSeries {
|
|
973
|
+
labels: string[];
|
|
974
|
+
current: number[];
|
|
975
|
+
previous: number[];
|
|
976
|
+
}
|
|
977
|
+
/** Week-over-week and month-over-month series consumed by MetricWidget. */
|
|
978
|
+
interface DashboardMetricData {
|
|
979
|
+
wow: DashboardMetricSeries;
|
|
980
|
+
mom: DashboardMetricSeries;
|
|
981
|
+
}
|
|
982
|
+
/** MetricWidget-ready daily and weekly comparison windows. */
|
|
983
|
+
declare function dashboardMetricData(points: Array<{
|
|
984
|
+
t: number;
|
|
985
|
+
v: number;
|
|
986
|
+
}>, now: number): DashboardMetricData;
|
|
944
987
|
/** Annualized cents for a Stripe subscription: sum each item's
|
|
945
988
|
* `unit_amount * quantity`, ×12 for monthly intervals. A yearly interval is
|
|
946
989
|
* taken as-is. Returns 0 for a shape with no priced items. */
|
|
@@ -1183,7 +1226,9 @@ declare function memberSession(user: SessionUser, opts: {
|
|
|
1183
1226
|
* theme. These are brand OVERRIDES on top of a base theme — they do not replace
|
|
1184
1227
|
* the theme layer the components need (see {@link brandTokens} usage in the docs).
|
|
1185
1228
|
*/
|
|
1186
|
-
declare function brandTokens(brand: ChapterBrand | undefined
|
|
1229
|
+
declare function brandTokens(brand: ChapterBrand | undefined, options?: {
|
|
1230
|
+
selector?: string;
|
|
1231
|
+
}): string;
|
|
1187
1232
|
|
|
1188
1233
|
/** A `meetings` row, as far as reconciliation cares. */
|
|
1189
1234
|
interface MeetingForReconcile {
|
|
@@ -1235,13 +1280,13 @@ interface ResolvedScheduling {
|
|
|
1235
1280
|
windowDays: number;
|
|
1236
1281
|
summaryTemplate: string;
|
|
1237
1282
|
}
|
|
1238
|
-
/**
|
|
1283
|
+
/** Proven defaults: 45-minute weekday slots, 9–5 Pacific, 24h notice,
|
|
1239
1284
|
* a 14-day window. The summary is generic (a chapter's group seed supplies a
|
|
1240
1285
|
* name-branded one). */
|
|
1241
1286
|
declare const SCHEDULING_DEFAULTS: ResolvedScheduling;
|
|
1242
1287
|
/**
|
|
1243
1288
|
* Resolve a group's scheduling config against the defaults, validating every
|
|
1244
|
-
* bound
|
|
1289
|
+
* bound at config-write time (throws on a bad config, so a
|
|
1245
1290
|
* misconfiguration surfaces immediately rather than yielding empty slots).
|
|
1246
1291
|
* `windowDays` is capped at 62 because Google FreeBusy is.
|
|
1247
1292
|
*/
|
|
@@ -1345,4 +1390,4 @@ type ApplicationBookingPatch = {
|
|
|
1345
1390
|
* already there (never backward). */
|
|
1346
1391
|
declare function applicationBookingUpdate(currentStatus: string, startAt: number, htmlLink?: string | null): ApplicationBookingPatch;
|
|
1347
1392
|
|
|
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 };
|
|
1393
|
+
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,44 @@ 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
|
+
chartPositive: "--ui-chart-pos",
|
|
1414
|
+
chartNegative: "--ui-chart-neg"
|
|
1415
|
+
};
|
|
1416
|
+
function semanticDecls(tokens) {
|
|
1417
|
+
return Object.entries(tokens ?? {}).flatMap(
|
|
1418
|
+
([key, value]) => typeof value === "string" && value.trim() ? [`${TOKEN_VARS[key]}: ${cleanValue(value)};`] : []
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
function brandTokens(brand, options = {}) {
|
|
1371
1422
|
if (!brand) return "";
|
|
1372
|
-
const light = paletteDecls(brand.palette);
|
|
1423
|
+
const light = [...paletteDecls(brand.palette), ...semanticDecls(brand.tokens)];
|
|
1373
1424
|
const fonts = brand.fonts;
|
|
1374
1425
|
if (fonts?.display) light.push(`--ui-font-display: ${cleanValue(fonts.display)};`);
|
|
1375
1426
|
if (fonts?.body) light.push(`--ui-font-sans: ${cleanValue(fonts.body)};`);
|
|
1376
1427
|
if (fonts?.numeral) light.push(`--ui-font-numeral: ${cleanValue(fonts.numeral)};`);
|
|
1377
|
-
const dark = paletteDecls(brand.paletteDark);
|
|
1378
|
-
|
|
1428
|
+
const dark = [...paletteDecls(brand.paletteDark), ...semanticDecls(brand.tokensDark)];
|
|
1429
|
+
const selector = options.selector ?? ":root";
|
|
1430
|
+
const darkSelector = selector === ":root" ? ':root[data-theme="dark"]' : `${selector}[data-theme="dark"]`;
|
|
1431
|
+
const systemSelector = selector === ":root" ? ':root:not([data-theme="light"])' : `${selector}:not([data-theme="light"])`;
|
|
1432
|
+
let css = light.length ? `${selector} {
|
|
1379
1433
|
${light.join("\n ")}
|
|
1380
1434
|
}
|
|
1381
1435
|
` : "";
|
|
@@ -1383,9 +1437,9 @@ function brandTokens(brand) {
|
|
|
1383
1437
|
const block = `{
|
|
1384
1438
|
${dark.join("\n ")}
|
|
1385
1439
|
}`;
|
|
1386
|
-
css +=
|
|
1440
|
+
css += `${darkSelector} ${block}
|
|
1387
1441
|
@media (prefers-color-scheme: dark) {
|
|
1388
|
-
|
|
1442
|
+
${systemSelector} ${block}
|
|
1389
1443
|
}
|
|
1390
1444
|
`;
|
|
1391
1445
|
}
|
|
@@ -1558,6 +1612,7 @@ export {
|
|
|
1558
1612
|
createChapterIntegration,
|
|
1559
1613
|
createClerkInvitation,
|
|
1560
1614
|
createClerkUser,
|
|
1615
|
+
dashboardMetricData,
|
|
1561
1616
|
defaultCrm,
|
|
1562
1617
|
defineChapter,
|
|
1563
1618
|
emailGroupFrom,
|