@odla-ai/chapter 0.22.1 → 0.24.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 +99 -26
- package/dist/{chunk-4COPR4SY.js → chunk-GMGTJIY3.js} +292 -97
- package/dist/chunk-GMGTJIY3.js.map +1 -0
- package/dist/chunk-WGQO4WDJ.js +412 -0
- package/dist/chunk-WGQO4WDJ.js.map +1 -0
- package/dist/{chunk-C4XQSRW7.js → chunk-ZPAJL7KG.js} +225 -190
- package/dist/chunk-ZPAJL7KG.js.map +1 -0
- package/dist/{types-CgWUQ2MH.d.ts → copy-context-Dp5hvj5W.d.ts} +85 -20
- package/dist/index.cjs +340 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -24
- package/dist/index.d.ts +111 -24
- package/dist/index.js +340 -9
- package/dist/index.js.map +1 -1
- package/dist/ui/admin/index.d.ts +5 -2
- package/dist/ui/admin/index.js +8 -3
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +11 -5
- package/dist/ui/member/index.d.ts +118 -2
- package/dist/ui/member/index.js +10 -4
- package/dist/worker/index.cjs +274 -213
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +74 -19
- package/dist/worker/index.d.ts +74 -19
- package/dist/worker/index.js +274 -213
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/runbooks/adopt-existing.md +23 -5
- package/runbooks/greenfield.md +85 -4
- package/dist/chunk-3QKGKUTX.js +0 -91
- package/dist/chunk-3QKGKUTX.js.map +0 -1
- package/dist/chunk-4COPR4SY.js.map +0 -1
- package/dist/chunk-C4XQSRW7.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -401,8 +401,8 @@ function resolveApplication(a) {
|
|
|
401
401
|
maxLen: a?.maxLen ?? {},
|
|
402
402
|
defaultMaxLen: a?.defaultMaxLen ?? 2e3,
|
|
403
403
|
bodyCap: a?.bodyCap ?? 32768,
|
|
404
|
-
requireDisclaimerAck: a?.requireDisclaimerAck ??
|
|
405
|
-
profileFields: a?.profileFields ??
|
|
404
|
+
requireDisclaimerAck: a?.requireDisclaimerAck ?? true,
|
|
405
|
+
profileFields: a?.profileFields ?? [],
|
|
406
406
|
crmFields: a?.crmFields ?? [],
|
|
407
407
|
maxArrayLen: a?.maxArrayLen ?? 100,
|
|
408
408
|
validateEmail: a?.validateEmail ?? true
|
|
@@ -422,7 +422,7 @@ function hasDisclaimerAck(fields) {
|
|
|
422
422
|
var IDENTITY_FIELDS = /* @__PURE__ */ new Set(["email", "firstName", "lastName"]);
|
|
423
423
|
function applicantProfile(chapter, fields) {
|
|
424
424
|
const app = chapter.application;
|
|
425
|
-
const allowed = (f) => app.profileFields
|
|
425
|
+
const allowed = (f) => app.profileFields.includes(f);
|
|
426
426
|
const profile = {};
|
|
427
427
|
for (const f of [...app.required, ...app.optional]) {
|
|
428
428
|
if (IDENTITY_FIELDS.has(f) || !allowed(f)) continue;
|
|
@@ -479,6 +479,300 @@ function joinConfig(group, paymentsReady2) {
|
|
|
479
479
|
};
|
|
480
480
|
}
|
|
481
481
|
|
|
482
|
+
// src/copy-defaults-admin.ts
|
|
483
|
+
var DEFAULT_ADMIN_COPY = {
|
|
484
|
+
auth: {
|
|
485
|
+
checking: "Checking access\u2026",
|
|
486
|
+
notAuthorized: "Not authorized",
|
|
487
|
+
accountNotAuthorized: "{account} isn't on the admin list.",
|
|
488
|
+
thisAccount: "This account",
|
|
489
|
+
signOut: "Sign out",
|
|
490
|
+
loading: "Loading\u2026",
|
|
491
|
+
signInNotConfigured: "Sign-in not configured",
|
|
492
|
+
missingPublishableKey: "No Clerk publishable key is set for this environment yet.",
|
|
493
|
+
noWorkspaces: "No admin workspaces are configured.",
|
|
494
|
+
signInTagline: "Admin sign-in, invite only"
|
|
495
|
+
},
|
|
496
|
+
shell: {
|
|
497
|
+
adminRole: "admin",
|
|
498
|
+
adminConsole: "Admin Console",
|
|
499
|
+
adminName: "Admin",
|
|
500
|
+
navigationLabel: "Admin navigation"
|
|
501
|
+
},
|
|
502
|
+
workspaces: {
|
|
503
|
+
dashboard: "Dashboard",
|
|
504
|
+
overview: "Overview",
|
|
505
|
+
billing: "Billing",
|
|
506
|
+
people: "People",
|
|
507
|
+
settings: "Settings",
|
|
508
|
+
calendar: "Calendar",
|
|
509
|
+
email: "Email",
|
|
510
|
+
dashboardViewsLabel: "Dashboard views",
|
|
511
|
+
settingsViewsLabel: "Settings views",
|
|
512
|
+
collectionsLabel: "CRM collections"
|
|
513
|
+
},
|
|
514
|
+
dashboard: {
|
|
515
|
+
loading: "Loading dashboard\u2026",
|
|
516
|
+
loadFailed: "Couldn't load the dashboard",
|
|
517
|
+
upcomingCalls: "Upcoming calls",
|
|
518
|
+
callsNeedAttention: "{count} need attention",
|
|
519
|
+
noUpcomingCalls: "No upcoming calls.",
|
|
520
|
+
drift: "drift",
|
|
521
|
+
open: "Open",
|
|
522
|
+
meet: "Meet",
|
|
523
|
+
applications: "Applications",
|
|
524
|
+
newMembers: "New members",
|
|
525
|
+
newMembersUnavailable: "Appears once billing is connected.",
|
|
526
|
+
revenueAdded: "Revenue \xB7 annual run rate added",
|
|
527
|
+
revenue: "Revenue",
|
|
528
|
+
revenueUnavailable: "Appears once billing is connected.",
|
|
529
|
+
pipeline: "Pipeline",
|
|
530
|
+
pipelineLabel: "Membership pipeline",
|
|
531
|
+
thisWeek: "+{count} this week",
|
|
532
|
+
noChange: "no change",
|
|
533
|
+
activeMemberships: "Active memberships",
|
|
534
|
+
annualRunRate: "Annual run rate",
|
|
535
|
+
testMode: "test mode"
|
|
536
|
+
},
|
|
537
|
+
billing: {
|
|
538
|
+
loading: "Loading\u2026",
|
|
539
|
+
loadFailed: "Couldn't load billing",
|
|
540
|
+
notConfigured: "Billing isn't configured. No Stripe key is vaulted for this group.",
|
|
541
|
+
active: "Active",
|
|
542
|
+
annualized: "Annualized",
|
|
543
|
+
renewingSoon: "Renewing within 60 days",
|
|
544
|
+
pastDue: "Past due",
|
|
545
|
+
subscriptions: "Subscriptions",
|
|
546
|
+
testMode: "Stripe test mode",
|
|
547
|
+
truncated: "Showing the first 100 subscriptions. The list is truncated.",
|
|
548
|
+
name: "Name",
|
|
549
|
+
email: "Email",
|
|
550
|
+
application: "Application",
|
|
551
|
+
subscription: "Subscription",
|
|
552
|
+
cancelling: "cancelling",
|
|
553
|
+
amount: "Amount",
|
|
554
|
+
renews: "Renews"
|
|
555
|
+
},
|
|
556
|
+
availability: {
|
|
557
|
+
loading: "Loading\u2026",
|
|
558
|
+
loadFailed: "Couldn't load availability",
|
|
559
|
+
saved: "Saved.",
|
|
560
|
+
title: "Booking availability",
|
|
561
|
+
days: "Days",
|
|
562
|
+
startHour: "Start hour (0\u201324)",
|
|
563
|
+
endHour: "End hour (0\u201324)",
|
|
564
|
+
slotMinutes: "Slot length (minutes)",
|
|
565
|
+
minNoticeHours: "Minimum notice (hours)",
|
|
566
|
+
windowDays: "Booking window (days)",
|
|
567
|
+
timezone: "Timezone",
|
|
568
|
+
summaryTemplate: "Event summary template",
|
|
569
|
+
save: "Save availability",
|
|
570
|
+
dayLabels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
|
|
571
|
+
},
|
|
572
|
+
email: {
|
|
573
|
+
loading: "Loading\u2026",
|
|
574
|
+
loadFailed: "Couldn't load email config",
|
|
575
|
+
saved: "Saved.",
|
|
576
|
+
sent: "Sent {template} to {address}{redirected}.",
|
|
577
|
+
testFailed: "Test send did not deliver.",
|
|
578
|
+
delivery: "Delivery",
|
|
579
|
+
notificationAddress: "Notification address",
|
|
580
|
+
replyTo: "Reply-to",
|
|
581
|
+
debugInbox: "Debug inbox",
|
|
582
|
+
debugInboxHint: "Non-production sends redirect here.",
|
|
583
|
+
sendTest: "Send test",
|
|
584
|
+
enabled: "Enabled",
|
|
585
|
+
subject: "Subject",
|
|
586
|
+
body: "Body",
|
|
587
|
+
save: "Save changes",
|
|
588
|
+
sendLog: "Send log",
|
|
589
|
+
sentColumn: "Sent",
|
|
590
|
+
templateColumn: "Template",
|
|
591
|
+
statusColumn: "Status",
|
|
592
|
+
toColumn: "To",
|
|
593
|
+
failed: "failed",
|
|
594
|
+
redirected: "redirected",
|
|
595
|
+
delivered: "delivered"
|
|
596
|
+
},
|
|
597
|
+
meetings: {
|
|
598
|
+
loading: "Loading\u2026",
|
|
599
|
+
loadFailed: "Couldn't load meetings",
|
|
600
|
+
cancelConfirm: "Cancel this call? The calendar provider notifies the attendee.",
|
|
601
|
+
newStartPrompt: "New start time (for example, 2026-08-01 14:00):",
|
|
602
|
+
parseFailed: "Couldn't parse that time.",
|
|
603
|
+
agenda: "Agenda",
|
|
604
|
+
empty: "No meetings.",
|
|
605
|
+
unknown: "(unknown)",
|
|
606
|
+
drift: "drift",
|
|
607
|
+
meet: "Meet",
|
|
608
|
+
reschedule: "Reschedule",
|
|
609
|
+
cancel: "Cancel"
|
|
610
|
+
},
|
|
611
|
+
network: {
|
|
612
|
+
title: "Share to a follower",
|
|
613
|
+
allowlistDescription: "Sends the target's allowlisted fields. Its pipeline and account state remain local.",
|
|
614
|
+
sharing: "Sharing\u2026",
|
|
615
|
+
shareWith: "Share with {target}",
|
|
616
|
+
shared: "Shared with {target}.",
|
|
617
|
+
shareFailed: "Could not share with {target}.",
|
|
618
|
+
deliveryFailed: "Delivery failed."
|
|
619
|
+
},
|
|
620
|
+
records: {
|
|
621
|
+
workflowMissing: "This record is not linked to an application workflow.",
|
|
622
|
+
comms: "Comms",
|
|
623
|
+
commsHistory: "Comms history",
|
|
624
|
+
scheduling: "Scheduling",
|
|
625
|
+
billing: "Billing",
|
|
626
|
+
notes: "Notes",
|
|
627
|
+
access: "Access",
|
|
628
|
+
sharing: "Sharing",
|
|
629
|
+
lifecycle: "Access & lifecycle",
|
|
630
|
+
role: "Role",
|
|
631
|
+
superAdminHint: "Super-admin, managed in odla Studio.",
|
|
632
|
+
noAccount: "No linked account yet. The role is set once they sign in.",
|
|
633
|
+
approve: "Approve",
|
|
634
|
+
refund: "Refund",
|
|
635
|
+
approved: "Approved.",
|
|
636
|
+
refunded: "Refund issued.",
|
|
637
|
+
roleSet: "Role set to {role}.",
|
|
638
|
+
messageSent: "Message sent.",
|
|
639
|
+
messageNotSent: "Message was not sent.",
|
|
640
|
+
loadingTemplates: "Loading templates\u2026",
|
|
641
|
+
template: "Template",
|
|
642
|
+
chooseTemplate: "Choose a template\u2026",
|
|
643
|
+
sending: "Sending\u2026",
|
|
644
|
+
send: "Send",
|
|
645
|
+
noMessages: "No messages recorded.",
|
|
646
|
+
message: "Message",
|
|
647
|
+
newStartPrompt: "New start time:",
|
|
648
|
+
parseFailed: "Couldn't parse that time.",
|
|
649
|
+
cancelConfirm: "Cancel this call?",
|
|
650
|
+
callCancelled: "Call cancelled.",
|
|
651
|
+
callRescheduled: "Call rescheduled.",
|
|
652
|
+
noApplication: "No application is linked to this record.",
|
|
653
|
+
loadingMeetings: "Loading meetings\u2026",
|
|
654
|
+
noMeetings: "No meetings recorded.",
|
|
655
|
+
joinMeeting: "Join meeting",
|
|
656
|
+
openCalendar: "Open calendar",
|
|
657
|
+
reschedule: "Reschedule",
|
|
658
|
+
cancel: "Cancel"
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
// src/copy-defaults.ts
|
|
663
|
+
var DEFAULT_COMMON_COPY = {
|
|
664
|
+
loading: "Loading\u2026",
|
|
665
|
+
saved: "Saved.",
|
|
666
|
+
unknown: "(unknown)"
|
|
667
|
+
};
|
|
668
|
+
var DEFAULT_JOIN_COPY = {
|
|
669
|
+
form: {
|
|
670
|
+
submit: "Submit application",
|
|
671
|
+
submitting: "Submitting\u2026",
|
|
672
|
+
submitFailed: "Your application could not be submitted.",
|
|
673
|
+
unexpectedFailure: "Something went wrong. Please try again."
|
|
674
|
+
},
|
|
675
|
+
booking: {
|
|
676
|
+
unavailable: "Scheduling is briefly unavailable. We'll reach out by email to arrange your call.",
|
|
677
|
+
loadFailed: "Times are briefly unavailable. Please try again.",
|
|
678
|
+
slotTaken: "That time was just taken. Here are the current openings.",
|
|
679
|
+
failed: "The booking could not be completed.",
|
|
680
|
+
loading: "Loading available times\u2026",
|
|
681
|
+
book: "Book this time",
|
|
682
|
+
booking: "Booking\u2026"
|
|
683
|
+
},
|
|
684
|
+
payment: {
|
|
685
|
+
setupFailed: "Payment could not be set up. Please try again.",
|
|
686
|
+
preparing: "Preparing secure payment\u2026",
|
|
687
|
+
pending: "Confirming your payment\u2026",
|
|
688
|
+
processing: "Processing\u2026",
|
|
689
|
+
payAndContinue: "Pay and continue",
|
|
690
|
+
incomplete: "The payment did not complete. Please try again.",
|
|
691
|
+
consent: "I have read and agree to the pricing and refund policy above."
|
|
692
|
+
},
|
|
693
|
+
done: {
|
|
694
|
+
label: "You're booked",
|
|
695
|
+
calendarInvite: "A calendar invitation with the video call link is on its way to your email.",
|
|
696
|
+
memberArea: "Go to your member area"
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
var DEFAULT_MEMBERS_COPY = {
|
|
700
|
+
loadFailed: "Sign in is briefly unavailable. Please refresh.",
|
|
701
|
+
account: {
|
|
702
|
+
signOut: "Sign out",
|
|
703
|
+
adminConsole: "Admin console"
|
|
704
|
+
},
|
|
705
|
+
provisional: {
|
|
706
|
+
cardLabel: "Your Application",
|
|
707
|
+
applicationNeeded: "One step remains",
|
|
708
|
+
applicationNeededBody: "Your account is ready, and the application that completes it takes a few minutes.",
|
|
709
|
+
apply: "Apply for membership",
|
|
710
|
+
refunded: "Membership refunded",
|
|
711
|
+
refundedBody: "Your fee has been refunded in full and your membership is canceled.",
|
|
712
|
+
active: "Your membership is active.",
|
|
713
|
+
renews: "Your membership is active and renews {date}.",
|
|
714
|
+
introductionCall: "Your introduction call",
|
|
715
|
+
calendarInvite: "A calendar invitation with the video call link is in your email.",
|
|
716
|
+
joinCall: "Join the video call",
|
|
717
|
+
bookCall: "Book your introduction call",
|
|
718
|
+
bookCallBody: "Your application is in. Choose a time below, and a calendar invitation will reach your email.",
|
|
719
|
+
chooseTime: "Choose a time"
|
|
720
|
+
},
|
|
721
|
+
full: {
|
|
722
|
+
welcome: "Welcome back."
|
|
723
|
+
},
|
|
724
|
+
reschedule: {
|
|
725
|
+
changeTime: "Change your time",
|
|
726
|
+
unavailable: "Scheduling is briefly unavailable. We'll reach out by email to arrange your call.",
|
|
727
|
+
loadFailed: "Times are briefly unavailable. Please try again.",
|
|
728
|
+
slotGone: "That time is no longer available. Please pick another.",
|
|
729
|
+
loading: "Loading available times\u2026",
|
|
730
|
+
noTimes: "No open times right now. Please check back soon.",
|
|
731
|
+
rescheduling: "Rescheduling\u2026",
|
|
732
|
+
keepTime: "Keep my current time"
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
// src/copy-resolve.ts
|
|
737
|
+
var DEFAULT_CHAPTER_COPY = {
|
|
738
|
+
common: DEFAULT_COMMON_COPY,
|
|
739
|
+
join: DEFAULT_JOIN_COPY,
|
|
740
|
+
members: DEFAULT_MEMBERS_COPY,
|
|
741
|
+
admin: DEFAULT_ADMIN_COPY
|
|
742
|
+
};
|
|
743
|
+
var isObject = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
744
|
+
function mergeCopy(base, input, path) {
|
|
745
|
+
if (typeof base === "string") {
|
|
746
|
+
if (input === void 0) return base;
|
|
747
|
+
if (typeof input !== "string") throw new Error(`${path}: must be a string`);
|
|
748
|
+
return input;
|
|
749
|
+
}
|
|
750
|
+
if (Array.isArray(base)) {
|
|
751
|
+
if (input === void 0) return [...base];
|
|
752
|
+
if (!Array.isArray(input) || !input.every((item) => typeof item === "string")) {
|
|
753
|
+
throw new Error(`${path}: must be an array of strings`);
|
|
754
|
+
}
|
|
755
|
+
return [...input];
|
|
756
|
+
}
|
|
757
|
+
if (!isObject(base)) return base;
|
|
758
|
+
if (input !== void 0 && !isObject(input)) throw new Error(`${path}: must be an object`);
|
|
759
|
+
const overrides = input;
|
|
760
|
+
const result = {};
|
|
761
|
+
for (const [key, value] of Object.entries(base)) {
|
|
762
|
+
result[key] = mergeCopy(value, overrides?.[key], `${path}.${key}`);
|
|
763
|
+
}
|
|
764
|
+
return result;
|
|
765
|
+
}
|
|
766
|
+
function resolveChapterCopy(input) {
|
|
767
|
+
return mergeCopy(DEFAULT_CHAPTER_COPY, input, "defineChapter.copy");
|
|
768
|
+
}
|
|
769
|
+
function formatChapterCopy(template, values) {
|
|
770
|
+
return template.replace(
|
|
771
|
+
/\{([a-zA-Z][a-zA-Z0-9]*)\}/g,
|
|
772
|
+
(match, key) => Object.prototype.hasOwnProperty.call(values, key) ? String(values[key]) : match
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
|
|
482
776
|
// src/config.ts
|
|
483
777
|
var SLUG = /^[a-z0-9][a-z0-9-]{1,62}$/;
|
|
484
778
|
var FIELD = /^[a-z][a-zA-Z0-9_]*$/;
|
|
@@ -557,11 +851,15 @@ function defineChapter(config) {
|
|
|
557
851
|
if (!config.prices || typeof config.prices.standardCents !== "number") {
|
|
558
852
|
throw new Error("defineChapter.prices.standardCents: required in chapter mode");
|
|
559
853
|
}
|
|
854
|
+
if (config.account === void 0) {
|
|
855
|
+
throw new Error('defineChapter.account: required in chapter mode; choose "none", "create", or "invite" explicitly');
|
|
856
|
+
}
|
|
560
857
|
}
|
|
561
858
|
const auth = resolveAuth(mode, config.auth);
|
|
562
859
|
const pipeline = resolvePipeline(config.pipeline);
|
|
563
860
|
const application = resolveApplication(config.application);
|
|
564
861
|
const brand = { ...config.brand, wordmark: config.brand?.wordmark ?? name };
|
|
862
|
+
const copy = resolveChapterCopy(config.copy);
|
|
565
863
|
const network = resolveNetwork(config, crm);
|
|
566
864
|
const { schema, rules } = chapterDb(mode, auth);
|
|
567
865
|
const services = config.services ?? ["db", "calendar", "o11y"];
|
|
@@ -616,6 +914,7 @@ function defineChapter(config) {
|
|
|
616
914
|
name,
|
|
617
915
|
mode,
|
|
618
916
|
brand,
|
|
917
|
+
copy,
|
|
619
918
|
network,
|
|
620
919
|
crm,
|
|
621
920
|
auth,
|
|
@@ -651,6 +950,16 @@ function createChapterIntegration(chapter, options = {}) {
|
|
|
651
950
|
if (group) {
|
|
652
951
|
seeds.push({ id: "group", ns: "groups", key: { attr: "id", value: chapter.id }, attrs: { ...group, createdAt: now } });
|
|
653
952
|
}
|
|
953
|
+
const isLeader = (chapter.config.network?.targets?.length ?? 0) > 0;
|
|
954
|
+
const runbooks = isLeader ? {
|
|
955
|
+
role: "leader",
|
|
956
|
+
slugs: ["chapter-leader", "chapter-network", "crm"],
|
|
957
|
+
guidance: `${chapter.name} is a LEADER hub: it holds the CRM and shares records with its chapters. Read it with \`odla-ai runbook get chapter-leader\`.`
|
|
958
|
+
} : {
|
|
959
|
+
role: "follower",
|
|
960
|
+
slugs: ["chapter-follower", "chapter-network"],
|
|
961
|
+
guidance: `${chapter.name} is a FOLLOWER site: it receives people and records from a leader hub. Read it with \`odla-ai runbook get chapter-follower\`.`
|
|
962
|
+
};
|
|
654
963
|
return {
|
|
655
964
|
id: "chapter",
|
|
656
965
|
title: `Chapter: ${chapter.name}`,
|
|
@@ -661,7 +970,8 @@ function createChapterIntegration(chapter, options = {}) {
|
|
|
661
970
|
},
|
|
662
971
|
rules: { ...crmDesc.rules, ...chapter.rules },
|
|
663
972
|
seeds,
|
|
664
|
-
probes: [...crmDesc.probes ?? []]
|
|
973
|
+
probes: [...crmDesc.probes ?? []],
|
|
974
|
+
runbooks
|
|
665
975
|
};
|
|
666
976
|
}
|
|
667
977
|
|
|
@@ -1048,7 +1358,7 @@ function billingColumns(app) {
|
|
|
1048
1358
|
async function syncApplicationToCrm(deps, opts) {
|
|
1049
1359
|
const emailKey = str(opts.app.email).toLowerCase();
|
|
1050
1360
|
if (!emailKey) return null;
|
|
1051
|
-
const
|
|
1361
|
+
const recordDeps = { crm: deps.crm, db: deps.db, now: deps.now, newId: deps.newId };
|
|
1052
1362
|
const input = personInputFromApp(deps.chapter, opts.app);
|
|
1053
1363
|
const { crm_record } = await deps.db.query({
|
|
1054
1364
|
crm_record: { $: { where: { type: "person", primaryEmail: emailKey }, limit: 1 } }
|
|
@@ -1058,16 +1368,16 @@ async function syncApplicationToCrm(deps, opts) {
|
|
|
1058
1368
|
let recordId;
|
|
1059
1369
|
if (existing && typeof existing.id === "string") {
|
|
1060
1370
|
recordId = existing.id;
|
|
1061
|
-
await updateRecord2(
|
|
1371
|
+
await updateRecord2(recordDeps, { id: recordId, input });
|
|
1062
1372
|
} else {
|
|
1063
|
-
const created = await createRecord2(
|
|
1373
|
+
const created = await createRecord2(recordDeps, { type: "person", input, ...stage ? { stage } : {} });
|
|
1064
1374
|
recordId = created.id;
|
|
1065
1375
|
}
|
|
1066
1376
|
if (existing && stage && existing.stage !== stage) {
|
|
1067
|
-
await setStage(
|
|
1377
|
+
await setStage(recordDeps, { id: recordId, to: stage, authorId: "system", mutationId: `crm:stage:${recordId}:${stage}` }).catch(() => void 0);
|
|
1068
1378
|
}
|
|
1069
1379
|
await deps.db.transact([{ t: "update", ns: "crm_record", id: recordId, attrs: billingColumns(opts.app) }]);
|
|
1070
|
-
await linkIdentity(
|
|
1380
|
+
await linkIdentity(recordDeps, { recordId, email: emailKey, mutationId: `crm:link:${recordId}:${emailKey}` }).catch(() => void 0);
|
|
1071
1381
|
return recordId;
|
|
1072
1382
|
}
|
|
1073
1383
|
async function backfillCrm(deps) {
|
|
@@ -1437,6 +1747,7 @@ function brandTokens(brand, options = {}) {
|
|
|
1437
1747
|
if (fonts?.body) light.push(`--ui-font-sans: ${cleanValue(fonts.body)};`);
|
|
1438
1748
|
if (fonts?.numeral) light.push(`--ui-font-numeral: ${cleanValue(fonts.numeral)};`);
|
|
1439
1749
|
const dark = [...paletteDecls(brand.paletteDark), ...semanticDecls(brand.tokensDark)];
|
|
1750
|
+
const invert = paletteDecls(brand.paletteInvert);
|
|
1440
1751
|
const selector = options.selector ?? ":root";
|
|
1441
1752
|
const darkSelector = selector === ":root" ? ':root[data-theme="dark"]' : `${selector}[data-theme="dark"]`;
|
|
1442
1753
|
const systemSelector = selector === ":root" ? ':root:not([data-theme="light"])' : `${selector}:not([data-theme="light"])`;
|
|
@@ -1452,10 +1763,26 @@ function brandTokens(brand, options = {}) {
|
|
|
1452
1763
|
@media (prefers-color-scheme: dark) {
|
|
1453
1764
|
${systemSelector} ${block}
|
|
1454
1765
|
}
|
|
1766
|
+
`;
|
|
1767
|
+
}
|
|
1768
|
+
if (invert.length) {
|
|
1769
|
+
const invertSelector = selector === ":root" ? ".ui-invert" : `${selector}.ui-invert, ${selector} .ui-invert`;
|
|
1770
|
+
css += `${invertSelector} {
|
|
1771
|
+
color-scheme: dark;
|
|
1772
|
+
${invert.join("\n ")}
|
|
1773
|
+
}
|
|
1455
1774
|
`;
|
|
1456
1775
|
}
|
|
1457
1776
|
return css;
|
|
1458
1777
|
}
|
|
1778
|
+
function chapterBrandFromTokens(compiled, base = {}) {
|
|
1779
|
+
return {
|
|
1780
|
+
...base,
|
|
1781
|
+
palette: { ...compiled.light, ...base.palette },
|
|
1782
|
+
paletteDark: { ...compiled.dark, ...base.paletteDark },
|
|
1783
|
+
paletteInvert: { ...compiled.dark, ...base.paletteInvert }
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1459
1786
|
|
|
1460
1787
|
// src/reconcile.ts
|
|
1461
1788
|
function isReconcilable(meeting, now) {
|
|
@@ -1596,6 +1923,7 @@ function applicationBookingUpdate(currentStatus, startAt, htmlLink) {
|
|
|
1596
1923
|
};
|
|
1597
1924
|
}
|
|
1598
1925
|
export {
|
|
1926
|
+
DEFAULT_CHAPTER_COPY,
|
|
1599
1927
|
DEFAULT_SHARE_FIELDS,
|
|
1600
1928
|
SCHEDULING_DEFAULTS,
|
|
1601
1929
|
applicantProfile,
|
|
@@ -1611,6 +1939,7 @@ export {
|
|
|
1611
1939
|
canChangeRole,
|
|
1612
1940
|
canTransition,
|
|
1613
1941
|
canceledPatch,
|
|
1942
|
+
chapterBrandFromTokens,
|
|
1614
1943
|
chapterDb,
|
|
1615
1944
|
clampArray,
|
|
1616
1945
|
clerkGetUser,
|
|
@@ -1630,6 +1959,7 @@ export {
|
|
|
1630
1959
|
endForSlot,
|
|
1631
1960
|
findApplicationRef,
|
|
1632
1961
|
firstPaymentPatch,
|
|
1962
|
+
formatChapterCopy,
|
|
1633
1963
|
getVaultSecret,
|
|
1634
1964
|
hasDisclaimerAck,
|
|
1635
1965
|
introIdempotencyKey,
|
|
@@ -1659,6 +1989,7 @@ export {
|
|
|
1659
1989
|
renewalPatch,
|
|
1660
1990
|
resolveApplication,
|
|
1661
1991
|
resolveAuth,
|
|
1992
|
+
resolveChapterCopy,
|
|
1662
1993
|
resolvePipeline,
|
|
1663
1994
|
resolveScheduling,
|
|
1664
1995
|
roleFromClaim,
|